/* fx-kit.css — shared interaction kit (Osmo-inspired), v1.2.1, 12 Oct 2026.
   Canonical copy: thomas-tamine-site/site/assets/fx-kit.css. Vendored, unchanged, into tgai-site.
   Edit the canonical copy, then copy it across. Each site sets the --fx-* tokens to its own brand.
   Everything here is progressive: with no JS, or with reduced motion, content shows at rest. */

:root{
  --fx-accent:#622338;         /* fills, markers, progress */
  --fx-on-accent:#fff;         /* text on --fx-accent */
  --fx-marker:#c593ff;         /* highlighter colour */
  --fx-faint:.28;              /* resting opacity for highlight-on-scroll words */
  --fx-line:currentColor;      /* hairlines */
  --fx-ease:cubic-bezier(.2,.8,.2,1);
  --fx-ease-io:cubic-bezier(.7,0,.2,1);
}

/* ---- mask: lines rise out of a slot ---- */
.fx-ln{display:block;overflow:hidden;padding-bottom:.08em;margin-bottom:-.08em}
.fx-ln > span{display:block;transition:transform .9s var(--fx-ease)}
.fx-motion [data-fx="mask"].fx-wait .fx-ln > span{transform:translateY(110%);transition:none}

/* ---- highlight: words fill in on scroll ---- */
.fx-motion [data-fx="highlight"] .fx-w{opacity:var(--fx-faint);transition:opacity .25s linear}
.fx-motion [data-fx="highlight"] .fx-w.is-on{opacity:1}

/* ---- direction-aware list hover ---- */
[data-fx="dir-list"] > *{position:relative;overflow:hidden;isolation:isolate}
.fx-fill{position:absolute;inset:0;background:var(--fx-accent);transform:translateY(101%);transition:transform .35s var(--fx-ease),opacity 0s .35s;z-index:-1;pointer-events:none;opacity:0}
[data-fx="dir-list"] > .is-active > .fx-fill{opacity:1;transition:transform .35s var(--fx-ease),opacity 0s}
[data-fx="dir-list"] > .is-active{color:var(--fx-on-accent)}
[data-fx="dir-list"] > *{transition:color .2s}

/* ---- draw path on scroll ---- */
[data-fx="draw"] [data-fx-at]{transition:fill .3s,stroke .3s,opacity .3s}

/* ---- tools wall ---- */
[data-fx="wall"].fx-on > *{position:relative;overflow:hidden}
.fx-wall-item{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;transition:transform .6s var(--fx-ease-io),opacity .6s}
.fx-wall-item.is-out{transform:translateY(-100%);opacity:0}
.fx-wall-item.is-in{transform:translateY(100%);opacity:0}

/* ---- rotating text ---- */
[data-fx="rotate"].fx-on{display:inline-grid;overflow:hidden;vertical-align:bottom}
[data-fx="rotate"].fx-on > *{grid-area:1/1;transition:transform .7s var(--fx-ease-io);white-space:nowrap}

/* ---- highlighter marker ---- */
[data-fx="marker"] mark,[data-fx="marker"] .fx-mk{color:inherit;background-color:transparent;background-image:linear-gradient(var(--fx-marker),var(--fx-marker));background-repeat:no-repeat;background-size:100% 88%;background-position:0 70%;padding:0 .1em;transition:background-size 1s cubic-bezier(.6,0,.2,1);-webkit-box-decoration-break:clone;box-decoration-break:clone}
.fx-motion [data-fx="marker"].fx-wait mark,.fx-motion [data-fx="marker"].fx-wait .fx-mk{background-size:0% 88%;transition:none}

/* ---- magnetic ---- */
[data-fx="magnetic"]{transition:transform .5s cubic-bezier(.2,.9,.3,1.3)}
[data-fx="magnetic"] .fx-mag-inner{display:inline-block;transition:transform .5s cubic-bezier(.2,.9,.3,1.3)}

/* ---- fanned cards ---- */
[data-fx="fan"].fx-on{position:relative}
[data-fx="fan"].fx-on > *{position:absolute;left:50%;top:0;transition:transform .5s var(--fx-ease),filter .4s;cursor:pointer}
[data-fx="fan"].is-focus > :not(.is-front){filter:grayscale(1) brightness(.92)}

/* ---- footer revealed underneath ----
   Put .fx-reveal-body on the wrapper above the footer (it needs an opaque background)
   and .fx-reveal-foot on the footer. Footer must be shorter than the viewport. */
.fx-reveal-body{position:relative;z-index:1}
.fx-reveal-foot{position:sticky;bottom:0;z-index:0}
@media (max-height:560px){.fx-reveal-foot{position:static}}

/* ---- copy to clipboard ---- */
[data-fx="copy"]{display:inline-grid;overflow:hidden;cursor:pointer;vertical-align:bottom}
[data-fx="copy"] > .fx-copy-a,[data-fx="copy"] > .fx-copy-b{grid-area:1/1;transition:transform .45s var(--fx-ease-io)}
[data-fx="copy"] > .fx-copy-b{transform:translateY(110%)}
[data-fx="copy"].is-done > .fx-copy-a{transform:translateY(-110%)}
[data-fx="copy"].is-done > .fx-copy-b{transform:none}

/* ---- table of contents ---- */
[data-fx="toc"] ol{list-style:none;margin:0;padding:0;display:grid;gap:.15em}
[data-fx="toc"] a{display:block;padding:.3em 0 .3em .9em;border-left:1px solid color-mix(in srgb,currentColor 25%,transparent);color:inherit;text-decoration:none;opacity:.65;transition:opacity .2s,border-color .2s}
[data-fx="toc"] .fx-toc-h3 a{padding-left:1.8em;font-size:.92em}
[data-fx="toc"] a:hover{opacity:1}
[data-fx="toc"] a[aria-current="true"]{opacity:1;border-left:2px solid var(--fx-accent);padding-left:calc(.9em - 1px)}
[data-fx="toc"] .fx-toc-h3 a[aria-current="true"]{padding-left:calc(1.8em - 1px)}

/* ---- tabs with autoplay ---- */
[data-fx="tabs"] [role="tab"]{position:relative;cursor:pointer}
[data-fx="tabs"] .fx-tab-bar{position:absolute;left:0;right:0;bottom:0;height:2px;background:color-mix(in srgb,currentColor 18%,transparent);overflow:hidden;pointer-events:none}
[data-fx="tabs"] .fx-tab-bar > i{position:absolute;inset:0;background:var(--fx-accent);transform-origin:left;transform:scaleX(0)}
[data-fx="tabs"] [aria-selected="true"] .fx-tab-bar > i{transform:scaleX(1)}
[data-fx="tabs"].is-playing [aria-selected="true"] .fx-tab-bar > i{transform:scaleX(0);animation:fx-tab-fill var(--fx-tab-ms,6000ms) linear forwards}
[data-fx="tabs"].is-paused [aria-selected="true"] .fx-tab-bar > i{animation-play-state:paused}
[data-fx="tabs"] [role="tabpanel"].is-entering{animation:fx-tab-in .5s var(--fx-ease)}
@keyframes fx-tab-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes fx-tab-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* =================== added in v1.2 =================== */

/* ---- odometer ---- */
[data-fx="odometer"]{--fx-odo-h:1.15em}
[data-fx="odometer"].fx-on{display:inline-flex;align-items:flex-start;height:var(--fx-odo-h);line-height:var(--fx-odo-h);overflow:hidden;position:relative;vertical-align:bottom}
[data-fx="odometer"].fx-on > span{display:block;height:var(--fx-odo-h);white-space:pre}
.fx-odo-col{overflow:hidden}
.fx-odo-reel{display:block;transition:transform 1.6s cubic-bezier(.2,.8,.15,1)}
.fx-odo-reel > span{display:block;height:var(--fx-odo-h);text-align:center}

/* ---- compare: before/after ---- */
[data-fx="compare"].fx-on{position:relative;overflow:hidden;user-select:none;--fx-cmp:50%}
:where([data-fx="compare"].fx-on > :first-child){display:block;width:100%}
.fx-cmp-after{position:absolute;inset:0;clip-path:inset(0 0 0 var(--fx-cmp))}
.fx-cmp-after > *{display:block;width:100%;height:100%;object-fit:cover}
.fx-cmp-handle{position:absolute;top:0;bottom:0;left:var(--fx-cmp);width:2px;margin-left:-1px;background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.08);pointer-events:none}
.fx-cmp-handle::after{content:"";position:absolute;top:50%;left:50%;width:40px;height:40px;margin:-20px 0 0 -20px;border-radius:50%;background:var(--fx-accent);box-shadow:0 4px 14px rgba(0,0,0,.3);background-image:linear-gradient(90deg,transparent 30%,var(--fx-on-accent) 30% 36%,transparent 36% 64%,var(--fx-on-accent) 64% 70%,transparent 70%);background-size:60% 30%;background-repeat:no-repeat;background-position:center}
.fx-cmp-range{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:ew-resize;touch-action:pan-y;-webkit-appearance:none;appearance:none}
[data-fx="compare"]:has(.fx-cmp-range:focus-visible) .fx-cmp-handle::after{outline:3px solid var(--fx-on-accent);outline-offset:2px}

/* ---- hand-drawn underline ---- */
a.fx-ul{position:relative}
a.fx-ul:is(:hover,:focus-visible){text-decoration-color:transparent}
.fx-ul-svg{position:absolute;left:-3%;bottom:-.32em;width:106%;height:.55em;overflow:visible;pointer-events:none}
.fx-ul-svg path{fill:none;stroke:var(--fx-underline,var(--fx-accent));stroke-width:2.2;stroke-linecap:round;vector-effect:non-scaling-stroke;transition:stroke-dashoffset .5s cubic-bezier(.6,0,.3,1)}

/* ---- reading progress ---- */
[data-fx="progress"]{position:fixed;top:env(safe-area-inset-top,0px);left:0;right:0;height:3px;z-index:60;background:var(--fx-accent);transform-origin:left;transform:scaleX(var(--fx-p,0));pointer-events:none}

/* ---- capture form ---- */
[data-fx="capture"].is-sending [type="submit"]{opacity:.6;cursor:progress}

/* ---- steps: line fills as you scroll ---- */
[data-fx="steps"]{position:relative;list-style:none;padding-left:var(--fx-steps-pad,2rem)}
[data-fx="steps"]::before,[data-fx="steps"]::after{content:"";position:absolute;left:var(--fx-steps-x,.5rem);top:.5em;bottom:.5em;width:2px;margin-left:-1px;background:color-mix(in srgb,currentColor 18%,transparent)}
[data-fx="steps"]::after{background:var(--fx-accent);transform-origin:top;transform:scaleY(var(--fx-p,1))}
[data-fx="steps"] > *{position:relative}
[data-fx="steps"] > *::before{content:"";position:absolute;top:.4em;left:calc(var(--fx-steps-x,.5rem) - var(--fx-steps-pad,2rem) - 6px);width:12px;height:12px;border-radius:50%;background:var(--fx-accent);transition:background .3s,transform .3s}
[data-fx="steps"].fx-on > :not(.is-on)::before{background:color-mix(in srgb,currentColor 22%,transparent);transform:scale(.8)}

/* ---- tilt ---- */
[data-fx="tilt"]{transition:transform .45s var(--fx-ease)}
@media (hover:hover) and (pointer:fine){[data-fx="tilt"]{will-change:transform}}
[data-fx="tilt"].is-tilting{transition:transform .08s linear}

/* ---- marquee ---- */
[data-fx="marquee"].fx-on{overflow:hidden}
.fx-marquee-rail{display:flex;width:max-content;animation:fx-marquee var(--fx-mq-dur,30s) linear infinite}
.fx-marquee-rail > *{flex:none}
.fx-marquee-rail.is-reverse{animation-direction:reverse}
[data-fx="marquee"]:hover .fx-marquee-rail,[data-fx="marquee"]:focus-within .fx-marquee-rail{animation-play-state:paused}
@keyframes fx-marquee{to{transform:translateX(calc(-1 * var(--fx-mq-w,50%)))}}

/* ---- tone: colour follows the section in view ---- */
[data-fx="tone"]{transition:background-color .7s var(--fx-ease),color .7s var(--fx-ease)}

/* ---- glass ---- */
.fx-glass{background:color-mix(in srgb,var(--fx-glass-tint,#fff) 16%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid color-mix(in srgb,#fff 28%,transparent);box-shadow:inset 0 1px 0 color-mix(in srgb,#fff 35%,transparent),0 10px 30px -12px rgba(0,0,0,.35)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.fx-glass{background:color-mix(in srgb,var(--fx-glass-tint,#fff) 82%,transparent)}}

@media (prefers-reduced-motion:reduce){
  .fx-marquee-rail{animation:none}
  [data-fx] *,[data-fx]{transition:none!important;animation:none!important}
}
