/* =========================================================== */
/* The Tooth Place - living motion (build pass 4)               */
/* Pairs with ttp-living.js. Motion is led by graphics: figures,*/
/* stars, the gold arc, the teeth mark, the hero frame depth.   */
/* Words never move after their entrance. Every rule that moves */
/* something is gated by html.js and cancelled by              */
/* html.motion-off (OS reduced motion, ?static=1, or the a11y   */
/* panel's "Reduced") at the bottom of this file.               */
/* Numbers: 210 / 420 / 630 / 900ms, 70ms stagger, 3/7/14/21px. */
/* =========================================================== */

/* ---- 1a count-ups: the real figure stays in the DOM (transparent while the
   aria-hidden layer counts over it), so width never changes and readers get the value ---- */
.ttp-count { position: relative; display: inline-block; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ttp-count.is-counting > .ttp-count__real { color: transparent; }
.ttp-count__vis { position: absolute; inset: 0; text-align: right; pointer-events: none; }

/* ---- 1b stars fill one by one (70ms), from a faint mark to full gold ---- */
.ttp-stars.lv-stars .icon {
  opacity: 0.21; transform: scale(0.86);
  transition: opacity var(--duration-quick) var(--ease-soft), transform var(--duration-lift) var(--ease-settle);
  transition-delay: calc(var(--i, 0) * var(--stagger) + 210ms + var(--s, 0) * var(--stagger));
}
.ttp-stars.lv-stars .icon:nth-child(2) { --s: 1; }
.ttp-stars.lv-stars .icon:nth-child(3) { --s: 2; }
.ttp-stars.lv-stars .icon:nth-child(4) { --s: 3; }
.ttp-stars.lv-stars .icon:nth-child(5) { --s: 4; }
.ttp-stars.lv-stars.is-on .icon { opacity: 1; transform: none; }
.ttp-score .ttp-stars { --i: 0; }

/* ---- 1c Why Us numerals 01-06 tick up out of their own baseline slot as each row arrives
   (the visible bottom edge stays fixed: translate and clip move together) ---- */
html.js .ttp-why__num {
  transition: translate var(--duration-medium) var(--ease-satisfying), clip-path var(--duration-medium) var(--ease-satisfying);
  transition-delay: calc(var(--i, 0) * var(--stagger) + 210ms);
}
html.js .ttp-why__list:not(.in-view) .ttp-why__num { translate: 0 42%; clip-path: inset(0 0 42% 0); }

/* ---- 2 gold arc thread: the logo's brush arc (CSS mask, .ttp-arc) above chosen section heads.
   It wipes on once with its .reveal (rules in ttp-site.css) and is static after. ---- */
.ttp-arc--head { width: 70px; margin-bottom: 14px; }

/* ---- 3 teeth progress mark (>= 1200px only: it sits in the 63px gutter, bottom-left,
   clear of the gold rail and the a11y button on the right, and of the mobile sticky bar) ---- */
.ttp-progress { display: none; }
@media (min-width: 1200px) {
  .ttp-progress {
    position: fixed; left: 14px; bottom: calc(21px + env(safe-area-inset-bottom)); z-index: 85;  /* under the veil (90) */
    display: grid; place-items: center; width: 42px; height: 42px; padding: 0;
    background: var(--paper); border: 1px solid var(--line-strong); border-radius: var(--r-14);
    color: var(--charcoal); cursor: pointer;
    opacity: 0; visibility: hidden;
    transition: opacity var(--duration-quick) var(--ease-soft), visibility 0s linear var(--duration-quick), border-color var(--duration-quick) var(--ease-soft);
  }
  .ttp-progress.is-shown { opacity: 1; visibility: visible; transition-delay: 0s; }
  html.is-loading .ttp-progress { visibility: hidden; }
}
.ttp-progress svg { display: block; width: 28px; height: 28px; overflow: visible; }
/* WCAG pass 2026-09-24 (1.4.11 non-text contrast): the empty teeth were sage-soft on paper (1.5:1), so the
   control was barely visible early in the page. sage-deep is 3.8:1 on paper and 3.7:1 against the
   charcoal fill, so both the teeth and the filled/empty state read at 3:1 or more. */
.ttp-progress__base { fill: var(--sage-deep); }
/* high contrast maps --sage-deep to ink, which would hide the fill: empty teeth become paper with an ink edge */
html[data-contrast="high"] .ttp-progress__base { fill: var(--paper); stroke: var(--ink); stroke-width: 16; }
.ttp-progress__fill { fill: var(--charcoal); }
.ttp-progress:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; box-shadow: 0 0 0 3px var(--ink); }
@media (hover: hover) { .ttp-progress:hover { border-color: var(--charcoal); } }

/* ---- 4 hero: a STATIC wash (pass 6, owner decision: the time-based drift was removed, so nothing in
   the hero moves on its own; this also settles WCAG 2.2.2 without leaning on the panel).
   The photo frame's scroll depth is written by JS as `translate` (0..21px) and moves only when the
   visitor scrolls. ---- */
.ttp-hero::before {
  content: ""; position: absolute; inset: -21px; z-index: -1; pointer-events: none;
  background: radial-gradient(700px 700px at 72% 28%, rgba(156, 175, 136, 0.09), rgba(156, 175, 136, 0)) no-repeat;
}

/* ---- hover life: review cards lift 3px (hover and keyboard focus), no glow.
   The desk cards already lift 7px on hover / focus (ttp-site.css). This rule also restores
   the cards' staggered entrance, which the plain .ttp-review transition was overriding. ---- */
.ttp-reviews__cards > .ttp-review {
  transition: opacity var(--duration-medium) var(--ease-settle) calc(var(--i, 0) * var(--stagger)),
    transform var(--duration-medium) var(--ease-settle) calc(var(--i, 0) * var(--stagger)),
    translate var(--duration-quick) var(--ease-settle), border-color var(--duration-quick) var(--ease-soft);
}
@media (hover: hover) { .ttp-reviews__cards > .ttp-review:hover { translate: 0 -3px; } }
.ttp-reviews__cards > .ttp-review:focus-visible { translate: 0 -3px; border-color: var(--sage); }

/* ---- 5 brush-ink icons (pass 7, ttp-icons.js). A mask on the <svg> (works for <use>-referenced filled
   symbols, where a stroke draw cannot): a 105deg gradient with a soft, brush-width edge, 260% wide, slides
   from "all clear" to "all ink". The classes (and so the mask) are removed when the wipe ends: the resting
   icon has no mask at all, so its final state is exact.
   .ink-armed  waiting offscreen (hidden)      .ink-go  paint-in, 630ms, --ink-d = group stagger (70ms)
   .ink-re     hover / focus repaint, 300ms    .ink-hover (on the link / button / tab / card / row): tilt + lift */
svg.ttp-ink.ink-armed, svg.ttp-ink.ink-go, svg.ttp-ink.ink-re {
  -webkit-mask-image: linear-gradient(105deg, #000 0%, #000 36%, rgba(0, 0, 0, 0.55) 45%, rgba(0, 0, 0, 0.18) 52%, transparent 60%);
  mask-image: linear-gradient(105deg, #000 0%, #000 36%, rgba(0, 0, 0, 0.55) 45%, rgba(0, 0, 0, 0.18) 52%, transparent 60%);
  -webkit-mask-size: 260% 100%; mask-size: 260% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: 100% 0; mask-position: 100% 0;
}
svg.ttp-ink.ink-go { animation: ttp-ink var(--duration-medium, 630ms) cubic-bezier(0.33, 0.8, 0.3, 1) var(--ink-d, 0ms) both; }
svg.ttp-ink.ink-re { animation: ttp-ink 300ms cubic-bezier(0.33, 0.8, 0.3, 1) both; }
@keyframes ttp-ink {
  from { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  to   { -webkit-mask-position: 0 0; mask-position: 0 0; }
}
/* hover / focus = slide swap (owner 2026-09-25): the icon slides out to the right, its twin slides in
   from the left. Both are <use> copies inside the same <svg>, whose own box clips them, so nothing ever
   travels over other elements. Leaving hover reverses it. */
svg.ttp-ink { overflow: hidden; }
/* 2026-09-25 fix: icons whose ink reaches the box edge (mirror-probe) leaked a sliver of the parked twin
   (its optical outline stroke) into view. The twin now parks 130% away and stays invisible until it moves. */
svg.ttp-ink > use { transform-box: view-box; transition: transform 420ms var(--ease-settle), opacity 280ms var(--ease-settle); }
svg.ttp-ink > use.ink-twin { transform: translateX(-130%); opacity: 0; }
.ink-hover svg.icon.ttp-ink > use:not(.ink-twin) { transform: translateX(130%); opacity: 0; }
.ink-hover svg.icon.ttp-ink > use.ink-twin { transform: none; opacity: 1; }

/* ---- final states: reduced motion (OS), ?static=1 and the panel's "Reduced" ---- */
html.motion-off .ttp-count > .ttp-count__real { color: inherit !important; }
html.motion-off .ttp-count__vis { display: none !important; }
html.motion-off .ttp-stars .icon { opacity: 1 !important; transform: none !important; transition: none !important; }
html.motion-off .ttp-why__num { translate: none !important; clip-path: none !important; transition: none !important; }
html.motion-off .ttp-hero__frame { translate: none !important; }
html.motion-off .ttp-progress, html.motion-off .ttp-reviews__cards > .ttp-review { transition: none !important; }
html.motion-off .ttp-reviews__cards > .ttp-review:hover, html.motion-off .ttp-reviews__cards > .ttp-review:focus-visible { translate: none; }
html.motion-off svg.ttp-ink { -webkit-mask-image: none !important; mask-image: none !important; animation: none !important; translate: none !important; rotate: none !important; transition: none !important; }
html.motion-off svg.ttp-ink > use { transform: none !important; transition: none !important; }
html.motion-off svg.ttp-ink > use.ink-twin { display: none !important; }

/* the score link's underline: an inline-block does not receive its parent's decoration, so the
   figure carries the same underline itself (same offset and thickness, so the line is continuous) */
.ttp-score__meta .ttp-count { text-decoration: underline; text-decoration-color: var(--line-on-ink-strong); text-underline-offset: 6px; text-decoration-thickness: 1px; }
@media (hover: hover) { .ttp-score__meta:hover .ttp-count { text-decoration-color: var(--sage); } }
