/* ky-feel.css — the visual half of native feel.

   Paired with ky/ky-feel.js, which stamps data-ky-feel="native" (default) or
   "cinematic" on <html>. Everything here is scoped to native so that
   ?feel=cinematic restores the authored look exactly by doing nothing.

   1. THE CURSOR
   -------------
   ky-world.css does `html.kyw-curon, html.kyw-curon body { cursor: none }` and
   substitutes a JS-drawn dot + eased ring. That cannot track the pointer, and
   not because it is written badly:

     - the OS cursor is composited by the system at the mouse's own report rate
       (125-1000Hz) with essentially zero latency;
     - a JS dot is sampled in a rAF callback and moved with a CSS transform, so
       it cannot be fresher than one frame, and in practice lands 2-3 frames
       late once style + paint + composite are counted — 16-50ms of visible gap;
     - the ring is additionally eased at 0.16/frame, i.e. deliberately ~5
       frames behind, which is the design.

   So "the cursor doesn't follow the pointer properly" is structural. The only
   fix is to stop hiding the real one. The JS cursor is display:none rather
   than torn down so that no world module has to know about this — its rAF
   callback keeps writing transforms to an element with no box, which costs
   nothing to lay out or paint.

   2. THE INK FILTERS
   ------------------
   index.html carries three rules, all gated on html.honeykit:not(.nokitfx):

     h1 svg        filter: url(#goo-tight) url(#roughen)
     h2            filter: url(#roughen)
     .ky-heroname  filter: url(#goo-tight) url(#roughen)

   Both filters are ANIMATED, with repeatCount="indefinite":

     #goo-tight   feGaussianBlur stdDeviation 3.4->5->3.4 every 2.8s
     #roughen     feTurbulence baseFrequency cycling every 7s, feeding a
                  feDisplacementMap whose scale cycles 5->9->5 every 5s

   An animated filter cannot be cached: its output is invalid on every frame,
   so the whole chain re-runs forever. Measured on this page that is 3 elements
   / 506,936px of content, and because #roughen declares x/y -40% and
   width/height 180% the actual filter REGION is 3.24x that — about 1.64
   MILLION pixels of feTurbulence per frame. feTurbulence is Perlin noise
   evaluated per pixel and is not GPU-accelerated in Chromium.

   That is the lag, and it is invisible to an fps counter: it runs on the
   raster/compositor side, so the main thread stays idle at 240fps with zero
   long-animation-frames while the machine is actually flat out. It is also
   why the text looks wrong — feDisplacementMap is literally shifting the
   glyphs by up to 9px of animated noise, continuously.

   nokitfx is not invented here: ky-themes.js already exposes it as the
   "liquid type off" user setting, so this is an existing supported state.
   The belt-and-braces `filter: none` below covers any rule that reaches the
   same elements without going through that class. */

html[data-ky-feel="native"].kyw-curon,
html[data-ky-feel="native"].kyw-curon body { cursor: auto; }

html[data-ky-feel="native"] .kyw-cur { display: none !important; }

/* 2026-08-13: the `h2` and `.ky-heroname` arms of this rule were DELETED.
   They were the second half of the ink kill-switch described above, and
   together with ky-feel.js's kit() they took the owner's signature type
   treatment off every world by default. See ky/ky-ink.js for what replaced
   them: the <animate> nodes are stripped at runtime, so the filters are static
   and cacheable, and the ink is re-applied per element in
   ky/worlds/idx-honey-ink.css rather than by a blanket tag selector.

   `h1 svg` is kept only because it is free — index.html's own rebrandHero()
   replaced the hero's SVG letterforms with span.ky-heroname long ago, so this
   selector has matched nothing since. Measured count: 0. It is not carried
   forward into the new rules. */
html[data-ky-feel="native"] h1 svg { filter: none !important; }
