/* ============================================================
   AMALAB — results-tiles.css
   Home #resultats « Si ça marche, ça doit se voir dans vos chiffres. »
   Six KPI bento tiles, Sierra-pattern, CENTRED composition: KPI label +
   title / centred line-art illustration / description, stacked on the axis.

   Colour system (V21.8 — flat brand navy, owner-directed « no gradient,
   brand colours »): every tile is ONE flat brand navy (#123C4A) — no
   gradient, no scrim, no glow, no glass. #123C4A is the sanctioned deep
   surface; the near-black navy-deep #0A1A20 is NOT used as a background
   (locked rule: navy-deep = text ink only). The six read as one KPI system;
   per-tile identity rides the illustration + title + index, not colour.
   Orange is NEVER a surface fill: it is the KPI text label (owner-directed +
   sanctioned by the locked orange rule, which lists KPI labels as orange
   marks) and, on KPI06 only, the upward trend line + arrowhead (the one
   measurable-value mark). The orange KPI label is sized as LARGE TEXT
   (≥18.66px @700) so it clears WCAG AA (3:1, computed 3.40) on flat navy —
   small orange would need 4.5 and fail, so the label grows, the tile never
   goes near-black. White title / paper desc clear AA comfortably (≥11:1).

   MEASUREMENT GRAMMAR (V24 rework — before→after stories, not assembly):
   the section's own copy is the spec — « Avant de construire, nous mesurons
   votre point de départ. Après, nous suivons les mêmes chiffres. La
   différence entre les deux, c'est le résultat. » Every illustration now
   performs that sentence with two inks:
     · FAINT paper (0.22–0.42) = AVANT — the measured starting point.
       Always lands FIRST (--d ≈ 130–420ms after the tile's --rt-base).
     · BRIGHT paper (0.86–0.94) = APRÈS — same chart, new numbers.
       Always lands SECOND (--d ≈ 520–1340ms). On KPI06 the après ink is
       orange (line + arrowhead — the one measurable-value signal).
     · The visible DELTA between the two inks is the payoff: lit adopters
       (01), the reclaimed arc (02), the ghost of removed time (03),
       jagged-high vs calm-low (04), everything above the cap line (05),
       the gap between projection and measurement (06).
   Per-element vars in the markup: --d (reveal delay), --d2 (KPI01 ignition
   delay), --dur (reveal duration where duration itself carries meaning —
   KPI03's avant bar crawls 700ms, its après bar snaps 300ms), --hd / --hdur
   (hover-replay delay / duration, après elements only).

   Motion doctrine: reveal on arrival (CSS transitions, interruptible,
   one-shot via js/site.js [data-reveal-stagger] → --ri + .is-visible), then
   a HOVER-gated ONE-SHOT REPLAY of the delta. The V21.8 infinite hover
   loops are RETIRED: their ping-pong keyframes spent half of every cycle in
   the semantically inverted state (bars shrinking, lines erasing, gains
   dimming — the opposite of every KPI's claim). The owner's 2026-07-24
   "replay on hover" intent is kept, made finite and story-true: hovering
   re-runs the APRÈS arrival once (`animation-iteration-count: 1`) and rests
   on the improved state. The AVANT ink never moves on hover — re-measuring
   never erases the baseline, and nothing ever animates toward regression.
   Also a motion-budget win: zero `infinite` animations remain in this file.
   Hover motion is gated (hover:hover) + (pointer:fine) — touch keeps only
   the shadow affordance ([[amalab-design-motion]] touch rule). no-JS →
   composed static (hidden states gate on html.js). reduced-motion →
   composed static, no transforms, no animations (block at end).
   Illustrations are aria-hidden, no text nodes (copy stays byte-identical
   in the markup). Palette: locked tokens only.
   ============================================================ */

/* ---------- Grid: reuse .grid.grid--3, room to breathe ---------- */
.results-grid { gap: clamp(16px, 2vw, 28px); }

/* ---------- Tile shell — flat brand navy, NO gradient ----------
   Owner-directed (2026-07-24): no gradients, brand colours only. Every tile
   is one flat brand navy (#123C4A) — the sanctioned deep surface, never the
   near-black navy-deep (locked rule: navy-deep = text ink only). The six read
   as one KPI system; per-tile identity rides the illustration + title + index.
   Orange KPI label clears WCAG AA as large text on this navy (see type). */
.result-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;      /* centred composition: KPI + title / illustration / description on the axis */
  justify-content: center;  /* group sits in the vertical centre of the tile */
  text-align: center;
  gap: clamp(12px, 1.7vw, 20px);
  min-height: clamp(244px, 24vw, 292px);
  padding: clamp(20px, 2.4vw, 30px);
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--navy);
  color: var(--inv-fg);
  /* Per-tile reveal base: bakes this tile's own --ri (set by js/site.js on
     each [data-reveal-stagger] child), inherits down to the illustration. */
  --rt-base: min(calc(var(--ri, 0) * 70ms), 560ms);
  /* Hover treatment mirrors the standard card (components.css .card:hover —
     lift + --shadow-card-hover, --t-ui/--ease-out) plus a slight grow
     (owner-directed 2026-07-24). Transition lives on the shell; the hover
     states are set below (two selectors, to win after the reveal settles). */
  transition: transform var(--t-ui) var(--ease-out),
              box-shadow var(--t-ui) var(--ease-out);
  --rt-hover-tf: translateY(-3px) scale(1.02);
}

/* KPI06 « Impact commercial » — the one measurable-value signal: orange trend
   line + arrowhead (INDICATEUR ↑). A mark, not a fill. Orange clears non-text
   (3:1) contrast on flat navy. Checkpoint dots stay paper. The faint dashed
   projection is .rt-soft, NOT .rt-line, so it never turns orange. Stroke
   colour is independent of the draw (stroke-dashoffset). */
.result-tile--06 .rt-line { stroke: var(--orange); }

/* ---------- Type: centred stack — KPI + title, illustration, description ---------- */
.result-tile__head { margin-bottom: 0; } /* gap on .result-tile spaces head / viz / desc */
.result-tile__kpi {
  /* KPI label in tertiary (orange) — owner-directed (2026-07-24) and sanctioned
     by the locked orange rule (KPI labels are orange marks). Sized as LARGE
     TEXT (≥18.66px @700) so orange clears WCAG AA (3:1, computed 3.40) on flat
     brand navy #123C4A — small orange would fail (needs 4.5), so the label
     grows rather than the tile going near-black. Orange stays OFF the fill: a
     label mark, not a surface. */
  font-size: clamp(1.1875rem, 1.07rem + 0.45vw, 1.3125rem); /* 19 → 21px */
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--orange);
  display: block;
  margin-bottom: var(--s-2);
}
.result-tile h3 {
  font-size: var(--step-h3); /* bumped from h4: keeps the title above the now-larger KPI label */
  line-height: 1.24;
  color: var(--inv-fg);
  margin: 0;
}
.result-tile__desc {
  margin-inline: auto; /* centred (was margin-top:auto bottom-push in the Sierra split) */
  font-size: var(--step-small);
  line-height: 1.5;
  color: rgba(251, 250, 248, 0.90);
  max-width: 34ch;
}

/* ---------- Illustration frame — the centred focal point ---------- */
.result-tile__viz {
  display: grid;
  place-items: center;
  flex: 0 0 auto; /* don't grow — the head/viz/desc group stays compact + vertically centred */
  min-height: 0;
  padding-block: clamp(4px, 1vw, 10px);
}
.result-tile__viz .rt-svg {
  width: min(82%, 184px);
  height: auto;
  overflow: visible;
}

/* Stroke language — the two-ink measurement grammar (paper on flat navy):
   FAINT = avant (ledge 0.28 furniture, soft 0.42 avant strokes, soft-bar 0.22
   avant fills, dot 0.34 unlit), BRIGHT = après (line 0.92, bar 0.86,
   dot--on 0.92, ignited 0.94). Dashed strokes (projection, cap, ghost) carry
   their dasharray as an SVG attribute; they only ever fade (.rt-fade), never
   draw, so the .rt-draw dasharray:1 technique stays free of conflicts. */
.rt-ledge   { stroke: rgba(251, 250, 248, 0.28); stroke-width: 1.4; stroke-linecap: round; }
.rt-line    { stroke: rgba(251, 250, 248, 0.92); stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.rt-soft    { stroke: rgba(251, 250, 248, 0.42); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.rt-ring    { stroke: rgba(251, 250, 248, 0.30); stroke-width: 1.6; fill: none; }
.rt-bar     { fill: rgba(251, 250, 248, 0.86); }
.rt-soft-bar{ fill: rgba(251, 250, 248, 0.22); }
.rt-dot     { fill: rgba(251, 250, 248, 0.34); }
.rt-dot--on { fill: rgba(251, 250, 248, 0.92); }
/* Ignition dots (KPI01 adopters): no-JS/base state = already lit (composed
   after-state). The html.js reveal block below re-bases them faint and lights
   them at --d2. */
.rt-ignite  { fill: rgba(251, 250, 248, 0.94); }

/* ============================================================
   Reveal choreography — avant draws faint first, après draws bright second.
   Delay = --rt-base (this tile's --ri, set on .result-tile) + per-element --d.
   Duration = per-element --dur where the markup sets one (duration carries
   meaning on KPI03: the long delay crawls, the short one snaps).
   Hidden states apply only under html.js (no-JS = composed).
   ============================================================ */

/* Stroke draw (lines, arcs, trend) — needs pathLength="1" in markup */
html.js .result-tile__viz .rt-draw {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset var(--dur, 800ms) var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 200ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-draw {
  stroke-dashoffset: 0;
}

/* Pop (dots) — scale + fade from their own centre (bigger initial scale = a
   clearer pop now the illustration is the focal point) */
html.js .result-tile__viz .rt-pop {
  opacity: 0;
  transform: scale(0.3);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 380ms var(--ease-out), transform 460ms var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 260ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-pop {
  opacity: 1;
  transform: none;
}

/* Ignite (KPI01 adopters — all carry .rt-pop too, so this rule sits AFTER
   .rt-pop and re-owns the transition longhands to add the fill channel):
   the dot pops in FAINT with the rest of the team grid at --d (phase A),
   then its fill lights up at --d2 (phase B) — adoption spreading person by
   person. The unlit teammates (.rt-dot) have no --d2 and simply stay faint. */
html.js .result-tile__viz .rt-ignite {
  fill: rgba(251, 250, 248, 0.30);
  transition-property: opacity, transform, fill;
  transition-duration: 380ms, 460ms, 540ms;
  transition-timing-function: var(--ease-out), var(--ease-out), var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 260ms)),
                    calc(var(--rt-base) + var(--d, 260ms)),
                    calc(var(--rt-base) + var(--d2, 640ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-ignite {
  fill: rgba(251, 250, 248, 0.94);
}

/* Grow (vertical bars) — rise from the baseline. KPI05's bright gain
   segments have their bottom edge ON the measured cap line, so origin:bottom
   makes them grow FROM the avant ceiling — the gain literally builds on the
   measurement. */
html.js .result-tile__viz .rt-grow {
  transform: scaleY(0);
  transform-box: fill-box;
  transform-origin: bottom;
  transition: transform var(--dur, 620ms) var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 220ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-grow {
  transform: none;
}

/* Extend (horizontal bars — KPI03's two délais) — grow from left. --dur is
   the story here: avant 700ms crawl, après 300ms snap. */
html.js .result-tile__viz .rt-extend {
  transform: scaleX(0);
  transform-box: fill-box;
  transform-origin: left center;
  transition: transform var(--dur, 640ms) var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 260ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-extend {
  transform: none;
}

/* Hand sweep (KPI02's needle) — the needle TRACKS the arc it measures.
   Authored in the markup at the measured position (composed no-JS state);
   html.js rebases it -120° so it rests at 12 o'clock (gauge at zero, visible
   as the tile arrives), then the reveal sweeps it to 0° = authored. It shares
   the arc's --d/--dur and easing: arc length is linear in angle, so identical
   timing makes the needle tip ride the arc's leading edge exactly — the
   gauge accumulates, the needle follows. Origin = the hub (64,42 in the
   128×76 view-box), so the rotation is physically about the pivot. */
html.js .result-tile__viz .rt-hand {
  transform: rotate(-120deg);
  transform-box: view-box;
  transform-origin: 64px 42px;
  transition: transform var(--dur, 640ms) var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 520ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-hand {
  transform: rotate(0deg);
}

/* Fade (reference furniture + dashed marks: baselines, ledges, the dial,
   the projection, the cap, the ghost of removed time) */
html.js .result-tile__viz .rt-fade {
  opacity: 0;
  transition: opacity 520ms var(--ease-out);
  transition-delay: calc(var(--rt-base) + var(--d, 160ms));
}
html.js [data-reveal-stagger].is-visible .result-tile__viz .rt-fade {
  opacity: 1;
}

/* ============================================================
   Hover interaction — lift + grow (card treatment), and the DELTA replays
   its arrival ONCE (`.rt-b` = the après elements, tagged in the markup).
   Replaces the V21.8 infinite ping-pong loops, which oscillated through the
   semantically inverted state (bars shrank, lines erased). A replay is a
   re-measurement: it cuts the delta back to its start, rebuilds it in story
   order (--hd stagger, `backwards` fill hides staggered parts while they
   wait), and RESTS on the improved state. The avant ink never moves; no
   animation in this file is infinite; re-hovering re-measures again.
   Interaction-gated: runs only on (hover:hover)+(pointer:fine) devices under
   html.js — touch keeps the shadow, reduced-motion opts out entirely.
   ============================================================ */

/* motion.css §1 owns the transition for stagger children (opacity+transform
   480ms; delay via --ri, dropped once site.js adds .is-settled). Re-declare
   it for the tiles with box-shadow ADDED, so the hover shadow eases in AND
   out; opacity+transform timings match §1 exactly, so the entrance and the
   .is-settled delay-drop are unchanged. (The base .result-tile transition
   still covers the no-JS path, where §1 never applies.) */
html.js [data-reveal-stagger] > .result-tile {
  transition: opacity 480ms var(--ease-out),
              transform 480ms var(--ease-out),
              box-shadow var(--t-ui) var(--ease-out);
}

/* Lift + grow. Two selectors: the plain one covers no-JS / pre-reveal; the
   stagger-scoped one re-wins after js/site.js settles the tile to
   transform:none (same override pattern as css/motion.css §6 for cards). The
   :hover transition is snappy (--t-ui, no delay) so the grow engages at once;
   releasing falls back to the shell transition for a gentle settle. */
.result-tile:hover,
html.js [data-reveal-stagger].is-visible > .result-tile:hover {
  box-shadow: var(--shadow-card-hover);
  transition: transform var(--t-ui) var(--ease-out),
              box-shadow var(--t-ui) var(--ease-out);
}

/* The grow is motion: fine-pointer devices only. Touch fires :hover on tap and
   leaves it stuck, so a tap would park the tile in its grown state until the
   next tap elsewhere. The shadow above stays ungated — it is the touch
   affordance, and it is not motion. */
@media (hover: hover) and (pointer: fine) {
  .result-tile:hover,
  html.js [data-reveal-stagger].is-visible > .result-tile:hover {
    transform: var(--rt-hover-tf);
  }
}

/* Replay keyframes — every one runs start → improved state and stops. None
   is infinite; none passes through a regressed value on its way anywhere.
   The reveal rules above already leave transform-box / transform-origin /
   stroke-dasharray:1 in force, so from-states land correctly. */
@keyframes rtr-draw   { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes rtr-grow   { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes rtr-extend { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes rtr-fade   { from { opacity: 0; } to { opacity: 1; } }
@keyframes rtr-pop    { from { opacity: 0; transform: scale(0.3); } to { opacity: 1; transform: scale(1); } }
/* KPI01 adopters don't re-ignite from dark (that would un-light the team);
   they pulse — a wave of "still in daily use" rippling in ignition order. */
@keyframes rtr-pulse  { 0%, 100% { transform: scale(1); } 45% { transform: scale(1.16); } }
/* KPI02 needle: re-sweeps with the arc's redraw (same --hd/--hdur → synced). */
@keyframes rtr-sweep  { from { transform: rotate(-120deg); } to { transform: rotate(0deg); } }

@media (hover: hover) and (pointer: fine) {
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-draw {
    animation: rtr-draw var(--hdur, 600ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-grow {
    animation: rtr-grow var(--hdur, 420ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-extend {
    animation: rtr-extend var(--hdur, 420ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-fade {
    animation: rtr-fade var(--hdur, 480ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-pop {
    animation: rtr-pop var(--hdur, 420ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
  html.js .result-tile:hover .result-tile__viz .rt-ignite {
    animation: rtr-pulse 520ms var(--ease-out) var(--hd, 0ms) 1 both;
  }
  html.js .result-tile:hover .result-tile__viz .rt-b.rt-hand {
    animation: rtr-sweep var(--hdur, 520ms) var(--ease-out) var(--hd, 0ms) 1 backwards;
  }
}

/* ---------- Responsive: one column on small screens ---------- */
@media (max-width: 640px) {
  .results-grid.grid--3 { grid-template-columns: repeat(2, 1fr); }
  .result-tile {
    min-height: 200px;
    padding: 16px;
  }
  .result-tile__viz .rt-svg { width: min(80%, 140px); }
  .result-tile h3 { font-size: var(--step-h4); }
  .result-tile__kpi { font-size: 1rem; }
  .result-tile__desc { font-size: 0.8125rem; }
}

/* ---------- Reduced motion: every illustration resolves composed ----------
   Both inks fully present, statically — the before→after story is still
   READABLE (faint avant vs bright après is a colour relationship, not
   motion); only the choreography is removed. No transforms, no animations
   ([[amalab-design-motion]] — unqualified). The hover shadow (not motion)
   stays as the affordance. */
@media (prefers-reduced-motion: reduce) {
  html.js .result-tile__viz .rt-draw {
    stroke-dashoffset: 0 !important;
    transition: none !important;
  }
  html.js .result-tile__viz .rt-pop,
  html.js .result-tile__viz .rt-grow,
  html.js .result-tile__viz .rt-extend,
  html.js .result-tile__viz .rt-fade,
  html.js .result-tile__viz .rt-hand {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  html.js .result-tile__viz .rt-ignite {
    fill: rgba(251, 250, 248, 0.94) !important;
    transition: none !important;
  }
  .result-tile:hover,
  html.js [data-reveal-stagger].is-visible > .result-tile:hover {
    transform: none !important;
  }
  html.js .result-tile:hover .result-tile__viz * {
    animation: none !important;
  }
}
