/* ===================================================================
   Feature deck — the "Key features" section on every app page.

   A six-column bento grid. Each card is a piece of paper with a tinted
   stage set into it, and the artwork — a chart, a ring, a device, a
   chat — sits on that stage. featuredeck.js animates it once when the
   card scrolls into view; everything here is layout and resting state,
   so the section is complete and readable before a frame runs.
   =================================================================== */

.fx {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 20px;
}

.fx-card {
  grid-column: span 2;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 26px 26px 24px;
  border-radius: 26px;
  overflow: hidden;
  isolation: isolate;
  /* the accent each page sets on its hero carries into the deck */
  --fx: var(--accent, var(--ink));
  background:
    linear-gradient(180deg, #fff 0%, var(--card) 46%, var(--paper-2) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 0 0 1px var(--line),
    0 2px 4px -2px rgba(16, 18, 16, .06),
    0 16px 34px -26px rgba(16, 18, 16, .3);
  transition: box-shadow .4s var(--ease), transform .4s var(--ease);
}

/* a breath of the app's colour in the top-right corner of every card */
.fx-card::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -46%; right: -32%;
  width: 78%; aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--fx) 20%, transparent) 0%, transparent 68%);
  opacity: .8;
  pointer-events: none;
}

html.fx-scrolling .fx-card { transition: none; }
html.fx-scrolling .fx-card:hover { transform: none; }
.fx-card:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 0 0 1px color-mix(in srgb, var(--fx) 26%, var(--line)),
    0 4px 8px -4px rgba(16, 18, 16, .07),
    0 30px 56px -30px color-mix(in srgb, var(--fx) 40%, rgba(16, 18, 16, .34));
}

.fx-w3 { grid-column: span 3; }
.fx-w4 { grid-column: span 4; }
.fx-w6 { grid-column: span 6; }

.fx-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--fx) 74%, var(--ink));
  background: color-mix(in srgb, var(--fx) 10%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fx) 18%, transparent);
  border-radius: var(--r-pill);
  padding: 6px 11px 6px 9px;
  margin-bottom: 15px;
}
.fx-chip::before {
  content: "";
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--fx);
  flex: none;
}

.fx-card h3 {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -.028em;
  margin: 0;
  line-height: 1.24;
}
.fx-card > p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
  margin: 9px 0 0;
  max-width: 46ch;
}

/* ---------- the stage the artwork sits on ---------- */
/* takes the slack, so cards in a row line their artwork up even when the
   copy above runs to different lengths */
.fx-viz {
  position: relative;
  margin-top: 20px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 116px;
  padding: 16px;
  border-radius: 18px;
  background:
    radial-gradient(120% 88% at 50% 0%, color-mix(in srgb, var(--fx) 9%, transparent) 0%, transparent 72%),
    linear-gradient(180deg, rgba(255, 255, 255, .72), rgba(255, 255, 255, .28));
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--fx) 12%, var(--line)),
    inset 0 1px 0 rgba(255, 255, 255, .8);
}
.fx-viz--tall { min-height: 196px; }
.fx-viz--flush { padding: 0; background: none; box-shadow: none; }

/* ---------- shared parts the visuals are built from ---------- */

/* a panel that reads as a slice of the app, floating on the stage */
.fx-panel {
  background: var(--card);
  border-radius: var(--r-md);
  padding: 13px 14px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--fx) 10%, var(--line)),
    0 10px 22px -16px rgba(16, 18, 16, .45);
}
.fx-row { display: flex; align-items: center; gap: 10px; }
.fx-row + .fx-row { margin-top: 10px; }
.fx-spread { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fx-mono { font-family: var(--font-mono); font-size: 11px; letter-spacing: .04em; color: var(--ink-3); }
.fx-key { font-size: 12.5px; color: var(--ink-2); }
.fx-num {
  font-size: 32px; font-weight: 600; letter-spacing: -.04em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.fx-num--lg { font-size: 46px; }
.fx-num--fx { color: var(--fx); }
.fx-unit {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}

/* bar chart — columns grow from the baseline */
.fx-bars { display: flex; align-items: flex-end; gap: 8px; height: 96px; }
.fx-bar {
  flex: 1 1 0;
  border-radius: 6px 6px 4px 4px;
  background: linear-gradient(180deg, rgba(16, 18, 16, .16), rgba(16, 18, 16, .09));
  height: var(--v, 40%);
  transform-origin: 50% 100%;
  min-height: 5px;
}
.fx-bar--on {
  background: linear-gradient(180deg, color-mix(in srgb, var(--fx) 78%, #fff) 0%, var(--fx) 100%);
  box-shadow: 0 6px 14px -8px color-mix(in srgb, var(--fx) 70%, transparent);
}
.fx-barlabels { display: flex; gap: 8px; margin-top: 10px; }
.fx-barlabels span { flex: 1 1 0; text-align: center; font-family: var(--font-mono); font-size: 9.5px; color: var(--ink-3); }

/* horizontal meters */
.fx-meter {
  height: 8px; border-radius: 99px; flex: 1 1 auto; overflow: hidden;
  background: rgba(16, 18, 16, .08);
  box-shadow: inset 0 1px 2px rgba(16, 18, 16, .06);
}
.fx-meter i {
  display: block; height: 100%; border-radius: 99px;
  width: var(--v, 50%); transform-origin: 0 50%;
  background: linear-gradient(90deg, color-mix(in srgb, var(--fx) 62%, #fff), var(--fx));
  box-shadow: 0 0 10px -2px color-mix(in srgb, var(--fx) 60%, transparent);
}

/* progress ring */
.fx-ring { position: relative; width: 112px; height: 112px; margin: 0 auto; }
.fx-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); display: block; overflow: visible; }
.fx-ring circle { fill: none; stroke-width: 9; stroke-linecap: round; }
.fx-ring .fx-ring-bg { stroke: rgba(16, 18, 16, .08); }
.fx-ring .fx-ring-fg { stroke: var(--fx); }
.fx-ring-mid {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; text-align: center;
}

/* line / area chart */
.fx-chart { width: 100%; height: 100px; display: block; overflow: visible; }
.fx-chart .fx-line {
  fill: none; stroke: var(--fx); stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 4px 8px color-mix(in srgb, var(--fx) 38%, transparent));
}
/* the area fades out downwards, which reads far better than a flat wash */
.fx-chart .fx-fill {
  fill: var(--fx); opacity: .22;
  mask-image: linear-gradient(to bottom, #000 0%, transparent 92%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 92%);
}
.fx-chart .fx-grid { stroke: rgba(16, 18, 16, .07); stroke-width: 1; }
.fx-chart .fx-dot { fill: var(--card); stroke: var(--fx); stroke-width: 2.6; }

/* candle chart */
.fx-candle rect { fill: var(--fx); }
.fx-candle line { stroke: var(--fx); stroke-width: 1.5; }
.fx-candle .down rect, .fx-candle .down line { fill: var(--ink-3); stroke: var(--ink-3); }

/* heatmap grid */
.fx-heat { display: grid; grid-template-columns: repeat(14, 1fr); gap: 5px; }
.fx-heat i { aspect-ratio: 1; border-radius: 4px; background: rgba(16, 18, 16, .06); }
.fx-heat i[data-l="1"] { background: color-mix(in srgb, var(--fx) 24%, transparent); }
.fx-heat i[data-l="2"] { background: color-mix(in srgb, var(--fx) 48%, transparent); }
.fx-heat i[data-l="3"] { background: color-mix(in srgb, var(--fx) 74%, transparent); }
.fx-heat i[data-l="4"] {
  background: var(--fx);
  box-shadow: 0 3px 9px -4px color-mix(in srgb, var(--fx) 75%, transparent);
}

/* pills */
.fx-pills { display: flex; flex-wrap: wrap; gap: 7px; }
.fx-pill {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .03em;
  border-radius: var(--r-pill);
  padding: 6px 11px; color: var(--ink-2);
  background: var(--card);
  box-shadow: 0 0 0 1px var(--line), 0 4px 10px -8px rgba(16, 18, 16, .4);
  white-space: nowrap;
}
.fx-pill--on {
  background: linear-gradient(180deg, color-mix(in srgb, var(--fx) 84%, #fff), var(--fx));
  color: #fff;
  box-shadow: 0 5px 14px -6px color-mix(in srgb, var(--fx) 70%, transparent);
}

/* checklist */
.fx-check { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.fx-check li { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--ink); }
/* Ticked is the RESTING state — these are things the app does, not a to-do
   list. Only when the deck's JS is actually driving (html.fd-js) do they
   start blank so they can tick themselves off. */
.fx-tick {
  width: 18px; height: 18px; flex: none; border-radius: 50%;
  position: relative;
  background: linear-gradient(180deg, color-mix(in srgb, var(--fx) 80%, #fff), var(--fx));
  box-shadow: 0 4px 9px -5px color-mix(in srgb, var(--fx) 80%, transparent);
  transition: background .25s var(--ease), box-shadow .25s var(--ease);
}
.fx-tick::after {
  content: ""; position: absolute; left: 5px; top: 2.5px;
  width: 4px; height: 8px; border: solid #fff; border-width: 0 1.9px 1.9px 0;
  transform: rotate(45deg) scale(1);
  transition: transform .26s var(--ease-spring);
}
html.fd-js .fx-check li:not(.on) { color: var(--ink-2); }
html.fd-js .fx-check li:not(.on) .fx-tick {
  background: var(--card);
  box-shadow: inset 0 0 0 1.6px var(--line-2);
}
html.fd-js .fx-check li:not(.on) .fx-tick::after { transform: rotate(45deg) scale(0); }

/* chat bubbles */
.fx-chat { display: grid; gap: 9px; }
.fx-bub { font-size: 13px; line-height: 1.5; border-radius: 15px; padding: 10px 13px; max-width: 88%; }
.fx-bub--me {
  justify-self: end; color: #fff; border-bottom-right-radius: 5px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--fx) 84%, #fff), var(--fx));
  box-shadow: 0 8px 18px -10px color-mix(in srgb, var(--fx) 70%, transparent);
}
.fx-bub--ai {
  justify-self: start; background: var(--card); border-bottom-left-radius: 5px;
  box-shadow: 0 0 0 1px var(--line), 0 8px 18px -14px rgba(16, 18, 16, .5);
}
.fx-caret { display: inline-block; width: 1.5px; height: 1em; background: var(--fx); vertical-align: -2px; margin-left: 2px; border-radius: 1px; }

/* phone frame */
.fx-phone {
  width: 118px; margin: 0 auto; border-radius: 20px; padding: 6px;
  background: linear-gradient(160deg, #2a2c2a, #101210);
  box-shadow: 0 18px 34px -20px rgba(16, 18, 16, .7);
}
.fx-phone-screen {
  border-radius: 15px; background: var(--card); overflow: hidden;
  aspect-ratio: 9 / 17; padding: 9px 8px; display: grid; align-content: start; gap: 6px;
}

/* watch frame */
.fx-watch { width: 92px; margin: 0 auto; }
.fx-watch-body {
  border-radius: 28px; padding: 8px 7px;
  background: linear-gradient(160deg, #2a2c2a, #101210);
  box-shadow: 0 16px 30px -18px rgba(16, 18, 16, .75);
}
.fx-watch-screen {
  border-radius: 22px; background: #000; aspect-ratio: 4/5;
  display: grid; place-content: center; gap: 4px; text-align: center; color: #fff;
}

/* stacked layers */
.fx-stack { position: relative; height: 104px; }
.fx-layer {
  position: absolute; left: 0; right: 0;
  background: var(--card);
  border-radius: var(--r-sm); padding: 9px 12px;
  display: flex; align-items: center; gap: 9px;
  font-size: 12.5px;
  box-shadow: 0 0 0 1px var(--line), 0 10px 20px -14px rgba(16, 18, 16, .55);
}

.fx-dotled {
  width: 8px; height: 8px; border-radius: 50%; background: var(--fx); flex: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx) 16%, transparent);
}

/* code sample */
.fx-code {
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.8;
  background: var(--card);
  border-radius: var(--r-md); padding: 13px 14px; overflow: hidden;
  white-space: pre; color: var(--ink-2);
  box-shadow: 0 0 0 1px var(--line), 0 10px 22px -18px rgba(16, 18, 16, .5);
}
.fx-code b { font-weight: 500; color: var(--fx); }

/* before / after comparison */
.fx-vs { display: grid; gap: 12px; }
.fx-vs-row { display: grid; grid-template-columns: 62px 1fr auto; align-items: center; gap: 11px; }
.fx-vs-row .fx-mono { text-align: right; }

/* ---------- resting state before the reveal runs ---------- */
/* Cards are NOT hidden by the stylesheet. featuredeck.js hides only the ones
   that are already below the fold when it runs, so nothing on screen can be
   blanked after it has painted — the deck script is deferred, and hiding from
   CSS meant a card could render and then vanish. */

@media (max-width: 1080px) {
  .fx { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .fx-w4, .fx-w6 { grid-column: span 4; }
}
@media (max-width: 720px) {
  .fx { grid-template-columns: 1fr; gap: 14px; }
  .fx-card, .fx-w3, .fx-w4, .fx-w6 { grid-column: span 1; }
  .fx-card { padding: 22px 20px 20px; border-radius: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-card:hover { transform: none; }
}

/* ===================================================================
   Richer pieces for the Cinder deck — a set logger that fills its
   card, a watch that reads as a watch, and a ring with the trend
   attached to it.
   =================================================================== */

/* ---- set logger ---- */
.fx-log { display: grid; grid-template-columns: 1.05fr .95fr; gap: 16px; align-items: stretch; }
.fx-log-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.fx-log-name { font-size: 14.5px; font-weight: 600; letter-spacing: -.01em; }
.fx-log-set {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fx);
  background: color-mix(in srgb, var(--fx) 12%, transparent);
  border-radius: var(--r-pill); padding: 4px 9px; white-space: nowrap;
}
/* reps × weight, sized so the pair reads as one figure */
.fx-log-fig { display: flex; align-items: flex-end; gap: 11px; }
.fx-log-fig .fx-num { font-size: 34px; }
.fx-log-x { font-size: 18px; color: var(--ink-3); padding-bottom: 5px; }
.fx-log-units { display: flex; gap: 11px; margin-top: 7px; }
.fx-log-units span { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-3); }
.fx-log-units span:first-child { width: 44px; }

/* the four set slots, so progress through the exercise is visible */
.fx-slots { display: flex; gap: 5px; margin-top: 16px; }
.fx-slots i {
  flex: 1 1 0; height: 5px; border-radius: 99px;
  background: rgba(16, 18, 16, .1);
}
.fx-slots i.done { background: var(--fx); }
.fx-slots i.now {
  background: color-mix(in srgb, var(--fx) 42%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--fx) 18%, transparent);
}

/* the set history beside it */
.fx-sets { display: grid; gap: 7px; align-content: start; }
.fx-set {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 9px;
  font-size: 12.5px; color: var(--ink-2);
  padding: 7px 10px; border-radius: 10px;
  background: color-mix(in srgb, var(--fx) 5%, transparent);
}
.fx-set--now {
  color: var(--ink); font-weight: 500;
  background: var(--card);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--fx) 26%, transparent);
}
.fx-set--todo { opacity: .5; }
.fx-set-n { font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); }
.fx-set-v { font-variant-numeric: tabular-nums; text-align: right; }
.fx-set-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--fx); }
.fx-set--todo .fx-set-dot { background: rgba(16, 18, 16, .18); }

/* ---- a watch that looks like a watch ---- */
.fx-watch { width: 104px; margin: 0 auto; position: relative; }
/* band lugs above and below the case */
.fx-watch::before, .fx-watch::after {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%);
  width: 58px; height: 16px; background: #1b1d1b; z-index: 0;
}
.fx-watch::before { top: -11px; border-radius: 8px 8px 3px 3px; }
.fx-watch::after { bottom: -11px; border-radius: 3px 3px 8px 8px; }
.fx-watch-body {
  position: relative; z-index: 1;
  border-radius: 30px; padding: 7px;
  background: linear-gradient(150deg, #43464a 0%, #1c1e1e 44%, #0c0d0c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .22),
    0 18px 32px -18px rgba(16, 18, 16, .8);
}
/* the digital crown */
.fx-watch-body::after {
  content: ""; position: absolute; right: -4px; top: 34%;
  width: 5px; height: 20px; border-radius: 3px;
  background: linear-gradient(90deg, #5a5d61, #2c2e30);
}
.fx-watch-screen {
  border-radius: 24px; background: #000; aspect-ratio: 4/4.7;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; color: #fff; padding: 8px 7px;
}
.fx-watch-label { font-family: var(--font-mono); font-size: 7.5px; letter-spacing: .13em; color: rgba(255,255,255,.5); }
.fx-watch-big { font-size: 19px; font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.fx-watch-bar { width: 58px; height: 3px; border-radius: 99px; background: rgba(255,255,255,.16); overflow: hidden; }
.fx-watch-bar i { display: block; height: 100%; border-radius: 99px; background: var(--fx); width: var(--v, 60%); }
.fx-watch-foot { display: flex; gap: 8px; font-family: var(--font-mono); font-size: 7.5px; color: rgba(255,255,255,.55); }

/* ---- ring with its trend ---- */
.fx-ring--lg { width: 132px; height: 132px; }
.fx-ring-cap { fill: var(--fx); }
.fx-ring-note {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 14px; font-size: 12.5px; color: var(--ink-2);
}
.fx-trend {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 600; color: var(--fx);
  background: color-mix(in srgb, var(--fx) 12%, transparent);
  border-radius: var(--r-pill); padding: 3px 9px; font-size: 12px;
}

@media (max-width: 900px) {
  .fx-log { grid-template-columns: 1fr; gap: 14px; }
}

/* ===================================================================
   Route map + passport stamps, for Bilbo.
   =================================================================== */

/* ---- the map ---- */
.fx-map { width: 100%; height: 196px; display: block; overflow: visible; }
.fx-map .fx-map-water { fill: color-mix(in srgb, #4A90D9 14%, transparent); }
.fx-map .fx-map-park  { fill: color-mix(in srgb, #4CAF6A 15%, transparent); }
.fx-map .fx-map-block { fill: rgba(16, 18, 16, .045); }
.fx-map .fx-map-road  { stroke: rgba(16, 18, 16, .11); stroke-width: 2.4; stroke-linecap: round; fill: none; }
.fx-map .fx-map-lane  { stroke: rgba(16, 18, 16, .07); stroke-width: 1.2; stroke-linecap: round; fill: none; }

/* the walking route: a dashed line at rest, dots that travel when it plays */
.fx-leg {
  fill: none; stroke: var(--fx); stroke-width: 2.2;
  stroke-dasharray: 4 6; stroke-linecap: round;
  opacity: .85;
}
html.fd-js .fx-leg { stroke: none; }
.fx-legdot { fill: var(--fx); }

.fx-stop-ring { fill: var(--card); stroke: var(--fx); stroke-width: 3; }
.fx-stop-num {
  font-family: var(--font-mono); font-size: 9px; font-weight: 500;
  fill: var(--ink); text-anchor: middle; dominant-baseline: central;
}
.fx-stop-tag {
  font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .06em;
  fill: var(--ink-3); text-anchor: middle;
}
.fx-stop-pulse { fill: none; stroke: var(--fx); stroke-width: 2; opacity: 0; }

/* ---- passport stamps ---- */
.fx-stamps {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 6px;
  padding: 4px 0;
}
.fx-stamp {
  position: relative;
  width: 86px; height: 86px; flex: none;
  border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; text-align: center;
  transform: rotate(var(--r, 0deg));
  /* rubber-stamp ink: the colour, thinned, over a double ring */
  color: color-mix(in srgb, var(--fx) 78%, var(--ink));
  border: 2px solid currentColor;
  box-shadow: inset 0 0 0 3px transparent, inset 0 0 0 4.5px currentColor;
  opacity: .82;
  margin: 0 -7px;
}
.fx-stamp b {
  font-family: var(--font-mono); font-size: 8.5px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; line-height: 1.15;
  max-width: 62px;
}
.fx-stamp i {
  font-family: var(--font-mono); font-style: normal;
  font-size: 7px; letter-spacing: .12em; text-transform: uppercase;
  opacity: .78;
}
.fx-stamp::before,
.fx-stamp::after {
  content: ""; position: absolute; left: 12px; right: 12px; height: 1px;
  background: currentColor; opacity: .55;
}
.fx-stamp::before { top: 22px; }
.fx-stamp::after  { bottom: 22px; }
/* a couple of them read as a different ink so the page looks lived in */
.fx-stamp--alt { color: color-mix(in srgb, var(--ink) 62%, var(--fx)); opacity: .6; }

.fx-stamps-note {
  display: flex; align-items: baseline; justify-content: center; gap: 8px;
  margin-top: 12px;
}

@media (max-width: 520px) {
  .fx-stamp { width: 74px; height: 74px; }
  .fx-stamp b { font-size: 7.5px; }
}

/* ---- a photo with detections drawn on it (Haplo AI vision) ---- */
.fx-shot {
  position: relative; width: 100%; height: 132px;
  border-radius: var(--r-md); overflow: hidden;
  background: linear-gradient(170deg, #eef3f7 0%, #e3ebf2 52%, #dbe6ee 100%);
  box-shadow: 0 0 0 1px var(--line), 0 10px 22px -18px rgba(16, 18, 16, .5);
}
.fx-shot-sky {
  position: absolute; left: 0; right: 0; bottom: 0; height: 42%;
  background: linear-gradient(180deg, rgba(16,18,16,.05), rgba(16,18,16,.11));
}
.fx-shot-cat {
  position: absolute; left: 26%; top: 50%; transform: translate(-50%, -50%);
  font-size: 52px; line-height: 1;
}
.fx-bbox {
  position: absolute; left: 10%; top: 18%; width: 34%; height: 62%;
  border: 2px solid var(--fx); border-radius: 4px;
}
.fx-bbox-tag {
  position: absolute; left: -2px; top: 0; transform: translateY(-100%);
  background: var(--fx); color: #fff;
  font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .04em;
  padding: 2px 6px; border-radius: 4px 4px 0 0; white-space: nowrap;
}
.fx-bbox--alt { left: 54%; top: 44%; width: 30%; height: 36%; border-color: var(--ink-3); }
.fx-bbox--alt .fx-bbox-tag { background: var(--ink-3); }

/* ---- a headline number that isn't alone in the box ---- */
.fx-figure { text-align: center; }
.fx-figure .fx-num { display: block; }
.fx-figure .fx-unit { display: block; margin-top: 7px; }
.fx-figure-row {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 6px;
  margin-top: 14px;
}

/* ===================================================================
   Biological age, built to match what the app actually shows: an
   organic blob behind the figure, the "younger than" pill, and the
   pace-of-aging scale with its tick marks.
   =================================================================== */
.fx-bio { display: flex; flex-direction: column; gap: 16px; }

.fx-bio-top { position: relative; display: grid; place-items: center; padding: 6px 0 2px; }
.fx-blob {
  position: relative;
  width: 152px; aspect-ratio: 1 / .94;
  display: grid; place-content: center; gap: 3px; text-align: center;
  background: linear-gradient(155deg,
    color-mix(in srgb, var(--fx) 26%, #fff) 0%,
    color-mix(in srgb, var(--fx) 12%, #fff) 58%,
    #fff 100%);
  /* the soft squircle the app uses, not a circle */
  border-radius: 62% 38% 46% 54% / 54% 46% 54% 46%;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 14px 30px -20px color-mix(in srgb, var(--fx) 70%, transparent);
}
.fx-bio-num { font-size: 40px; font-weight: 700; letter-spacing: -.045em; line-height: 1; font-variant-numeric: tabular-nums; }
.fx-bio-label { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-2); }
.fx-bio-pill {
  margin-top: 6px; justify-self: center;
  background: color-mix(in srgb, var(--fx) 88%, var(--ink));
  color: #fff; font-size: 11.5px; font-weight: 600;
  padding: 4px 11px; border-radius: var(--r-pill);
  box-shadow: 0 6px 14px -8px color-mix(in srgb, var(--fx) 80%, transparent);
  white-space: nowrap;
}

/* pace of aging */
.fx-pace-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.fx-pace-title { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-2); }
.fx-pace-val { font-size: 19px; font-weight: 600; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.fx-pace-ends { display: flex; justify-content: space-between; font-size: 10.5px; margin-top: 6px; }
.fx-pace-ends .slow { color: var(--fx); font-weight: 500; }
.fx-pace-ends .fast { color: var(--ink-3); }
.fx-scale { position: relative; height: 30px; margin-top: 4px; }
.fx-scale-ticks { display: flex; align-items: flex-end; justify-content: space-between; height: 100%; }
.fx-scale-ticks i { width: 1.5px; height: 46%; background: rgba(16,18,16,.16); border-radius: 1px; }
.fx-scale-ticks i:nth-child(5n + 1) { height: 74%; background: rgba(16,18,16,.22); }
.fx-scale-mark {
  position: absolute; top: 0; bottom: 0; width: 3.5px; border-radius: 2px;
  background: var(--fx); left: var(--at, 32%);
  box-shadow: 0 0 10px -1px color-mix(in srgb, var(--fx) 80%, transparent);
}
.fx-scale-axis { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 9px; color: var(--ink-3); margin-top: 5px; }

/* the object inside a detection box */
.fx-bbox-obj {
  position: absolute; inset: 0;
  display: grid; place-content: center;
  font-size: 30px; line-height: 1;
}

/* what actually goes over the network, and what never does */
.fx-net { display: grid; gap: 8px; }
.fx-net-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 11px;
  background: var(--card); border-radius: var(--r-sm); padding: 9px 12px;
  box-shadow: 0 0 0 1px var(--line), 0 8px 18px -16px rgba(16,18,16,.5);
}
.fx-net-ic { font-size: 17px; line-height: 1; }
.fx-net-what { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.fx-net-what b { font-size: 12.5px; font-weight: 600; }
.fx-net-what i { font-style: normal; font-size: 11px; color: var(--ink-3); }
.fx-net-when {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fx);
  background: color-mix(in srgb, var(--fx) 11%, transparent);
  padding: 4px 8px; border-radius: var(--r-pill); white-space: nowrap;
}
.fx-net-row--never .fx-net-when { color: var(--ink-3); background: rgba(16,18,16,.06); }

/* Home Screen widget tiles */
.fx-widgets { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; }
.fx-widget {
  background: var(--card); border-radius: 14px; padding: 11px 12px;
  display: flex; flex-direction: column; gap: 3px;
  box-shadow: 0 0 0 1px var(--line), 0 8px 18px -14px rgba(16,18,16,.5);
}
.fx-widget b { font-size: 19px; font-weight: 600; letter-spacing: -.03em; line-height: 1.1; }
.fx-widget i {
  font-style: normal; font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.fx-widget--fx { background: linear-gradient(165deg, color-mix(in srgb, var(--fx) 88%, #fff), var(--fx)); }
.fx-widget--fx b, .fx-widget--fx i { color: #fff; }
.fx-widget--fx i { opacity: .85; }
.fx-widget--wide { grid-column: span 2; }
@media (max-width: 720px) { .fx-widgets { grid-template-columns: repeat(2, 1fr); } }

/* SVG groups scale about themselves, not the viewBox origin */
.fx-chart g, .fx-map g, .fx-candle g { transform-box: fill-box; transform-origin: 50% 50%; }

/* ===================================================================
   Barrier: the real app icons, locking one after another.
   =================================================================== */
.fx-locks { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }
.fx-lock { position: relative; width: 54px; height: 54px; flex: none; }
.fx-lock img {
  width: 100%; height: 100%; display: block; border-radius: 14px;
  box-shadow: 0 0 0 1px rgba(16,18,16,.07), 0 8px 18px -10px rgba(16,18,16,.5);
  transition: filter .45s var(--ease), opacity .45s var(--ease);
}
/* the padlock badge, sitting on the corner */
.fx-lock i {
  position: absolute; right: -5px; bottom: -5px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--fx); color: #fff;
  display: grid; place-content: center;
  font-size: 11px; font-style: normal; line-height: 1;
  box-shadow: 0 0 0 2.5px var(--card), 0 4px 10px -4px color-mix(in srgb, var(--fx) 80%, transparent);
  opacity: 0; transform: scale(.4);
  transition: opacity .3s var(--ease), transform .34s var(--ease-spring);
}
.fx-lock.locked img { filter: blur(2.6px) grayscale(.7); opacity: .55; }
.fx-lock.locked i { opacity: 1; transform: none; }

/* a pill carrying the app it refers to */
.fx-pill img {
  width: 15px; height: 15px; border-radius: 4px; display: inline-block;
  vertical-align: -3px; margin-right: 5px;
}

/* ---- continuous loops, formerly driven by the animation library ---- */
@keyframes fxPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes fxFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@keyframes fxSweep { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
@keyframes fxPing  { from { opacity: .7; transform: scale(.5); } to { opacity: 0; transform: scale(2.4); } }
.fx-loop-pulse { animation: fxPulse 2.2s ease-in-out infinite; }
.fx-loop-float { animation: fxFloat 4.5s ease-in-out infinite; }
.fx-loop-sweep { animation: fxSweep 1.8s ease-in-out infinite; }
.fx-pinging    { animation: fxPing .9s ease-out both; transform-box: fill-box; transform-origin: 50% 50%; }
@media (prefers-reduced-motion: reduce) {
  .fx-loop-pulse, .fx-loop-float, .fx-loop-sweep, .fx-pinging { animation: none; }
}
