vireglass 2.3.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +37 -6
  2. package/dist/{adapters-BOPIRMnL.d.cts → adapters--bXcGvhW.d.cts} +2 -2
  3. package/dist/{adapters-B_amRBqc.d.ts → adapters-BlMhc6pI.d.ts} +2 -2
  4. package/dist/{chunk-MMPK6DCK.js → chunk-CPSIY2DZ.js} +58 -8
  5. package/dist/chunk-CPSIY2DZ.js.map +1 -0
  6. package/dist/{chunk-UDPJLNFW.js → chunk-RWUR3OV6.js} +4 -4
  7. package/dist/{chunk-UDPJLNFW.js.map → chunk-RWUR3OV6.js.map} +1 -1
  8. package/dist/{chunk-CTTZNZFV.js → chunk-VLDD655U.js} +3 -3
  9. package/dist/{chunk-CTTZNZFV.js.map → chunk-VLDD655U.js.map} +1 -1
  10. package/dist/{chunk-V47YU75P.js → chunk-YAN2OK4H.js} +31 -38
  11. package/dist/chunk-YAN2OK4H.js.map +1 -0
  12. package/dist/{chunk-SLRPHDV7.js → chunk-Z4FKYY47.js} +3 -3
  13. package/dist/{chunk-SLRPHDV7.js.map → chunk-Z4FKYY47.js.map} +1 -1
  14. package/dist/dom.cjs +180 -55
  15. package/dist/dom.cjs.map +1 -1
  16. package/dist/dom.d.cts +72 -25
  17. package/dist/dom.d.ts +72 -25
  18. package/dist/dom.js +116 -54
  19. package/dist/dom.js.map +1 -1
  20. package/dist/{geometry-RhKd7CM5.d.cts → geometry-ip9WSlZv.d.cts} +1 -1
  21. package/dist/{geometry-GvXtt-_S.d.ts → geometry-pabkYV7w.d.ts} +1 -1
  22. package/dist/{group-model-z4N27qsC.d.ts → group-model-CQiI5cCe.d.ts} +1 -1
  23. package/dist/{group-model-DwtixGhG.d.cts → group-model-DX2_W9J_.d.cts} +1 -1
  24. package/dist/index.cjs +92 -40
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +6 -6
  27. package/dist/index.d.ts +6 -6
  28. package/dist/index.js +5 -5
  29. package/dist/law.cjs +56 -6
  30. package/dist/law.cjs.map +1 -1
  31. package/dist/law.d.cts +54 -4
  32. package/dist/law.d.ts +54 -4
  33. package/dist/law.js +1 -1
  34. package/dist/{material-CnUmdKg1.d.ts → material-D9m1EN47.d.cts} +9 -6
  35. package/dist/{material-CnUmdKg1.d.cts → material-D9m1EN47.d.ts} +9 -6
  36. package/dist/react.d.cts +1 -1
  37. package/dist/react.d.ts +1 -1
  38. package/dist/reference.d.cts +2 -2
  39. package/dist/reference.d.ts +2 -2
  40. package/dist/reference.js +2 -2
  41. package/dist/web/index.cjs +91 -39
  42. package/dist/web/index.cjs.map +1 -1
  43. package/dist/web/index.d.cts +3 -3
  44. package/dist/web/index.d.ts +3 -3
  45. package/dist/web/index.js +4 -4
  46. package/docs/dom.md +49 -3
  47. package/docs/law.md +1 -1
  48. package/package.json +1 -1
  49. package/src/dom/body.ts +93 -39
  50. package/src/dom/index.ts +49 -20
  51. package/src/dom/probe.ts +1 -1
  52. package/src/dom/rim.ts +63 -28
  53. package/src/dom/style-hold.ts +8 -0
  54. package/src/law.ts +54 -4
  55. package/src/lens-shader.ts +26 -33
  56. package/src/material.ts +10 -7
  57. package/dist/chunk-MMPK6DCK.js.map +0 -1
  58. package/dist/chunk-V47YU75P.js.map +0 -1
package/dist/dom.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adaptation.ts","../src/law.ts","../src/geometry.ts","../src/sdf.ts","../src/dom/displacement.ts","../src/spectral.ts","../src/dom/spectral-map.ts","../src/dom/map-cache.ts","../src/optics.ts","../src/material.ts","../src/dom/probe.ts","../src/dom/support.ts","../src/shadow-tint.ts","../src/dom/shadow.ts","../src/dom/body.ts","../src/accessibility.ts","../src/dom/preferences.ts","../src/glass-scale.ts","../src/appear.ts","../src/accent.ts","../src/concentric.ts","../src/dom/rim.ts","../src/dom/nesting.ts","../src/adapters.ts","../src/touch-response.ts","../src/scroll-edge.ts","../src/dom/scroll-edge.ts","../src/group-model.ts","../src/dom/group.ts","../src/dom/index.ts"],"names":["BEVEL_SAMPLES","mapDensity","clamp01","thicknessDp","bevelDp","diffraction","clamp","luma","smoothstep","k","to255","r","g","b"],"mappings":";;;AAyCA,IAAM,YAAA,GAAe,EAAA;AAId,SAAS,YAAY,MAAA,EAAuE;AACjG,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAc,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,YAAY,CAAA,GAAI,YAAA;AACrF,EAAA,OAAO,CAAC,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AACxD;AAIO,IAAM,SAAA,GAAY,IAAA;AAClB,IAAM,QAAA,GAAW,IAAA;AAajB,SAAS,gBAAA,CAAiB,QAAuC,QAAA,EAA4B;AAClG,EAAA,OAAO,YAAA,CAAa,MAAM,CAAA,IAAK,QAAA,GAAW,SAAA,GAAY,WAAA,CAAA;AACxD;AAEO,IAAM,YAAA,GAAe,CAAC,MAAA,KAC3B,MAAA,CAAO,OAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,EAAA,IAAM,MAAA,CAAO,IAAA,IAAQ,IAAA;AAG7C,IAAM,SAAA,GAAY,IAAA;AAGlB,IAAM,WAAA,GAAc,GAAA;AAIpB,IAAM,aAAA,GAAgB,CAAA;;;ACjEtB,IAAM,GAAA,GAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAejB,YAAA,EAAc,CAAA;AAAA;AAAA,EAEd,WAAA,EAAa,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKb,QAAA,EAAU,IAAA;AAAA;AAAA,EAEV,OAAA,EAAS;AACX,CAAA;AAGO,IAAM,IAAA,GAAO;AAAA;AAAA,EAElB,QAAA,EAAU,IAAA;AAAA;AAAA,EAEV,QAAA,EAAU,IAAA;AAAA;AAAA,EAEV,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,IAAA;AAAA;AAAA,EAEX,QAAA,EAAU,IAAA;AAAA;AAAA,EAEV,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA,EAGZ,YAAA,EAAc,IAAA;AAAA,EACd,UAAA,EAAY,IAAA;AAAA;AAAA,EAEZ,SAAA,EAAW,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOX,cAAA,EAAgB;AAClB,CAAA;AAGO,IAAM,MAAA,GAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,SAAA,EAAW,IAAA;AAAA,EACX,SAAA,EAAW;AACb,CAAA;AAGO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW;AACb,CAAA;AAIO,IAAM,KAAA,GAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnB,SAAA,EAAW,IAAA;AAAA;AAAA;AAAA,EAGX,KAAA,EAAO,IAAA;AAAA;AAAA,EAEP,SAAA,EAAW,IAAA;AAAA;AAAA;AAAA,EAGX,UAAA,EAAY,IAAA;AAAA,EACZ,SAAA,EAAW,GAAA;AAAA;AAAA;AAAA,EAGX,QAAA,EAAU,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKV,gBAAA,EAAkB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKlB,YAAA,EAAc,IAAA;AAAA;AAAA,EAEd,WAAA,EAAa,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,SAAA,EAAW,CAUb,CAAA;AAKO,IAAM,KAAA,GAAQ;AAAA,EACnB,MAAA,EAAQ,IAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,QAAA,EAAU;AACZ,CAAA;AAGO,IAAM,OAAA,GAAU,IAAA;AA+BhB,IAAM,IAAA,GAAO;AAAA,EAGJ;AAAA,EAEd,QAAA,EAAU,EAAA;AAAA;AAAA,EAEV,OAAA,EAAS,IAAA;AAAA;AAAA,EAET,OAAA,EAAS,GAAA;AAAA,EACT,OAAA,EAAS,GAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAA;AAGO,IAAM,UAAA,GAAa;AAAA,EAKjB;AAAA,EAEP,IAAA,EAAM;AACR,CAAA;AAeO,IAAM,QAAA,GAAW;AAAA;AAAA;AAAA,EAGtB,gBAAA,EAAkB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYlB,gBAAA,EAAkB,IAAA;AAAA;AAAA,EAElB,kBAAA,EAAoB,CAAA;AAAA;AAAA,EAEpB,eAAA,EAAiB;AACnB,CAAA;AAGO,IAAM,MAAA,GAAS;AAAA;AAAA;AAAA,EAGpB,IAAA,EAAM,IAAA;AAAA,EACN,KAAA,EAAO,IAAA;AAAA;AAAA;AAAA,EAGP,MAAA,EAAQ;AACV,CAAA;AAOO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,UAAA,EAAY,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMZ,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA,EAGZ,eAAA,EAAiB,IAAA;AAAA;AAAA,EAEjB,gBAAA,EAAkB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlB,WAAA,EAAa,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,UAAA,EAAY;AACd,CAAA;AA+CO,IAAM,MAAA,GAAS;AAAA;AAAA,EAEpB,WAAA,EAAa,IAAA;AAAA;AAAA,EAEb,eAAA,EAAiB,CAAA;AAAA;AAAA,EAEjB,WAAA,EAAa,GAAA;AAAA;AAAA,EAEb,YAAA,EAAc,IAAA;AAAA;AAAA;AAAA,EAGd,gBAAA,EAAkB,GAAA;AAAA;AAAA;AAAA,EAGlB,sBAAA,EAAwB,KAAA;AAAA,EAEX;AAAA;AAAA,EAGb,cAAA,EAAgB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBhB,SAAA,EAAW,EAAA;AAAA;AAAA;AAAA,EAGX,mBAAA,EAAqB,GAAA;AAAA,EACrB,kBAAA,EAAoB,CAAA;AAAA;AAAA,EAEpB,oBAAA,EAAsB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtB,OAAA,EAAS,CAAC,IAAA,EAAM,CAAA,EAAK,IAAI,CAAA;AAAA,EACzB,UAAA,EAAY,CAAC,CAAA,EAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EAC5B,OAAA,EAAS,CAAC,IAAA,EAAM,CAAA,EAAK,IAAI,CAAA;AAAA;AAAA,EAEzB,UAAA,EAAY,GAAA;AAAA,EACZ,OAAA,EAAS,IAAA;AAAA;AAAA;AAAA,EAGT,YAAA,EAAc,IAAA;AAAA,EACd,aAAA,EAAe,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf,cAAA,EAAgB,CAAA;AAAA;AAAA;AAAA;AAAA,EAIhB,WAAA,EAAa,CAAA;AAAA,EACb,WAAA,EAAa,EAAA;AAAA;AAAA;AAAA,EAGb,WAAA,EAAa,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMb,aAAA,EAAe,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcf,qBAAA,EAAuB,KAAA;AAAA;AAAA;AAAA;AAAA,EAIvB,wBAAA,EAA0B,IAAA;AAAA;AAAA;AAAA,EAG1B,qBAAA,EAAuB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAevB,cAAA,EAAgB;AAClB,CAAA;AAOO,IAAM,IAAA,GAAO;AAAA;AAAA;AAAA,EAGlB,WAAA,EAAa,EAAA;AAAA;AAAA,EAEb,OAAA,EAAS,GAAA;AAAA,EACT,OAAA,EAAS,GAAA;AAAA;AAAA;AAAA,EAGT,gBAAA,EAAkB;AACpB,CAAA;AASO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,IAAA,EAAM,GAAA;AAAA;AAAA,EAEN,QAAA,EAAU,CAAA;AAAA,EACV,QAAA,EAAU,GAAA;AAAA;AAAA;AAAA,EAGV,IAAA,EAAM;AACR,CAAA;AAUO,IAAM,MAAA,GAAS;AAAA;AAAA,EAEpB,aAAA,EAAe,GAAA;AAAA,EACf,WAAA,EAAa,EAAA;AAAA;AAAA,EAEb,gBAAA,EAAkB,GAAA;AAAA,EAClB,cAAA,EAAgB,EAAA;AAAA;AAAA,EAEhB,WAAA,EAAa,IAAA;AAAA,EACb,YAAA,EAAc,IAAA;AAAA;AAAA;AAAA,EAGd,WAAA,EAAa,KAAA;AAAA;AAAA,EAEb,YAAA,EAAc,IAAA;AAAA;AAAA;AAAA,EAGd,SAAA,EAAW,IAAA;AAAA,EACX,kBAAA,EAAoB,CAAA;AAAA;AAAA;AAAA,EAGpB,aAAA,EAAe,GAAA;AAAA,EACf,gBAAA,EAAkB;AACpB,CAAA;AAGO,IAAM,KAAA,GAAQ;AAAA;AAAA,EAEnB,OAAA,EAAS,IAAA;AAAA;AAAA,EAET,aAAA,EAAe;AACjB,CAAA;AAUO,IAAM,WAAA,GAAc;AAAA;AAAA,EAEzB,QAAA,EAAU,EAAA;AAAA,EAaQ;AAAA;AAAA,EAGlB,cAAA,EAAgB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,QAAA,EAAU,GAAA;AAAA;AAAA;AAAA,EAGV,UAAA,EAAY,EAAA;AAAA,EACZ,SAAA,EAAW;AACb,CAAA;;;ACliBO,IAAM,mBAAA,GAAsB,CACjC,KAAA,EACA,MAAA,EACA,kBACuB,EAAE,KAAA,EAAO,QAAQ,YAAA,EAAa,CAAA;AAEhD,IAAM,SAAA,GAAY,CAAC,CAAA,KAAyB,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,EAAO,CAAA,CAAE,MAAM,CAAA,GAAI,GAAG,CAAC,CAAA;AAKvF,IAAM,WAAA,GAAc,IAAA;AAcpB,IAAM,SAAS,CAAC,CAAA,KACrB,KAAK,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,GAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,GAAQ,CAAA,CAAE,MAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAC,CAAA;AAiBlE,IAAM,QAAA,GAAW,CAAC,CAAA,KAAyB;AAChD,EAAA,MAAM,MAAM,IAAA,CAAK,IAAA,CAAK,OAAO,CAAC,CAAA,GAAI,KAAK,WAAW,CAAA;AAClD,EAAA,IAAI,GAAA,IAAO,IAAA,CAAK,OAAA,EAAS,OAAO,IAAA,CAAK,OAAA;AACrC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,OAAA;AACjC,EAAA,OAAO,IAAA,CAAK,OAAA,GAAU,IAAA,IAAQ,CAAA,GAAI,IAAA,CAAK,IAAI,EAAE,GAAA,GAAM,IAAA,CAAK,OAAA,CAAA,GAAW,IAAI,CAAA,CAAA;AACzE,CAAA;AAIO,IAAM,qBAAqB,IAAA,CAAK,gBAAA;AAEhC,IAAM,aAAA,GAAgB,CAAC,CAAA,EAAsB,CAAA,KAClD,KAAK,GAAA,CAAI,kBAAA,EAAqB,CAAA,CAAE,OAAA,GAAU,QAAA,CAAS,CAAC,CAAA,GAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAEhE,IAAM,OAAA,GAAU,CAAC,CAAA,EAAsB,CAAA,KAC5C,IAAA,CAAK,GAAA,CAAI,aAAA,CAAc,CAAA,EAAG,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,GAAG,CAAC,CAAA;AAEzC,IAAM,cAAc,CAAC,CAAA,EAAsB,MAChD,CAAA,CAAE,WAAA,GAAc,SAAS,CAAC,CAAA;AAIrB,IAAM,YAAA,GAAe,IAAA;AAErB,IAAM,QAAQ,CAAC,CAAA,EAAsB,MAAuB,WAAA,CAAY,CAAA,EAAG,CAAC,CAAA,GAAI,YAAA;AAGhF,IAAM,aAAA,GAAgB,CAAC,CAAA,KAC5B,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,SAAA,CAAU,CAAC,CAAA,GAAI,IAAA,EAAM,CAAC,GAAG,EAAE,CAAA;AAyExC,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,OACE,cAAA,CAAe,IAAA,GACf,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAC,CAAA,GAAI,cAAA,CAAe,QAAA,EAAU,cAAA,CAAe,QAAQ,CAAA;AAEjF;AAIO,SAAS,kBAAkB,MAAA,EAAkC;AAClE,EAAA,OAAO,IAAA,CAAK,MAAM,aAAA,CAAc,MAAA,CAAO,IAAI,CAAA,GAAI,cAAA,CAAe,IAAI,CAAA,GAAI,cAAA,CAAe,IAAA;AACvF;;;ACzKA,IAAM,MAAA,GAAS,aAAA;AAyJR,SAAS,cAAA,CAAe,CAAA,EAAW,CAAA,EAAW,CAAA,EAAW,GAAW,CAAA,EAAmB;AAC5F,EAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACjC,EAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACjC,EAAA,OAAO,IAAA,CAAK,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,EAAE,CAAA,EAAG,CAAC,CAAA,GAAI,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,CAAI,IAAI,CAAC,CAAA,EAAG,KAAK,GAAA,CAAI,EAAA,EAAI,CAAC,CAAC,CAAA,GAAI,CAAA;AACxF;AAQO,SAAS,sBAAA,CAAuB,CAAA,EAAW,CAAA,EAAW,CAAA,EAAW,GAAW,CAAA,EAA6B;AAC9G,EAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACjC,EAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACjC,EAAA,IAAI,EAAA;AACJ,EAAA,IAAI,EAAA;AACJ,EAAA,IAAI,EAAA,GAAK,CAAA,IAAK,EAAA,GAAK,CAAA,EAAG;AACpB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAM,CAAA;AAC9B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAM,CAAA;AAC9B,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAC7B,IAAA,EAAA,GAAK,EAAA,GAAK,GAAA;AACV,IAAA,EAAA,GAAK,EAAA,GAAK,GAAA;AAAA,EACZ,CAAA,MAAA,IAAW,KAAK,EAAA,EAAI;AAClB,IAAA,EAAA,GAAK,CAAA;AACL,IAAA,EAAA,GAAK,CAAA;AAAA,EACP,CAAA,MAAO;AACL,IAAA,EAAA,GAAK,CAAA;AACL,IAAA,EAAA,GAAK,CAAA;AAAA,EACP;AACA,EAAA,OAAO,CAAC,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,CAAC,GAAG,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAA;AAC9C;AAUO,SAAS,IAAA,CAAK,CAAA,EAAW,CAAA,EAAW,CAAA,EAAmB;AAC5D,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,GAAA,GAAO,GAAA,IAAO,CAAA,GAAI,CAAA,CAAA,GAAM,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,CAAA;AAC5D,EAAA,OAAO,KAAK,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,KAAK,CAAA,GAAI,CAAA,CAAA;AACxC;AAgCO,SAAS,aAAA,CACd,GACA,CAAA,EACA,CAAA,EACA,GACA,CAAA,EACA,SAAA,GAAY,MACT,MAAA,EACK;AACR,EAAA,IAAI,IAAI,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACpC,EAAA,IAAI,SAAA,IAAa,GAAG,OAAO,CAAA;AAC3B,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,KAAA,IAAS,CAAA,EAAG;AACxB,IAAA,CAAA,GAAI,KAAK,CAAA,EAAG,cAAA,CAAe,CAAA,GAAI,CAAA,CAAE,SAAS,CAAA,GAAI,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,YAAY,GAAG,SAAS,CAAA;AAAA,EACxG;AACA,EAAA,OAAO,CAAA;AACT;AAOO,SAAS,aAAA,CACd,GACA,CAAA,EACA,CAAA,EACA,GACA,CAAA,EACA,SAAA,GAAY,MACT,MAAA,EACe;AAClB,EAAA,IAAI,IAAI,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACpC,EAAA,IAAI,CAAC,IAAI,EAAE,CAAA,GAAI,uBAAuB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACnD,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,YAAY,CAAA,EAAG;AACjB,IAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,MAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,KAAA,IAAS,CAAA,EAAG;AACxB,MAAA,MAAM,EAAA,GAAK,IAAI,CAAA,CAAE,OAAA;AACjB,MAAA,MAAM,EAAA,GAAK,IAAI,CAAA,CAAE,OAAA;AACjB,MAAA,MAAM,EAAA,GAAK,eAAe,EAAA,EAAI,EAAA,EAAI,EAAE,KAAA,EAAO,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,YAAY,CAAA;AACnE,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,GAAA,GAAO,GAAA,IAAO,EAAA,GAAK,CAAA,CAAA,GAAM,SAAA,EAAW,CAAC,CAAA,EAAG,CAAC,CAAA;AAC1E,MAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,sBAAA,CAAuB,EAAA,EAAI,EAAA,EAAI,CAAA,CAAE,KAAA,EAAO,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,YAAY,CAAA;AACjF,MAAA,EAAA,GAAK,EAAA,GAAA,CAAM,KAAK,EAAA,IAAM,MAAA;AACtB,MAAA,EAAA,GAAK,EAAA,GAAA,CAAM,KAAK,EAAA,IAAM,MAAA;AACtB,MAAA,CAAA,GAAI,IAAA,CAAK,CAAA,EAAG,EAAA,EAAI,SAAS,CAAA;AACzB,MAAA,OAAA,GAAU,IAAA;AAAA,IACZ;AAAA,EACF;AAIA,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,CAAC,IAAI,EAAE,CAAA;AAG5B,EAAA,EAAA,IAAM,OAAA;AACN,EAAA,EAAA,IAAM,OAAA;AACN,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA,IAAK,CAAA;AAClC,EAAA,OAAO,CAAC,EAAA,GAAK,GAAA,EAAK,EAAA,GAAK,GAAG,CAAA;AAC5B;AAoBO,SAAS,SAAA,CAAU,CAAA,EAAW,CAAA,EAAW,CAAA,EAAgC;AAC9E,EAAA,IAAI,EAAE,MAAA,IAAU,CAAA,EAAG,OAAO,CAAC,GAAG,CAAC,CAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,CAAA,GAAI,KAAA,CAAM,SAAA,GAAY,CAAA,CAAE,KAAA;AACrC,EAAA,IAAI,KAAK,CAAA,GAAI,IAAA;AACb,EAAA,IAAI,KAAK,CAAA,GAAI,IAAA;AACb,EAAA,MAAM,EAAA,GAAK,KAAK,CAAA,CAAE,CAAA;AAClB,EAAA,MAAM,EAAA,GAAK,KAAK,CAAA,CAAE,CAAA;AAClB,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAE3B,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,CAAE,MAAA,GAAS,CAAA,IAAK,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA,EAAG,CAAC,CAAA;AAC5D,EAAA,MAAM,CAAA,GAAI,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,CAAA,CAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,CAAA,CAAA;AAE9B,EAAA,MAAM,GAAA,GAAM,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,CAAA,GAAK,CAAA;AAE9B,EAAA,EAAA,IAAM,CAAA,CAAE,KAAA,IAAS,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,GAAA,CAAA;AACtC,EAAA,EAAA,IAAM,CAAA,CAAE,KAAA,IAAS,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,GAAA,CAAA;AACtC,EAAA,EAAA,IAAM,EAAA,IAAM,CAAA,CAAE,KAAA,GAAQ,KAAA,CAAM,SAAA,GAAY,IAAA,CAAA;AACxC,EAAA,EAAA,IAAM,EAAA,IAAM,CAAA,CAAE,KAAA,GAAQ,KAAA,CAAM,SAAA,GAAY,IAAA,CAAA;AAExC,EAAA,IAAI,CAAA,CAAE,OAAA,GAAU,CAAA,IAAK,CAAA,GAAI,IAAA,EAAQ;AAC/B,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,MAAA,GAAS,KAAA,CAAM,QAAA;AAC9B,IAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,IAAK,IAAA,GAAO,MAAM,UAAA,CAAA,GAAc,CAAA,CAAE,SAAA,GAAY,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,IAAK,IAAA,GAAO,MAAM,SAAA,CAAU,CAAA;AACpH,IAAA,EAAA,IAAO,EAAA,GAAK,CAAA,GAAK,IAAA,GAAO,CAAA,CAAE,OAAA;AAC1B,IAAA,EAAA,IAAO,EAAA,GAAK,CAAA,GAAK,IAAA,GAAO,CAAA,CAAE,OAAA;AAAA,EAC5B;AACA,EAAA,OAAO,CAAC,IAAI,EAAE,CAAA;AAChB;;;ACpUA,IAAM,UAAA,GAAa,IAAA;AAYnB,IAAM,WAAA,GAAc,IAAA;AACpB,IAAM,YAAY,GAAA,GAAM,WAAA;AAYxB,IAAM,aAAA,GAAgB,CAAA;AAGtB,SAAS,UAAA,CAAW,QAAA,EAA6B,KAAA,EAAe,GAAA,EAAqB;AACnF,EAAA,IAAI,KAAA,IAAS,GAAG,OAAO,GAAA;AACvB,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,aAAA,GAAgB,KAAK,CAAA;AAC5C;AAIA,SAAS,MAAA,CAAO,cAAsB,KAAA,EAAuB;AAC3D,EAAA,MAAM,UAAU,IAAA,CAAK,KAAA,CAAM,GAAA,IAAO,YAAA,GAAe,QAAQ,GAAA,CAAI,CAAA;AAC7D,EAAA,OAAO,OAAA,GAAU,CAAA,GAAI,CAAA,GAAI,OAAA,GAAU,MAAM,GAAA,GAAM,OAAA;AACjD;AAKA,SAAS,aAAa,CAAA,EAAmB;AACvC,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,IAAI,IAAA,CAAK,IAAA,CAAK,KAAK,GAAA,CAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,MAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAC,CAAA,EAAG,MAAM,QAAQ,CAAA;AACnG,EAAA,OAAO,MAAM,KAAA,CAAM,QAAA;AACrB;AAwBO,SAAS,yBACd,MAAA,EACA,QAAA,EACA,GAAA,EACA,KAAA,GAA2B,EAAC,EAC+C;AAC3E,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,QAAA,EAAU,MAAM,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,QAAA,EAAU,KAAA,EAAO,GAAG,CAAA;AAC/C,EAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,QAAA,CAAS,KAAA,GAAQ,OAAO,CAAC,CAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,QAAA,CAAS,MAAA,GAAS,OAAO,CAAC,CAAA;AAChE,EAAA,MAAM,WAAW,MAAA,CAAO,UAAA,GAAa,WAAA,CAAY,QAAA,EAAU,MAAM,CAAA,GAAI,UAAA;AACrE,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,SAAS,CAAA;AAC1C,EAAA,MAAM,SAAA,GAAY,MAAM,SAAA,IAAa,CAAA;AAErC,EAAA,MAAM,MAAA,GAAqC,CAAC,KAAA,CAAM,KAAA,EAAO,KAAA,CAAM,QAAQ,GAAI,KAAA,CAAM,MAAA,IAAU,EAAG,CAAA;AAE9F,EAAA,MAAM,IAAA,GAAO,IAAI,iBAAA,CAAkB,KAAA,GAAQ,SAAS,CAAC,CAAA;AACrD,EAAA,MAAM,KAAA,GAAQ,SAAS,KAAA,GAAQ,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,GAAS,CAAA;AAEhC,EAAA,KAAA,IAAS,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,MAAA,EAAQ,MAAM,CAAA,EAAG;AACrC,IAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,GAAA,IAAO,OAAA,GAAU,KAAA;AACjC,IAAA,KAAA,IAAS,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,KAAA,EAAO,MAAM,CAAA,EAAG;AACpC,MAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,GAAA,IAAO,OAAA,GAAU,KAAA;AACjC,MAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,KAAA,GAAQ,EAAA,IAAM,CAAA;AAE9B,MAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,MAAM,KAAA,GAAQ,SAAA,CAAU,CAAA,EAAG,CAAA,EAAG,KAAA,CAAM,KAAK,CAAA,GAAI,CAAC,GAAG,CAAC,CAAA;AACnE,MAAA,MAAM,EAAA,GAAK,aAAA,CAAc,EAAA,EAAI,EAAA,EAAI,QAAA,CAAS,KAAA,EAAO,QAAA,CAAS,MAAA,EAAQ,QAAA,CAAS,YAAA,EAAc,SAAA,EAAW,GAAG,MAAM,CAAA;AAC7G,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAA,CAAK,KAAK,KAAA,IAAS,KAAA,EAAO,CAAC,CAAA,EAAG,CAAC,CAAA;AACvD,MAAA,IAAI,CAAA,IAAK,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG;AACxB,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,GAAA;AACV,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AACd,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AACd,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AACd,QAAA;AAAA,MACF;AACA,MAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,cAAc,EAAA,EAAI,EAAA,EAAI,QAAA,CAAS,KAAA,EAAO,SAAS,MAAA,EAAQ,QAAA,CAAS,YAAA,EAAc,SAAA,EAAW,GAAG,MAAM,CAAA;AAGnH,MAAA,MAAM,SAAA,GAAY,YAAA,CAAa,CAAC,CAAA,IAAK,KAAA,GAAQ,CAAA,CAAA;AAC7C,MAAA,MAAM,EAAA,GAAK,CAAC,EAAA,GAAK,SAAA;AACjB,MAAA,MAAM,EAAA,GAAK,CAAC,EAAA,GAAK,SAAA;AAEjB,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,MAAA,CAAO,EAAA,EAAI,KAAK,CAAA;AAC1B,MAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,MAAA,CAAO,IAAI,KAAK,CAAA;AAC9B,MAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AACd,MAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AAAA,IAChB;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAM;AACtC;AAEA,SAAS,gBAAA,GAA4B;AACnC,EAAA,OAAO,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,SAAS,aAAA,KAAkB,UAAA;AAC9E;AAIO,SAAS,qBACd,MAAA,EACA,QAAA,EACA,GAAA,EACA,KAAA,GAA2B,EAAC,EACX;AACjB,EAAA,IAAI,CAAC,kBAAiB,EAAG;AACvB,IAAA,MAAM,IAAI,MAAM,6DAA6D,CAAA;AAAA,EAC/E;AACA,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,KAAU,wBAAA,CAAyB,MAAA,EAAQ,QAAA,EAAU,GAAA,EAAK,KAAK,CAAA;AAC5F,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,KAAA,GAAQ,KAAA;AACf,EAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,8CAA8C,CAAA;AACxE,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,eAAA,CAAgB,KAAA,EAAO,MAAM,CAAA;AACnD,EAAA,SAAA,CAAU,IAAA,CAAK,IAAI,IAAI,CAAA;AACvB,EAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW,CAAA,EAAG,CAAC,CAAA;AAChC,EAAA,OAAO,EAAE,KAAK,MAAA,CAAO,SAAA,CAAU,WAAW,CAAA,EAAG,KAAA,EAAO,QAAQ,KAAA,EAAM;AACpE;;;AC9JA,IAAM,GAAA,GAAM,aAAA;AACZ,IAAM,SAA4C,CAAC,IAAA,CAAK,SAAS,IAAA,CAAK,OAAA,EAAS,KAAK,OAAO,CAAA;AAE3F,IAAM,OAAA,GAAU,CAAC,CAAA,KAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAGxD,SAAS,MAAM,CAAA,EAAuD;AACpE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,IAAK,GAAG,IAAK,CAAA;AACrD,EAAA,OAAO,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,EAAM,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,EAAM,CAAA,CAAE,CAAC,CAAA,GAAI,IAAI,CAAA;AAC/C;AAGO,SAAS,cAAc,CAAA,EAAmB;AAC/C,EAAA,MAAM,CAAA,GAAI,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA;AACvB,EAAA,OAAQ,CAAA,GAAI,CAAA,GAAI,CAAA,GAAK,IAAA,CAAK,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,EAAG,IAAI,GAAG,IAAI,CAAA;AACvE;AAGO,SAAS,YAAA,CAAa,CAAA,EAAW,KAAA,EAAe,GAAA,EAAa,KAAA,EAAuB;AACzF,EAAA,IAAI,CAAA,IAAK,KAAA,IAAS,KAAA,IAAS,CAAA,EAAG,OAAO,CAAA;AACrC,EAAA,OAAO,IAAA,CAAK,GAAA,CAAA,CAAM,KAAA,GAAQ,GAAA,IAAO,KAAA,GAAS,cAAc,CAAA,GAAI,KAAK,CAAA,EAAG,IAAA,CAAK,QAAQ,CAAA;AACnF;AAIO,SAAS,cAAc,KAAA,EAAuB;AACnD,EAAA,OAAO,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,CAAA,GAAI,QAAQ,KAAK,CAAA;AACxC;AAGO,SAAS,YAAA,CAAa,MAAc,MAAA,EAA0C;AACnF,EAAA,MAAM,SAAS,CAAA,GAAI,IAAA,GAAO,IAAA,KAAS,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA,CAAA;AACvD,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,GAAI,KAAA,EAAO,CAAC,CAAC,CAAA;AAC7C,EAAA,MAAM,GAAA,GAAM,CAAA,GAAI,IAAA,CAAK,OAAA,GAAU,MAAA,GAAS,IAAA;AACxC,EAAA,OAAO,KAAA,CAAM;AAAA,IACX,GAAA,GAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAK,GAAA,GAAM,MAAO,MAAA,CAAO,CAAC,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AAAA,IACtD,GAAA,GAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAK,GAAA,GAAM,MAAO,MAAA,CAAO,CAAC,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AAAA,IACtD,GAAA,GAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAK,GAAA,GAAM,MAAO,MAAA,CAAO,CAAC,CAAA,GAAI,IAAA,CAAK,EAAE;AAAA,GACvD,CAAA;AACH;AAGO,SAAS,WAAA,CAAY,cAAsB,KAAA,EAAyC;AACzF,EAAA,MAAM,KAAA,GAAS,MAAM,QAAA,CAAS,kBAAA,GAAqB,eAAgB,IAAA,CAAK,GAAA,CAAI,OAAO,CAAC,CAAA;AACpF,EAAA,MAAM,CAAA,GAAI,CAAC,MAAA,KAAmB,GAAA,GAAM,GAAA,GAAM,KAAK,GAAA,CAAK,KAAA,GAAQ,QAAA,CAAS,eAAA,GAAmB,MAAM,CAAA;AAC9F,EAAA,OAAO,MAAM,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,CAAA,CAAE,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,CAAA,CAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AACzD;AAEA,SAAS,UAAA,CAAW,KAAA,EAAe,KAAA,EAAe,CAAA,EAAmB;AACnE,EAAA,MAAM,CAAA,GAAI,OAAA,CAAA,CAAS,CAAA,GAAI,KAAA,KAAU,QAAQ,KAAA,CAAM,CAAA;AAC/C,EAAA,OAAO,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,CAAA,CAAA;AAC1B;AAQO,SAAS,WAAA,CACd,CAAA,EACA,KAAA,EACA,GAAA,EACA,OACA,MAAA,EAC0B;AAC1B,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AAGR,EAAA,MAAM,IAAI,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,GAAI,CAAA,GAAI,QAAQ,CAAC,CAAA;AAE/C,EAAA,IAAI,MAAA,CAAO,cAAc,IAAA,EAAO;AAI9B,IAAA,MAAM,IAAI,MAAA,CAAO,WAAA,GAAc,WAAW,QAAA,CAAS,gBAAA,EAAkB,GAAG,CAAC,CAAA;AACzE,IAAA,IAAI,IAAI,CAAA,EAAG;AACT,MAAA,MAAM,IAAA,GAAO,QAAQ,aAAA,CAAc,YAAA,CAAa,GAAG,KAAA,EAAO,GAAA,EAAK,KAAK,CAAC,CAAC,CAAA;AACtE,MAAA,MAAM,CAAA,GAAI,YAAA,CAAa,IAAA,EAAM,MAAA,CAAO,IAAI,CAAA;AACxC,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAClB,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAClB,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,cAAc,IAAA,EAAO;AAG9B,IAAA,MAAM,IAAI,MAAA,CAAO,WAAA,GAAc,WAAW,QAAA,CAAS,gBAAA,EAAkB,GAAG,CAAC,CAAA;AACzE,IAAA,IAAI,IAAI,CAAA,EAAG;AACT,MAAA,MAAM,CAAA,GAAI,WAAA,CAAY,CAAA,EAAG,KAAK,CAAA;AAC9B,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAClB,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAClB,MAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,IAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACjB;;;ACzFA,IAAM,QAAA,GAAW,CAAA;AAOjB,IAAMA,cAAAA,GAAgB,EAAA;AAEtB,SAASC,WAAAA,CAAW,OAAe,GAAA,EAAqB;AACtD,EAAA,IAAI,KAAA,IAAS,GAAG,OAAO,GAAA;AACvB,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAKD,cAAAA,GAAgB,KAAK,CAAA;AAC5C;AAEO,SAAS,oBAAA,CACd,MAAA,EACA,QAAA,EACA,GAAA,EAC8E;AAC9E,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,QAAA,EAAU,MAAM,CAAA;AACtC,EAAA,MAAM,OAAA,GAAUC,WAAAA,CAAW,KAAA,EAAO,GAAG,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,QAAA,CAAS,KAAA,GAAQ,OAAO,CAAC,CAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,QAAA,CAAS,MAAA,GAAS,OAAO,CAAC,CAAA;AAChE,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,QAAA,EAAU,MAAM,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,QAAA,EAAU,MAAM,CAAA;AAE1C,EAAA,MAAM,IAAA,GAAO,IAAI,iBAAA,CAAkB,KAAA,GAAQ,SAAS,CAAC,CAAA;AACrD,EAAA,MAAM,KAAA,GAAQ,SAAS,KAAA,GAAQ,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,GAAS,CAAA;AAChC,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAO,CAAA,GAAI,WAAY,GAAG,CAAA;AAE/C,EAAA,KAAA,IAAS,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,MAAA,EAAQ,MAAM,CAAA,EAAG;AACrC,IAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,GAAA,IAAO,OAAA,GAAU,KAAA;AACjC,IAAA,KAAA,IAAS,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,KAAA,EAAO,MAAM,CAAA,EAAG;AACpC,MAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,GAAA,IAAO,OAAA,GAAU,KAAA;AACjC,MAAA,MAAM,CAAA,GAAA,CAAK,EAAA,GAAK,KAAA,GAAQ,EAAA,IAAM,CAAA;AAC9B,MAAA,MAAM,EAAA,GAAK,eAAe,CAAA,EAAG,CAAA,EAAG,SAAS,KAAA,EAAO,QAAA,CAAS,MAAA,EAAQ,QAAA,CAAS,YAAY,CAAA;AACtF,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAC,CAAA;AACzB,MAAA,IAAI,KAAK,KAAA,EAAO;AAEd,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,OAAA;AACV,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,OAAA;AACd,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,OAAA;AACd,QAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AACd,QAAA;AAAA,MACF;AACA,MAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,YAAY,CAAA,EAAG,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAM,CAAA;AAC1D,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,KAAA,CAAO,CAAA,GAAI,WAAY,GAAG,CAAA;AACzC,MAAA,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,KAAK,KAAA,CAAO,CAAA,GAAI,WAAY,GAAG,CAAA;AAC7C,MAAA,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,KAAK,KAAA,CAAO,CAAA,GAAI,WAAY,GAAG,CAAA;AAC7C,MAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AAAA,IAChB;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,UAAU,QAAA,EAAS;AACnD;AAIO,SAAS,gBAAgB,MAAA,EAAkC;AAChE,EAAA,OAAO,MAAA,CAAO,WAAA,GAAc,IAAA,IAAS,MAAA,CAAO,WAAA,GAAc,IAAA;AAC5D;AAEO,SAAS,gBAAA,CACd,MAAA,EACA,QAAA,EACA,GAAA,EACa;AACb,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,QAAA,CAAS,kBAAkB,UAAA,EAAY;AACnF,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,EAAE,MAAM,KAAA,EAAO,MAAA,EAAQ,UAAS,GAAI,oBAAA,CAAqB,MAAA,EAAQ,QAAA,EAAU,GAAG,CAAA;AACpF,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,KAAA,GAAQ,KAAA;AACf,EAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,8CAA8C,CAAA;AACxE,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,eAAA,CAAgB,KAAA,EAAO,MAAM,CAAA;AAC/C,EAAA,KAAA,CAAM,IAAA,CAAK,IAAI,IAAI,CAAA;AACnB,EAAA,GAAA,CAAI,YAAA,CAAa,KAAA,EAAO,CAAA,EAAG,CAAC,CAAA;AAC5B,EAAA,OAAO,EAAE,KAAK,MAAA,CAAO,SAAA,CAAU,WAAW,CAAA,EAAG,KAAA,EAAO,QAAQ,QAAA,EAAS;AACvE;;;AC7FA,IAAM,KAAA,GAAQ,EAAA;AAEd,IAAM,KAAA,uBAAY,GAAA,EAAqB;AAEhC,SAAS,MAAA,CAAU,KAAa,KAAA,EAAmB;AACxD,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACzB,EAAA,IAAI,QAAQ,MAAA,EAAW;AAErB,IAAA,KAAA,CAAM,OAAO,GAAG,CAAA;AAChB,IAAA,KAAA,CAAM,GAAA,CAAI,KAAK,GAAG,CAAA;AAClB,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,MAAM,QAAQ,KAAA,EAAM;AACpB,EAAA,KAAA,CAAM,GAAA,CAAI,KAAK,KAAK,CAAA;AACpB,EAAA,IAAI,KAAA,CAAM,OAAO,KAAA,EAAO;AACtB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,EAAK,CAAE,IAAA,EAAK;AACjC,IAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAM,KAAA,CAAM,MAAA,CAAO,OAAO,KAAK,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,aAAA,GAAsB;AACpC,EAAA,KAAA,CAAM,KAAA,EAAM;AACd;AAEO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,KAAA,CAAM,IAAA;AACf;;;ACzBA,IAAM,KAAA,GAAQ,CAAC,CAAA,EAAW,EAAA,EAAY,EAAA,KAAgB,IAAI,EAAA,GAAK,EAAA,GAAK,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,CAAA;AAClF,IAAMC,WAAU,CAAC,CAAA,KAAc,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA;AAGrC,IAAM,YAAY,CAAC,GAAA,KAAA,CAAA,CAAkB,GAAA,GAAM,CAAA,KAAM,MAAM,CAAA,CAAA,KAAO,CAAA;AAE9D,IAAM,eAAA,GAAkB,CAAC,GAAA,KAAgBA,QAAAA,CAAQ,UAAU,GAAG,CAAA,GAAI,OAAO,WAAW,CAAA;AAGpF,IAAM,mBAAmB,MAAA,CAAO,eAAA;AAIhC,IAAM,qBAAqB,CAAC,GAAA,KAAgBA,UAAS,GAAA,GAAM,CAAA,IAAK,OAAO,WAAW,CAAA;AAElF,IAAM,eAAA,GAAkB,CAAC,GAAA,EAAaC,YAAAA,KAC3C,CAAA,GAAI,MAAA,CAAO,YAAA,GAAeA,YAAAA,IAAe,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,KAAK,CAAC,CAAA,CAAA;AAE3D,IAAM,aAAa,CAAC,GAAA,KAAgBD,UAAS,GAAA,GAAM,CAAA,IAAK,OAAO,gBAAgB,CAAA;AAE/E,IAAM,YAAY,CAAC,GAAA,KAAgB,UAAA,CAAW,GAAG,IAAI,MAAA,CAAO,sBAAA;AAE5D,IAAM,UAAA,GAAa,CAAC,MAAA,KACzB,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAQ,GAAc,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAC,CAAA;AAQjD,IAAM,WAAA,GAAc,CAACC,YAAAA,EAAqBC,QAAAA,KAAoB;AACnE,EAAA,MAAM,IAAA,GAAO,WAAWD,YAAW,CAAA;AACnC,EAAA,IAAI,IAAA,IAAQ,GAAG,OAAO,CAAA;AACtB,EAAA,OAAO,KAAA,CAAM,WAAWA,YAAAA,GAAcC,QAAO,IAAI,IAAA,EAAM,CAAA,EAAG,OAAO,cAAc,CAAA;AACjF,CAAA;AAUO,IAAM,OAAO,CAAC,SAAA,KAAsBF,QAAAA,CAAQ,SAAS,IAAI,MAAA,CAAO,SAAA;AAGhE,IAAM,aAAA,GAAgB,CAAC,SAAA,KAC5B,MAAA,CAAO,mBAAA,GACPA,SAAQ,SAAS,CAAA,IAAK,MAAA,CAAO,mBAAA,GAAsB,MAAA,CAAO,kBAAA,CAAA;AAGrD,IAAM,gBAAA,GAAmB,CAAC,GAAA,EAAa,SAAA,KAC5CA,QAAAA,CAAQ,eAAA,CAAgB,GAAG,CAAA,IAAK,CAAA,GAAIA,QAAAA,CAAQ,SAAS,CAAA,GAAI,OAAO,oBAAA,CAAqB,CAAA;AASvF,IAAM,MAAA,GAAS,CAAC,CAAA,EAAQ,CAAA,EAAQ,CAAA,KAAmB;AAAA,EACjD,CAAA,CAAE,CAAC,CAAA,GAAA,CAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA;AAAA,EACvB,CAAA,CAAE,CAAC,CAAA,GAAA,CAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA;AAAA,EACvB,CAAA,CAAE,CAAC,CAAA,GAAA,CAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,IAAK;AACzB,CAAA;AAEO,SAAS,WAAW,GAAA,EAAkD;AAC3E,EAAA,MAAM,IAAIA,QAAAA,CAAAA,CAAS,GAAA,GAAM,MAAA,CAAO,UAAA,IAAc,OAAO,OAAO,CAAA;AAC5D,EAAA,MAAM,MACJ,CAAA,GAAI,GAAA,GACA,OAAO,MAAA,CAAO,OAAA,EAAS,OAAO,UAAA,EAAY,CAAA,GAAI,CAAC,CAAA,GAC/C,OAAO,MAAA,CAAO,UAAA,EAAY,OAAO,OAAA,EAAA,CAAU,CAAA,GAAI,OAAO,CAAC,CAAA;AAC7D,EAAA,MAAM,OAAO,MAAA,CAAO,YAAA,GAAe,SAAA,CAAU,GAAG,IAAI,MAAA,CAAO,aAAA;AAC3D,EAAA,OAAO,EAAE,GAAGA,QAAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,GAAG,CAAA,EAAGA,QAAAA,CAAQ,IAAI,CAAC,CAAA,GAAI,IAAI,CAAA,EAAG,CAAA,EAAGA,SAAQ,GAAA,CAAI,CAAC,CAAA,GAAI,IAAI,CAAA,EAAE;AAC3F;AAgBO,IAAM,YAAA,GAAe,CAACE,QAAAA,KAC3B,KAAA,CAAM,KAAK,GAAA,CAAIA,QAAAA,EAAS,CAAC,CAAA,GAAI,MAAA,CAAO,cAAA,EAAgB,MAAA,CAAO,WAAA,EAAa,OAAO,WAAW,CAAA;AAOrF,IAAM,cAAc,CAACD,YAAAA,KAC1B,MAAA,CAAO,WAAA,GAAc,WAAWA,YAAW,CAAA;AAWtC,IAAM,SAAA,GAAY,CAAC,GAAA,KAAgBD,QAAAA,CAAQ,UAAU,GAAG,CAAA,GAAI,OAAO,aAAa,CAAA;AAchF,IAAM,WAAA,GAAc,CAAC,GAAA,EAAa,MAAA,KACvC,MAAA,IAAU,CAAA,GAAI,CAAA,GAAIA,QAAAA,CAAQ,eAAA,CAAgB,GAAG,CAAA,GAAI,MAAA,CAAO,qBAAqB,CAAA;AAQxE,IAAMG,YAAAA,GAAc,CAAC,GAAA,KAC1BH,QAAAA,CAAQ,WAAW,GAAG,CAAA,GAAI,OAAO,wBAAwB,CAAA;AAQpD,IAAM,WAAA,GAAc,CAAC,GAAA,KAC1B,KAAA,CAAM,eAAA,CAAgB,GAAG,CAAA,GAAI,MAAA,CAAO,qBAAA,EAAuB,CAAA,EAAG,MAAA,CAAO,cAAc,CAAA;;;AC7E9E,IAAM,eAAA,GAAkB;AAAA,EAC7B,GAAA,EAAK,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EACV,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,EACjB,KAAA,EAAO,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,EACb,SAAA,EAAW,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EAChB,WAAA,EAAa,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EAClB,UAAA,EAAY,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EACjB,OAAA,EAAS,CAAC,CAAA,EAAG,GAAG,CAAA;AAAA,EAChB,GAAA,EAAK,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EACV,QAAA,EAAU,CAAC,CAAA,EAAG,GAAG,CAAA;AAAA,EACjB,IAAA,EAAM,CAAC,CAAA,EAAG,GAAG;AACf,CAAA;AAMO,IAAM,YAAA,GAAe,EAAA;AAK5B,IAAMI,MAAAA,GAAQ,CAAC,CAAA,EAAW,EAAA,EAAY,EAAA,KAAgB,IAAI,EAAA,GAAK,EAAA,GAAK,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,CAAA;AAwE3E,IAAM,qBAAA,GAA2C;AAAA,EACtD,GAAA,EAAK,GAAA;AAAA,EACL,SAAA,EAAW,EAAA;AAAA,EACX,KAAA,EAAO,CAAA;AAAA,EACP,SAAA,EAAW,IAAA;AAAA,EACX,WAAA,EAAa,IAAA;AAAA,EACb,UAAA,EAAY,IAAA;AAAA,EACZ,OAAA,EAAS,CAAA;AAAA,EACT,GAAA,EAAK,CAAA;AAAA,EACL,QAAA,EAAU,IAAA;AAAA,EACV,IAAA,EAAM;AACR,CAAA;AAgEO,IAAM,kBAAA,GAAqB,qBAAA;AA2D3B,SAAS,eAAA,CAAgB,KAAA,GAAoC,EAAC,EAAsB;AACzF,EAAA,MAAM,CAAA,GAAI,EAAE,GAAG,kBAAA,EAAoB,GAAG,KAAA,EAAM;AAC5C,EAAA,MAAM,GAAA,GAAM,EAAE,GAAG,CAAA,EAAE;AACnB,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,eAAe,CAAA,EAA4B;AACvE,IAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,gBAAgB,GAAG,CAAA;AACpC,IAAA,GAAA,CAAI,GAAG,CAAA,GAAIA,MAAAA,CAAM,IAAI,GAAG,CAAA,EAAG,IAAI,EAAE,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,aAAA,CAAc,KAAA,GAAoC,EAAC,EAAoB;AACrF,EAAA,MAAM,CAAA,GAAI,gBAAgB,KAAK,CAAA;AAC/B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA,CAAS,CAAA,CAAE,SAAS,CAAA;AAAA,IAC1B,UAAA,EAAY,kBAAA,CAAmB,CAAA,CAAE,GAAG,CAAA;AAAA,IACpC,eAAA,EAAiB,eAAA,CAAoB,CAAA,CAAE,GAAA,EAAK,EAAE,SAAS,CAAA;AAAA,IACvD,SAAS,CAAA,CAAE,KAAA;AAAA,IACX,cAAA,EAAgB,YAAA,CAAiB,CAAA,CAAE,KAAK,CAAA;AAAA,IACxC,OAAA,EAAS,eAAA,CAAgB,CAAA,CAAE,GAAG,CAAA;AAAA,IAC9B,YAAA,EAAc,gBAAA;AAAA,IACd,QAAA,EAAU,gBAAA,CAAiB,CAAA,CAAE,GAAA,EAAK,EAAE,SAAS,CAAA;AAAA,IAC7C,aAAA,EAAe,aAAA,CAAkB,CAAA,CAAE,SAAS,CAAA;AAAA,IAC5C,UAAA,EAAY,UAAA,CAAe,CAAA,CAAE,GAAG,CAAA;AAAA,IAChC,IAAA,EAAM,UAAA,CAAW,CAAA,CAAE,GAAG,CAAA;AAAA,IACtB,YAAA,EAAc,UAAA,CAAW,CAAA,CAAE,SAAS,CAAA;AAAA,IACpC,WAAA,EAAa,WAAA,CAAgB,CAAA,CAAE,SAAA,EAAW,EAAE,KAAK,CAAA;AAAA,IACjD,aAAa,CAAA,CAAE,WAAA;AAAA,IACf,YAAY,CAAA,CAAE,UAAA;AAAA,IACd,SAAS,CAAA,CAAE,OAAA;AAAA,IACX,KAAK,CAAA,CAAE,GAAA;AAAA,IACP,UAAU,CAAA,CAAE,QAAA;AAAA,IACZ,WAAA,EAAa,YAAA;AAAA,IACb,WAAA,EAAa,WAAA,CAAgB,CAAA,CAAE,SAAS,CAAA;AAAA,IACxC,SAAA,EAAW,SAAA,CAAc,CAAA,CAAE,GAAG,CAAA;AAAA,IAC9B,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,WAAA,EAAa,WAAA,CAAgB,CAAA,CAAE,GAAA,EAAK,EAAE,IAAI,CAAA;AAAA,IAC1C,WAAA,EAAaD,YAAAA,CAAgB,CAAA,CAAE,GAAG,CAAA;AAAA,IAClC,WAAA,EAAa,WAAA,CAAgB,CAAA,CAAE,GAAG,CAAA;AAAA,IAClC,KAAK,CAAA,CAAE,GAAA;AAAA,IACP,aAAa,CAAA,CAAE,SAAA;AAAA,IACf,SAAA,EAAW,SAAA,CAAc,CAAA,CAAE,GAAG;AAAA,GAChC;AACF;AAsHO,IAAM,OAAA,GAAU;AAAA,EACrB,UAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA;AAKgD,OAAA,CAAQ,MAAA;AAAA,EACtD,CAAC,KAAK,CAAA,MAAO,EAAE,GAAG,GAAA,EAAK,CAAC,CAAC,GAAG,IAAA,EAAK,CAAA;AAAA,EACjC;AACF;;;AC/dA,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,SAAA,GAAY,CAAA;AASX,SAAS,WAAW,KAAA,EAAgC;AACzD,EAAA,MAAM,KAAA,GAAQ,4EAAA,CAA6E,IAAA,CAAK,KAAK,CAAA;AACrG,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACzB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACzB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACzB,EAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA,KAAM,SAAY,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACtD,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,CAAC,KAAK,CAAC,MAAA,CAAO,SAAS,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAC,OAAO,QAAA,CAAS,CAAC,GAAG,OAAO,IAAA;AACrG,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE;AACtB;AAEA,SAAS,IAAA,CAAK,CAAA,EAAW,CAAA,EAAW,CAAA,EAAmB;AACrD,EAAA,OAAO,MAAA,GAAS,CAAA,GAAI,MAAA,GAAS,CAAA,GAAI,MAAA,GAAS,CAAA;AAC5C;AAQO,SAAS,iBAAiB,OAAA,EAA8C;AAC7E,EAAA,MAAM,IAAI,OAAA,CAAQ,MAAA;AAClB,EAAA,IAAI,MAAM,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,KAAK,IAAA,EAAM,CAAA,EAAG,EAAA,EAAI,GAAA,EAAK,IAAI,GAAA,EAAK,CAAA,EAAG,KAAK,CAAA,EAAG,GAAA,EAAK,GAAG,GAAA,EAAI;AAEnF,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,CAAA,GAAI,EAAE,CAAA,GAAI,GAAA;AAChB,IAAA,MAAM,CAAA,GAAI,EAAE,CAAA,GAAI,GAAA;AAChB,IAAA,MAAM,CAAA,GAAI,EAAE,CAAA,GAAI,GAAA;AAChB,IAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AACxB,IAAA,EAAA,IAAM,CAAA;AACN,IAAA,EAAA,IAAM,CAAA;AACN,IAAA,EAAA,IAAM,CAAA;AAAA,EACR;AAEA,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,MAAW,CAAA,IAAK,OAAO,IAAA,IAAQ,CAAA;AAC/B,EAAA,IAAA,IAAQ,CAAA;AAER,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,IAAI,IAAI,CAAA;AAChD,EAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAK,IAAA,GAAO,CAAA,GAAK,GAAG,CAAC,CAAA;AAEjC,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAK,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAC9C,EAAA,MAAM,UAAA,GAAa,CAAC,CAAA,KAAc;AAChC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAA,GAAI,CAAA,CAAA;AACrB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACzB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA;AACxB,IAAA,OAAO,MAAA,CAAO,EAAE,CAAA,GAAA,CAAK,MAAA,CAAO,EAAE,CAAA,GAAI,MAAA,CAAO,EAAE,CAAA,KAAM,GAAA,GAAM,EAAA,CAAA;AAAA,EACzD,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA;AAAA,IACN,IAAA;AAAA,IACA,EAAA,EAAI,WAAW,GAAG,CAAA;AAAA,IAClB,EAAA,EAAI,WAAW,GAAG,CAAA;AAAA,IAClB,GAAG,EAAA,GAAK,CAAA;AAAA,IACR,GAAG,EAAA,GAAK,CAAA;AAAA,IACR,GAAG,EAAA,GAAK;AAAA,GACV;AACF;AASO,SAAS,gBAAgB,MAAA,EAA8C;AAC5E,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,CAAA,IAAK,CAAA,GAAI,CAAA,CAAA;AAC7B,IAAA,IAAI,SAAS,CAAA,EAAG;AAChB,IAAA,CAAA,IAAK,MAAM,CAAA,GAAI,KAAA;AACf,IAAA,CAAA,IAAK,MAAM,CAAA,GAAI,KAAA;AACf,IAAA,CAAA,IAAK,MAAM,CAAA,GAAI,KAAA;AACf,IAAA,CAAA,IAAK,KAAA;AACL,IAAA,IAAI,KAAK,KAAA,EAAO;AAAA,EAClB;AACA,EAAA,IAAI,CAAA,IAAK,MAAO,OAAO,IAAA;AAGvB,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAE;AAC3C;AAIA,SAAS,aAAA,CAAc,EAAA,EAAiB,CAAA,EAAW,CAAA,EAA4B;AAC7E,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,iBAAA,CAAkB,CAAA,EAAG,CAAC,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,KAAS,EAAA,IAAM,CAAC,EAAA,CAAG,QAAA,CAAS,IAAI,CAAC,CAAA;AACvE,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AACzB,IAAA,MAAM,EAAA,GAAK,UAAA,CAAW,gBAAA,CAAiB,IAAI,EAAE,eAAe,CAAA;AAG5D,IAAA,IAAI,MAAM,EAAA,CAAG,CAAA,GAAI,IAAA,EAAO,MAAA,CAAO,KAAK,EAAE,CAAA;AAAA,EACxC;AACA,EAAA,MAAM,UAAA,GAAa,gBAAgB,MAAM,CAAA;AACzC,EAAA,IAAI,YAAY,OAAO,UAAA;AACvB,EAAA,OAAO,YAAY,EAAE,CAAA;AACvB;AAeA,SAAS,YAAY,EAAA,EAAkC;AACrD,EAAA,MAAM,MAAM,EAAA,CAAG,aAAA;AACf,EAAA,KAAA,MAAW,QAAQ,CAAC,GAAA,CAAI,eAAA,EAAiB,GAAA,CAAI,IAAI,CAAA,EAAG;AAClD,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,EAAA,GAAK,UAAA,CAAW,gBAAA,CAAiB,IAAI,EAAE,eAAe,CAAA;AAC5D,IAAA,IAAI,EAAA,IAAM,EAAA,CAAG,CAAA,GAAI,IAAA,EAAO,OAAO,EAAA,CAAG,CAAA,IAAK,KAAA,GAAQ,EAAA,GAAK,eAAA,CAAgB,CAAC,EAAA,EAAI,KAAK,CAAC,CAAA;AAAA,EACjF;AACA,EAAA,OAAO,KAAA;AACT;AAGA,IAAM,KAAA,GAAkB,EAAE,CAAA,EAAG,GAAA,EAAK,GAAG,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,CAAA,EAAG,CAAA,EAAE;AAahD,SAAS,aAAA,CAAc,EAAA,EAAiB,IAAA,GAAqB,EAAC,EAAmB;AACtF,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,SAAA;AAC1B,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,SAAA;AAC1B,EAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AAItC,EAAA,IAAI,IAAA,CAAK,SAAS,CAAA,IAAK,IAAA,CAAK,UAAU,CAAA,EAAG,OAAO,gBAAA,CAAiB,EAAE,CAAA;AACnE,EAAA,MAAM,UAAsB,EAAC;AAC7B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,KAAK,CAAA,EAAG;AAChC,IAAA,MAAM,IAAI,IAAA,CAAK,GAAA,GAAA,CAAQ,CAAA,GAAI,GAAA,IAAO,OAAQ,IAAA,CAAK,MAAA;AAC/C,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,KAAK,CAAA,EAAG;AAChC,MAAA,MAAM,IAAI,IAAA,CAAK,IAAA,GAAA,CAAS,CAAA,GAAI,GAAA,IAAO,OAAQ,IAAA,CAAK,KAAA;AAChD,MAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,EAAA,EAAI,CAAA,EAAG,CAAC,CAAA;AACpC,MAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA;AAAA,IAC/B;AAAA,EACF;AACA,EAAA,OAAO,iBAAiB,OAAO,CAAA;AACjC;;;ACnLA,IAAI,qBAAA,GAAwC,IAAA;AAC5C,IAAI,wBAAA,GAA2C,IAAA;AAS/C,SAAS,aAAA,CAAc,UAAkB,KAAA,EAAwB;AAC/D,EAAA,IAAI,OAAO,GAAA,KAAQ,WAAA,IAAe,OAAO,GAAA,CAAI,QAAA,KAAa,YAAY,OAAO,KAAA;AAC7E,EAAA,OAAO,GAAA,CAAI,QAAA,CAAS,QAAA,EAAU,KAAK,CAAA;AACrC;AAGO,SAAS,sBAAA,GAAkC;AAChD,EAAA,IAAI,0BAA0B,IAAA,EAAM;AAClC,IAAA,qBAAA,GACE,cAAc,iBAAA,EAAmB,WAAW,CAAA,IAAK,aAAA,CAAc,2BAA2B,WAAW,CAAA;AAAA,EACzG;AACA,EAAA,OAAO,qBAAA;AACT;AAKO,SAAS,yBAAA,GAAqC;AACnD,EAAA,IAAI,6BAA6B,IAAA,EAAM;AACrC,IAAA,wBAAA,GAA2B,aAAA,CAAc,mBAAmB,+BAA+B,CAAA;AAAA,EAC7F;AACA,EAAA,OAAO,wBAAA;AACT;AAIO,SAAS,iBAAA,GAA0B;AACxC,EAAA,qBAAA,GAAwB,IAAA;AACxB,EAAA,wBAAA,GAA2B,IAAA;AAC7B;;;ACvCA,IAAM,IAAA,GAA0C,CAAC,MAAA,EAAQ,MAAA,EAAQ,MAAM,CAAA;AAEvE,IAAME,QAAO,CAAC,CAAA,KAAyC,EAAE,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA;AAO/F,SAAS,WAAW,OAAA,EAAsE;AAC/F,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAA,EAAG,IAAK,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAgC,CAAC,OAAA,CAAQ,CAAC,CAAA,GAAI,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,IAAA,EAAM,OAAA,CAAQ,CAAC,IAAI,IAAI,CAAA;AAC9F,EAAA,MAAM,IAAA,GAAOA,MAAK,GAAG,CAAA;AACrB,EAAA,MAAM,SAAA,GAAYA,MAAK,OAAO,CAAA;AAC9B,EAAA,OAAO,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,GAAI,QAAQ,SAAA,EAAA,CAAY,GAAA,CAAI,CAAC,CAAA,GAAI,QAAQ,SAAA,EAAA,CAAY,GAAA,CAAI,CAAC,CAAA,GAAI,QAAQ,SAAS,CAAA;AAC/F;;;ACRA,IAAM,YAAA,GAAe,cAAc,CAAC,CAAA;AACpC,IAAM,YAAA,GAAe,cAAc,CAAC,CAAA;AAE7B,SAAS,gBAAgB,MAAA,EAAkC;AAChE,EAAA,MAAM,CAAA,GAAA,CAAK,iBAAA,CAAkB,MAAM,CAAA,GAAI,iBAAiB,YAAA,GAAe,YAAA,CAAA;AACvE,EAAA,MAAM,QAAQ,MAAA,CAAO,SAAA,GAAY,CAAA,IAAK,MAAA,CAAO,YAAY,MAAA,CAAO,SAAA,CAAA;AAChE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,CAAC,GAAG,CAAC,CAAA;AACvC;AAEA,IAAM,KAAA,GAAQ,CAAC,CAAA,KAAc,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,IAAI,GAAG,CAAA;AAelE,SAAS,YAAA,CACd,QAAA,EACA,MAAA,EACA,MAAA,GAAS,CAAA,EACD;AACR,EAAA,MAAM,KAAA,GAAQ,cAAc,QAAQ,CAAA;AACpC,EAAA,MAAM,UAAU,MAAA,GAAS,CAAA,GAAI,CAAA,GAAI,MAAA,GAAS,IAAI,CAAA,GAAI,MAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,MAAM,CAAA,GAAI,OAAA;AACxC,EAAA,MAAM,OAAA,GAAU,MAAA,IAAU,MAAA,GAAS,WAAA,CAAY,MAAwB,CAAA,GAAI,IAAA;AAC3E,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,CAAA,IAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,iBAAA,EAAoB,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAEhF,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,WAAW,OAAO,CAAA;AACpC,EAAA,MAAM,QAAQ,UAAA,CAAW,IAAA;AACzB,EAAA,OACE,CAAA,IAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,WACf,KAAA,CAAM,CAAA,GAAI,KAAK,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,IAAI,KAAK,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,CAAA,GAAI,KAAK,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAE3F;;;AC9CA,IAAM;AAAA,EACJ,QAAA,EAAU,cAAA;AAAA,EACV,QAAA,EAAU,cAAA;AAAA,EACV,QAAA,EAAU,SAAA;AAAA,EACV,SAAA,EAAW,UAAA;AAAA,EACX,UAAA,EAAY,WAAA;AAAA,EACZ,QAAA,EAAU,SAAA;AAAA,EACV,YAAA,EAAc,cAAA;AAAA,EACd,UAAA,EAAY,YAAA;AAAA,EACZ,SAAA,EAAW;AACb,CAAA,GAAI,IAAA;AAEJ,IAAMD,MAAAA,GAAQ,CAAC,CAAA,EAAW,EAAA,EAAY,EAAA,KAAgB,IAAI,EAAA,GAAK,EAAA,GAAK,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,CAAA;AAClF,IAAM,MAAM,CAAC,CAAA,EAAW,GAAW,CAAA,KAAc,CAAA,GAAA,CAAK,IAAI,CAAA,IAAK,CAAA;AAE/D,SAASE,WAAAA,CAAW,KAAA,EAAe,KAAA,EAAe,CAAA,EAAmB;AACnE,EAAA,MAAM,IAAIF,MAAAA,CAAAA,CAAO,CAAA,GAAI,UAAU,KAAA,GAAQ,KAAA,CAAA,EAAQ,GAAG,CAAC,CAAA;AACnD,EAAA,OAAO,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,CAAA,CAAA;AAC1B;AAiBO,SAAS,WAAA,CAAY,MAAA,EAAyB,MAAA,EAAsB,GAAA,EAAwB;AACjG,EAAA,MAAM,SAASA,MAAAA,CAAM,MAAA,CAAO,UAAA,GAAa,CAAA,EAAG,GAAG,CAAC,CAAA;AAChD,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,cAAA,EAAgB,cAAA,EAAgB,MAAM,CAAA;AAC3D,EAAA,MAAM,YAAY,CAAA,GAAI,QAAA;AACtB,EAAA,MAAM,GAAA,GAAMA,MAAAA,CAAM,GAAA,EAAK,CAAA,EAAG,CAAC,CAAA;AAG3B,EAAA,MAAM,SAASA,MAAAA,CAAM,MAAA,CAAO,UAAA,GAAa,CAAA,EAAG,GAAG,CAAC,CAAA;AAEhD,EAAA,MAAM,IAAA,GAAOA,MAAAA,CAAM,MAAA,CAAO,IAAA,EAAM,GAAG,CAAC,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAM,CAAC,CAAA;AAIpC,EAAA,MAAM,QAAA,GAAWE,WAAAA,CAAW,cAAA,EAAgB,YAAA,EAAc,IAAI,CAAA;AAC9D,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,UAAA,EAAY,SAAA,EAAW,QAAQ,CAAA;AAChD,EAAA,MAAM,QAAA,GAAW,IAAI,IAAA,EAAM,GAAA,CAAI,YAAY,SAAA,EAAW,GAAG,GAAG,MAAM,CAAA;AAKlE,EAAA,MAAM,OAAO,IAAA,GAAO,SAAA;AACpB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,GAAO,MAAM,CAAC,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,GAAO,MAAM,CAAC,CAAA;AACrC,EAAA,MAAM,YAAA,GAAe,KAAA,GAAQ,QAAA,GAAWF,MAAAA,CAAAA,CAAO,QAAQ,QAAA,IAAY,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,SAAA,EAAW,IAAI,CAAA,EAAG,CAAA,EAAG,UAAU,CAAA,GAAI,CAAA;AACvH,EAAA,MAAM,WAAA,GAAc,KAAA,GAAQ,SAAA,GAAYA,MAAAA,CAAAA,CAAO,YAAY,KAAA,IAAS,IAAA,CAAK,GAAA,CAAI,UAAA,GAAa,KAAA,EAAO,IAAI,CAAA,EAAG,CAAA,EAAG,UAAU,CAAA,GAAI,CAAA;AACzH,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,WAAA,EAAa,YAAA,EAAc,GAAG,CAAA,GAAI,MAAA;AAGzD,EAAA,MAAM,MAAA,GAAS,IAAA,GAAO,MAAA,CAAO,UAAA,GAAa,WAAA;AAE1C,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,WAAA,EAAa,MAAM,CAAA,EAAG,UAAU,CAAA,EAAG,QAAA,EAAS;AACzF;AAoBO,SAAS,YAAA,CAAa,IAAA,EAAiB,MAAA,EAAyB,MAAA,EAAiC;AACtG,EAAA,IAAI,MAAA,CAAO,QAAA,IAAY,CAAA,EAAG,OAAO,IAAA;AACjC,EAAA,MAAM,IAAA,GAAOA,MAAAA,CAAM,MAAA,CAAO,IAAA,EAAM,GAAG,CAAC,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,QAAA,GAAW,IAAI,CAAA,GAAI,IAAA,GAAO,IAAA,CAAK,QAAA,GAAW,IAAA,GAAO,IAAA,GAAO,GAAA;AACpF,EAAA,MAAM,IAAA,GAAO,QAAQ,UAAA,GAAa,SAAA;AAClC,EAAA,MAAM,UAAA,GAAa,KAAK,GAAA,CAAI,MAAA,CAAO,UAAU,IAAA,CAAK,GAAA,CAAI,IAAA,GAAO,IAAI,CAAC,CAAA;AAClE,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,KAAK,QAAA,GAAW,IAAI,IAAI,IAAA,CAAK,OAAA;AACtD,EAAA,IAAI,OAAA,IAAW,YAAY,OAAO,IAAA;AAClC,EAAA,MAAM,MAAA,GAAS,aAAa,IAAA,CAAK,GAAA,CAAI,KAAK,GAAA,CAAI,IAAA,GAAO,IAAI,CAAA,EAAG,IAAI,CAAA;AAChE,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,KAAK,GAAA,CAAI,MAAA,EAAQ,IAAA,CAAK,cAAc,CAAC,CAAA;AAAA;AAAA;AAAA,IAGrE,QAAA,EAAU,KAAK,GAAA,CAAI,IAAA,CAAK,WAAW,IAAI,CAAA,GAAI,IAAA,GAAO,IAAA,CAAK,QAAA,GAAW;AAAA,GACpE;AACF;;;ACjGO,IAAM,gBAAA,GAA2C;AAAA,EACtD,kBAAA,EAAoB,KAAA;AAAA,EACpB,gBAAA,EAAkB,KAAA;AAAA,EAClB,YAAA,EAAc;AAChB,CAAA;AAKO,SAAS,kBAAA,CACd,MAAA,EACA,IAAA,GAA+B,gBAAA,EACd;AACjB,EAAA,IAAI,CAAC,IAAA,CAAK,kBAAA,IAAsB,CAAC,IAAA,CAAK,kBAAkB,OAAO,MAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,EAAE,GAAG,MAAA,EAAO;AACxB,EAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,IAAA,GAAA,CAAI,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,cAAc,UAAU,CAAA;AACtD,IAAA,GAAA,CAAI,cAAc,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,cAAc,UAAU,CAAA;AAAA,EACtE;AACA,EAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,IAAA,GAAA,CAAI,cAAc,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,cAAc,eAAe,CAAA;AACzE,IAAA,GAAA,CAAI,WAAW,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,QAAA,EAAU,cAAc,gBAAgB,CAAA;AACpE,IAAA,GAAA,CAAI,UAAA,GAAa,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,GAAA;AACT;AAUO,SAAS,gBAAgB,QAAA,EAA0B;AACxD,EAAA,MAAM,QAAQ,QAAA,GAAW,GAAA;AACzB,EAAA,OAAO,KAAA,GACH,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,cAAc,WAAA,EAAa,IAAA,CAAK,SAAS,CAAA,GAC7D,KAAK,GAAA,CAAI,QAAA,GAAW,aAAA,CAAc,WAAA,EAAa,KAAK,QAAQ,CAAA;AAClE;AAOO,SAAS,cAAA,CAAe,OAA+B,gBAAA,EAA2B;AACvF,EAAA,OAAO,CAAC,IAAA,CAAK,YAAA;AACf;;;ACxDA,IAAM,OAAA,GAAU;AAAA,EACd,kBAAA,EAAoB,wCAAA;AAAA,EACpB,gBAAA,EAAkB,0BAAA;AAAA,EAClB,YAAA,EAAc;AAChB,CAAA;AAEA,SAAS,QAAQ,KAAA,EAAwB;AACvC,EAAA,IAAI,OAAO,UAAA,KAAe,UAAA,EAAY,OAAO,KAAA;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,UAAA,CAAW,KAAK,CAAA,CAAE,OAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AAGN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEO,SAAS,mBAAA,GAA8C;AAC5D,EAAA,IAAI,OAAO,UAAA,KAAe,UAAA,EAAY,OAAO,gBAAA;AAC7C,EAAA,OAAO;AAAA,IACL,kBAAA,EAAoB,OAAA,CAAQ,OAAA,CAAQ,kBAAkB,CAAA;AAAA,IACtD,gBAAA,EAAkB,OAAA,CAAQ,OAAA,CAAQ,gBAAgB,CAAA;AAAA,IAClD,YAAA,EAAc,OAAA,CAAQ,OAAA,CAAQ,YAAY;AAAA,GAC5C;AACF;AAIO,SAAS,mBAAmB,QAAA,EAA8D;AAC/F,EAAA,IAAI,OAAO,UAAA,KAAe,UAAA,EAAY,OAAO,MAAM;AAAA,EAAC,CAAA;AACpD,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,mBAAA,EAAqB,CAAA;AACpD,EAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAG;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,WAAW,KAAK,CAAA;AAC7B,MAAA,IAAA,CAAK,gBAAA,CAAiB,UAAU,OAAO,CAAA;AACvC,MAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,IACjB,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,MAAM;AACX,IAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,IAAA,CAAK,mBAAA,CAAoB,UAAU,OAAO,CAAA;AAAA,EACtE,CAAA;AACF;;;ACvCO,IAAM,sBAAsB,KAAA,CAAM,OAAA;AAEzC,IAAMJ,QAAAA,GAAU,CAAC,CAAA,KAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAUjD,SAAS,eAAA,CAAgB,QAAyB,KAAA,EAAgC;AACvF,EAAA,MAAM,CAAA,GAAIA,SAAQ,KAAK,CAAA;AACvB,EAAA,IAAI,CAAA,KAAM,qBAAqB,OAAO,MAAA;AACtC,EAAA,IAAI,IAAI,mBAAA,EAAqB;AAC3B,IAAA,MAAMO,KAAI,CAAA,GAAI,mBAAA;AACd,IAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,UAAA,EAAY,MAAA,CAAO,aAAaA,EAAAA,EAAG,OAAA,EAAS,MAAA,CAAO,OAAA,GAAUA,EAAAA,EAAE;AAAA,EACrF;AACA,EAAA,MAAM,CAAA,GAAA,CAAK,CAAA,GAAI,mBAAA,KAAwB,CAAA,GAAI,mBAAA,CAAA;AAC3C,EAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,WAAA,EAAa,KAAA,CAAM,aAAA,GAAgB,CAAC,CAAA,EAAE;AACzF;;;ACrBA,IAAMP,QAAAA,GAAU,CAAC,CAAA,KAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAMjD,SAAS,WAAA,CAAY,QAAyB,CAAA,EAA4B;AAC/E,EAAA,MAAM,CAAA,GAAIA,SAAQ,CAAC,CAAA;AACnB,EAAA,IAAI,CAAA,KAAM,GAAG,OAAO,MAAA;AACpB,EAAA,OAAO;AAAA,IACL,GAAG,MAAA;AAAA,IACH,UAAA,EAAY,OAAO,UAAA,GAAa,CAAA;AAAA,IAChC,IAAA,EAAM,OAAO,IAAA,GAAO,CAAA;AAAA,IACpB,WAAA,EAAa,OAAO,WAAA,GAAc,CAAA;AAAA,IAClC,OAAA,EAAS,OAAO,OAAA,GAAU,CAAA;AAAA,IAC1B,SAAA,EAAW,OAAO,SAAA,GAAY,CAAA;AAAA;AAAA;AAAA,IAG9B,QAAA,EAAU,OAAO,QAAA,GAAW,CAAA;AAAA;AAAA;AAAA;AAAA,IAI5B,UAAA,EAAY,OAAO,UAAA,GAAa,CAAA;AAAA,IAChC,WAAA,EAAa,OAAO,WAAA,GAAc,CAAA;AAAA,IAClC,WAAA,EAAa,OAAO,WAAA,GAAc,CAAA;AAAA,IAClC,YAAA,EAAc,OAAO,YAAA,GAAe,CAAA;AAAA;AAAA;AAAA;AAAA,IAIpC,UAAA,EAAY,OAAO,UAAA,GAAa;AAAA,GAClC;AACF;;;AC/BA,IAAMA,QAAAA,GAAU,CAAC,CAAA,KAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AASjD,SAAS,UAAA,CACd,OACA,YAAA,EAC0B;AAC1B,EAAA,MAAM,CAAA,GAAI,OAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,QAAQ,MAAA,CAAO,IAAA,IAAQA,SAAQ,YAAY,CAAA;AAC3E,EAAA,OAAO,CAACA,QAAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,CAAC,GAAGA,QAAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,CAAC,CAAA,EAAGA,QAAAA,CAAQ,MAAM,CAAC,CAAA,GAAI,CAAC,CAAC,CAAA;AAC7E;AAIO,SAAS,aAAa,MAAA,EAAiC;AAC5D,EAAA,OAAOA,QAAAA,CAAQ,MAAA,CAAO,MAAA,IAAU,MAAA,CAAO,MAAM,CAAA;AAC/C;;;ACrBO,SAAS,gBAAA,CAAiB,WAAA,EAAqB,KAAA,EAAe,OAAA,GAAU,CAAA,EAAW;AACxF,EAAA,OAAO,IAAA,CAAK,IAAI,WAAA,GAAc,KAAA,EAAO,KAAK,GAAA,CAAI,OAAA,EAAS,CAAC,CAAC,CAAA;AAC3D;;;ACJA,IAAM,EAAE,YAAA,EAAc,aAAA,EAAe,aAAa,YAAA,EAAc,QAAA,EAAU,WAAU,GAAI,GAAA;AAGxF,IAAM,KAAA,GAAQ,EAAA;AAOP,SAAS,gBAAgB,KAAA,EAA0C;AACxE,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,KAAA;AACjB,EAAA,MAAM,GAAA,GAAO,KAAK,KAAA,CAAM,EAAA,EAAI,CAAC,EAAE,CAAA,GAAI,MAAO,IAAA,CAAK,EAAA;AAC/C,EAAA,OAAA,CAAQ,MAAM,GAAA,IAAO,GAAA;AACvB;AAIO,SAAS,OAAA,CAAQ,UAAkB,QAAA,EAA0B;AAClE,EAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAK,QAAA,GAAW,IAAA,CAAK,KAAM,GAAG,CAAA;AAClD,EAAA,MAAM,QAAQ,MAAA,GAAS,CAAA,GAAI,KAAK,GAAA,CAAI,MAAA,EAAQ,aAAa,CAAA,GAAI,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,SAAS,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,MAAA,EAAQ,aAAa,CAAA,GAAI,CAAA;AAC7D,EAAA,OAAO,QAAA,IAAY,QAAQ,YAAA,GAAe,IAAA,CAAA;AAC5C;AAEA,IAAMA,QAAAA,GAAU,CAAC,CAAA,KAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACxD,IAAMQ,MAAAA,GAAQ,CAAC,CAAA,KAAc,IAAA,CAAK,MAAMR,QAAAA,CAAQ,CAAC,IAAI,GAAG,CAAA;AAYjD,SAAS,cAAA,CACd,MAAA,EACA,OAAA,EACA,KAAA,EACA,SAAS,CAAA,EACD;AACR,EAAA,MAAM,OAAA,GAAUA,SAAQ,MAAM,CAAA;AAC9B,EAAA,MAAM,KAAA,GAAQ,gBAAgB,KAAK,CAAA;AACnC,EAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAI,OAAA;AACrB,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,KAAA,EAAO,KAAK,CAAA,EAAG;AAClC,IAAA,MAAM,KAAA,GAAS,IAAI,KAAA,GAAS,GAAA;AAC5B,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,KAAA,EAAO,MAAA,CAAO,QAAQ,CAAA;AAC1C,IAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,KAAM,GAAG,CAAA;AAE/C,IAAA,MAAM,MAAA,GAAS,MAAA,GAAS,CAAA,GAAI,MAAA,CAAO,cAAc,YAAA,GAAe,CAAA;AAChE,IAAA,MAAM,IAAA,GAAOA,QAAAA,CAAQ,GAAA,GAAM,MAAA,CAAO,OAAO,CAAA;AAEzC,IAAA,MAAM,IAAI,EAAA,GAAA,CAAM,CAAA,GAAI,EAAA,IAAMA,QAAAA,CAAQ,OAAO,MAAM,CAAA;AAC/C,IAAA,MAAM,CAAA,GAAI,EAAA,GAAA,CAAM,CAAA,GAAI,EAAA,IAAM,IAAA;AAC1B,IAAA,MAAM,IAAI,EAAA,GAAA,CAAM,CAAA,GAAI,EAAA,IAAMA,QAAAA,CAAQ,OAAO,MAAM,CAAA;AAI/C,IAAA,MAAM,QAAQA,QAAAA,CAAQ,SAAA,GAAY,IAAA,IAAQ,CAAA,GAAI,UAAU,CAAA,GAAI,OAAA;AAE5D,IAAA,MAAM,MAAA,GAAS,IAAA,GAAO,IAAA,GAClB,CAAA,KAAA,EAAQQ,MAAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAIA,OAAM,CAAC,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA,GAC5D,CAAA,WAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAClC,IAAA,KAAA,CAAM,IAAA,CAAK,GAAG,MAAM,CAAA,CAAA,EAAI,MAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAK,CAAA;AAAA,EAC/C;AAEA,EAAA,OAAO,CAAA,oBAAA,EAAuB,MAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,KAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AACxE;AAEO,IAAM,eAAe,GAAA,CAAI;AAWzB,SAAS,cAAA,CAAe,UAAkB,OAAA,EAAyB;AACxE,EAAA,MAAM,CAAA,GAAIA,OAAM,OAAO,CAAA;AAIvB,EAAA,OAAO,CAAA,mBAAA,EAAsB,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,YAAA,EAAe,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,SAAA,CAAA;AACpE;;;ACzFA,IAAM,MAAA,uBAAa,OAAA,EAAiB;AAG7B,IAAM,UAAA,GAAa,gBAAA;AAEnB,SAAS,aAAa,EAAA,EAAmB;AAC9C,EAAA,IAAI,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,EAAG;AACpB,EAAA,MAAM,QAAQ,EAAA,CAAG,aAAA,EAAe,OAAA,CAAQ,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,CAAA;AACzD,EAAA,IAAI,CAAC,KAAA,EAAO;AACZ,EAAA,MAAA,CAAO,IAAI,EAAE,CAAA;AAGb,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,WAAA,EAAY,IAAK,MAAM,EAAA,GAAK,CAAA,CAAA,EAAI,KAAA,CAAM,EAAE,CAAA,CAAA,GAAK,EAAA,CAAA;AACzE,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,yEAAoE,KAAK,CAAA,+JAAA;AAAA,GAG3E;AACF;ACkSO,IAAM,UAAA,GAAwC,CAAC,MAAA,EAAQ,MAAM,CAAA;;;ACtR7D,SAAS,YAAA,CAAa,OAAA,GAAyB,EAAC,EAAG;AACxD,EAAA,IAAI,OAAA,GAAU,QAAQ,OAAA,KAAY,KAAA;AAClC,EAAA,IAAI,YAAA,GAAe,OAAA,GAAU,CAAA,GAAI,aAAA,CAAc,UAAA;AAC/C,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,YAAA,GAAe,CAAA;AACnB,EAAA,IAAI,YAAA,GAAe,CAAA;AACnB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,IAAA,GAAO,KAAA;AACX,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,SAAA,GAAY,CAAA;AAGhB,EAAA,SAAS,IAAA,CAAK,CAAA,EAAW,CAAA,EAAW,SAAA,EAAyB;AAG3D,IAAA,MAAM,SAAS,IAAA,EAAK;AACpB,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,YAAA,GAAe,CAAA;AACf,IAAA,YAAA,GAAe,CAAA;AAIf,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,GAAS,CAAA;AACT,MAAA,MAAA,GAAS,CAAA;AAAA,IACX;AACA,IAAA,OAAA,GAAU,CAAA;AACV,IAAA,OAAA,GAAU,CAAA;AAGV,IAAA,IAAI,OAAA,YAAmB,IAAA,CAAK,GAAA,CAAI,UAAU,SAAA,EAAW,SAAA,GAAY,OAAO,aAAa,CAAA;AAAA,EACvF;AAEA,EAAA,SAAS,IAAA,CAAK,EAAA,EAAY,EAAA,EAAY,KAAA,EAAqB;AACzD,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,OAAA,EAAS;AACvB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAG7B,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,GAAQ,KAAA,GAAQ,KAAK,IAAA,CAAK,GAAA,GAAM,KAAK,CAAA,GAAK,GAAA,GAAM,CAAA;AACpE,IAAA,OAAA,GAAU,EAAA,GAAK,KAAA;AACf,IAAA,OAAA,GAAU,EAAA,GAAK,KAAA;AAAA,EACjB;AAGA,EAAA,SAAS,QAAQ,SAAA,EAAyB;AACxC,IAAA,IAAA,GAAO,KAAA;AACP,IAAA,OAAA,GAAU,CAAA;AACV,IAAA,OAAA,GAAU,CAAA;AACV,IAAA,IAAI,OAAA,YAAmB,IAAA,CAAK,GAAA,CAAI,UAAU,SAAA,EAAW,SAAA,GAAY,OAAO,gBAAgB,CAAA;AAAA,EAC1F;AAEA,EAAA,SAAS,UAAU,EAAA,EAAkB;AACnC,IAAA,MAAM,CAAA,GAAI,IAAA,GAAO,MAAA,CAAO,aAAA,GAAgB,MAAA,CAAO,gBAAA;AAC/C,IAAA,MAAM,CAAA,GAAI,IAAA,GAAO,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,cAAA;AAC7C,IAAA,EAAA,IAAA,CAAO,CAAA,IAAK,OAAA,GAAU,KAAA,CAAA,GAAS,CAAA,GAAI,EAAA,IAAM,EAAA;AACzC,IAAA,EAAA,IAAA,CAAO,CAAA,IAAK,OAAA,GAAU,KAAA,CAAA,GAAS,CAAA,GAAI,EAAA,IAAM,EAAA;AACzC,IAAA,KAAA,IAAS,EAAA,GAAK,EAAA;AACd,IAAA,KAAA,IAAS,EAAA,GAAK,EAAA;AAEd,IAAA,MAAM,WAAA,GAAc,OAAO,YAAA,GAAe,CAAA;AAC1C,IAAA,MAAM,GAAA,GAAM,IAAA,GAAO,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,YAAA;AAC/C,IAAA,KAAA,IAAA,CAAU,cAAc,KAAA,KAAU,CAAA,GAAI,KAAK,GAAA,CAAI,CAAC,KAAK,GAAG,CAAA,CAAA;AACxD,IAAA,MAAA,IAAA,CAAW,WAAA,GAAc,WAAW,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,EAAA,GAAK,OAAO,YAAY,CAAA,CAAA;AAG1E,IAAA,MAAM,SAAS,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,EAAA,GAAK,OAAO,WAAW,CAAA;AACpD,IAAA,MAAA,IAAA,CAAW,eAAe,MAAA,IAAU,MAAA;AACpC,IAAA,MAAA,IAAA,CAAW,eAAe,MAAA,IAAU,MAAA;AAEpC,IAAA,SAAA,IAAa,KAAK,MAAA,CAAO,kBAAA;AACzB,IAAA,OAAA,IAAW,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,GAAK,OAAO,SAAS,CAAA;AAC1C,IAAA,IAAI,OAAA,GAAU,MAAM,OAAA,GAAU,CAAA;AAAA,EAChC;AAOA,EAAA,SAAS,KAAK,EAAA,EAAkB;AAC9B,IAAA,IAAI,IAAA,GAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,EAAA,EAAI,CAAC,GAAG,IAAI,CAAA;AACzC,IAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,IAAA,OAAO,OAAO,IAAA,EAAM;AAClB,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAA;AAC9B,MAAA,SAAA,CAAU,KAAK,CAAA;AACf,MAAA,IAAA,IAAQ,KAAA;AAAA,IACV;AAKA,IAAA,IAAI,MAAK,EAAG;AACV,MAAA,KAAA,GAAQ,CAAA;AACR,MAAA,KAAA,GAAQ,CAAA;AACR,MAAA,EAAA,GAAK,CAAA;AACL,MAAA,EAAA,GAAK,CAAA;AACL,MAAA,KAAA,GAAQ,CAAA;AACR,MAAA,MAAA,GAAS,CAAA;AACT,MAAA,SAAA,GAAY,CAAA;AAAA,IACd;AAAA,EACF;AAGA,EAAA,SAAS,IAAA,GAAgB;AACvB,IAAA,OACE,CAAC,QACD,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,GAAI,IAAA,IAClB,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,GAAI,QAClB,IAAA,CAAK,KAAA,CAAM,IAAI,EAAE,CAAA,GAAI,OACrB,KAAA,GAAQ,IAAA,IACR,MAAA,GAAS,IAAA,IACT,OAAA,KAAY,CAAA;AAAA,EAEhB;AAIA,EAAA,SAAS,WAAW,EAAA,EAAmB;AACrC,IAAA,IAAI,OAAO,OAAA,EAAS;AACpB,IAAA,OAAA,GAAU,EAAA;AACV,IAAA,YAAA,GAAe,EAAA,GAAK,IAAI,aAAA,CAAc,UAAA;AACtC,IAAA,IAAI,CAAC,EAAA,EAAI;AACP,MAAA,KAAA,GAAQ,CAAA;AACR,MAAA,KAAA,GAAQ,CAAA;AACR,MAAA,EAAA,GAAK,CAAA;AACL,MAAA,EAAA,GAAK,CAAA;AACL,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,SAAA,GAAY,CAAA;AAAA,IACd;AAAA,EACF;AAEA,EAAA,SAAS,MAAA,GAAuB;AAC9B,IAAA,OAAO,EAAE,QAAQ,MAAA,EAAQ,KAAA,EAAO,OAAO,KAAA,EAAO,MAAA,EAAQ,SAAS,SAAA,EAAU;AAAA,EAC3E;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,SAAS,IAAA,EAAM,IAAA,EAAM,QAAQ,UAAA,EAAW;AAC/D;AAiBO,SAAS,eAAe,KAAA,EAAiD;AAC9E,EAAA,MAAM,IAAI,KAAA,GAAQ,CAAA,GAAI,CAAA,GAAI,KAAA,GAAQ,IAAI,CAAA,GAAI,KAAA;AAC1C,EAAA,OAAO,EAAE,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA,EAAG,KAAA,EAAO,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA,EAAE;AAChE;;;AC/LO,SAAS,eAAA,CAAgB,QAAA,EAAmB,MAAA,GAAS,KAAA,EAAwB;AAClF,EAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,EAAA,OAAO,WAAW,KAAA,GAAQ,UAAA;AAC5B;AAGO,IAAM,wBAAwB,WAAA,CAAY,QAAA;AAiB1C,SAAS,kBAAA,CAAmB,IAAA,EAAwB,MAAA,EAAgB,SAAA,EAA2B;AACpG,EAAA,MAAM,IAAA,GAAO,IAAA,KAAS,KAAA,GAAQ,MAAA,GAAS,SAAA,GAAY,MAAA;AACnD,EAAA,OAAO,IAAA,CAAK,IAAI,IAAA,CAAK,GAAA,CAAI,OAAO,qBAAA,EAAuB,CAAC,GAAG,CAAC,CAAA;AAC9D;;;ACXO,SAAS,QAAA,CAAS,OAAwB,IAAA,EAAmC;AAClF,EAAA,MAAM,SAAA,GAAY,IAAA,KAAS,KAAA,GAAQ,QAAA,GAAW,WAAA;AAC9C,EAAA,IAAI,UAAU,MAAA,EAAQ;AAEpB,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,CAAA,KAAA,EAAQ,WAAA,CAAY,UAAU,CAAA,GAAA,CAAA;AAAA,MACtC,IAAA,EAAM,EAAA;AAAA,MACN,IAAA,EAAM,CAAA,gBAAA,EAAmB,SAAS,CAAA,aAAA,EAAgB,YAAY,SAAS,CAAA,SAAA;AAAA,KACzE;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAO,mBAAmB,SAAS,CAAA,uCAAA,CAAA;AACzC,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAA,KAAA,EAAQ,WAAA,CAAY,cAAc,CAAA,GAAA,CAAA;AAAA,IAC1C,IAAA,EAAM,IAAA;AAAA,IACN,IAAA,EACE,UAAU,KAAA,GACN,CAAA,gBAAA,EAAmB,SAAS,CAAA,aAAA,EAAgB,WAAA,CAAY,QAAQ,CAAA,yBAAA,CAAA,GAChE;AAAA,GACR;AACF;AAOO,SAAS,gBAAA,CACd,QAAA,EACA,MAAA,EACA,IAAA,GAA0B,EAAC,EACT;AAClB,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,KAAA;AAC1B,EAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,EAAA,SAAS,MAAA,GAAe;AACtB,IAAA,IAAI,SAAA,EAAW;AACf,IAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,SAAS,YAAA,GAAe,QAAA,CAAS,cAAc,CAAC,CAAA;AAC3E,IAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,IAAA,EAAM,QAAA,CAAS,WAAW,SAAS,CAAA;AACvE,IAAA,MAAM,QAAA,GAAA,CAAY,IAAA,CAAK,GAAA,IAAM,IAAK,CAAA,IAAK,GAAA;AACvC,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,QAAA,EAAU,IAAA,CAAK,MAAM,CAAA;AACnD,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AAElC,IAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,iBAAA,EAAmB,KAAA,CAAM,MAAM,CAAA;AACxD,IAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,yBAAA,EAA2B,KAAA,CAAM,MAAM,CAAA;AAChE,IAAA,IAAI,MAAM,IAAA,EAAM;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,YAAA,EAAc,KAAA,CAAM,IAAI,CAAA;AACjD,MAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,oBAAA,EAAsB,KAAA,CAAM,IAAI,CAAA;AAAA,IAC3D,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,YAAY,CAAA;AACxC,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,oBAAoB,CAAA;AAAA,IAClD;AACA,IAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,kBAAA,EAAoB,KAAA,CAAM,IAAI,CAAA;AACvD,IAAA,MAAA,CAAO,MAAM,WAAA,CAAY,SAAA,EAAW,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,EACzD;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,EAAO;AAC9B,EAAA,QAAA,CAAS,iBAAiB,QAAA,EAAU,QAAA,EAAU,EAAE,OAAA,EAAS,MAAM,CAAA;AAC/D,EAAA,MAAA,EAAO;AAEP,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,QAAA,CAAS,mBAAA,CAAoB,UAAU,QAAQ,CAAA;AAC/C,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,iBAAiB,CAAA;AAC7C,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,yBAAyB,CAAA;AACrD,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,YAAY,CAAA;AACxC,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,oBAAoB,CAAA;AAChD,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,kBAAkB,CAAA;AAC9C,MAAA,MAAA,CAAO,KAAA,CAAM,eAAe,SAAS,CAAA;AAAA,IACvC;AAAA,GACF;AACF;;;AC9EO,IAAM,MAAA,GAAS,IAAA;AAKf,IAAM,MAAA,GAAS,IAAA;AAmBtB,SAAS,QAAQ,OAAA,EAIf;AACA,EAAA,MAAM,IAAI,OAAA,CAAQ,MAAA;AAClB,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,EAAA,IAAM,CAAA,CAAE,CAAA;AACR,IAAA,EAAA,IAAM,EAAE,MAAA,CAAO,IAAA;AAAA,EACjB;AACA,EAAA,EAAA,IAAM,CAAA;AACN,EAAA,EAAA,IAAM,CAAA;AACN,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,EAAA,GAAK,EAAE,CAAA,GAAI,EAAA;AACjB,IAAA,GAAA,IAAO,EAAA,GAAK,EAAA;AACZ,IAAA,GAAA,IAAO,EAAA,GAAK,EAAE,MAAA,CAAO,IAAA;AAAA,EACvB;AACA,EAAA,OAAO,EAAE,IAAI,EAAA,EAAI,KAAA,EAAO,MAAM,IAAA,GAAO,GAAA,GAAM,MAAM,CAAA,EAAE;AACrD;AAGO,SAAS,UACd,OAAA,EACuD;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAEjC,EAAA,MAAM,EAAE,EAAA,EAAI,EAAA,EAAI,KAAA,EAAM,GAAI,QAAQ,OAAO,CAAA;AACzC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AAIT,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AAGR,EAAA,IAAI,UAAA,GAAa,CAAA;AACjB,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAA,CAAE,OAAO,IAAI,CAAA;AACnC,IAAA,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,CAAA,CAAE,OAAO,EAAE,CAAA;AAC7B,IAAA,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,CAAA,CAAE,OAAO,EAAE,CAAA;AAC7B,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAA,CAAE,OAAO,IAAI,CAAA;AACnC,IAAA,CAAA,IAAK,EAAE,MAAA,CAAO,CAAA;AACd,IAAA,CAAA,IAAK,EAAE,MAAA,CAAO,CAAA;AACd,IAAA,CAAA,IAAK,EAAE,MAAA,CAAO,CAAA;AACd,IAAA,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,CAAA,CAAE,UAAU,CAAA;AAAA,EAChD;AACA,EAAA,MAAM,IAAI,OAAA,CAAQ,MAAA;AAClB,EAAA,OAAO;AAAA,IACL,OAAO,EAAE,EAAA,EAAI,EAAA,EAAI,KAAA,EAAO,MAAM,IAAA,EAAM,CAAC,IAAA,EAAM,EAAA,EAAI,IAAI,CAAA,GAAI,CAAA,EAAG,IAAI,CAAA,EAAG,CAAA,GAAI,CAAC,CAAA,EAAE;AAAA;AAAA;AAAA,IAGxE,UAAU,EAAE,QAAA,EAAU,KAAK,IAAA,GAAO,EAAA,GAAK,MAAM,UAAA;AAAW,GAC1D;AACF;AAQO,SAAS,WAAA,CAAY,MAAyB,IAAA,EAA8B;AACjF,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,MAAM,CAAA,GAAI,CAAC,GAAA,EAAa,GAAA,KACtB,IAAA,CAAK,GAAA,CAAI,GAAA,GAAM,GAAG,CAAA,GAAI,MAAA,GAAS,GAAA,GAAM,GAAA,GAAA,CAAO,MAAM,GAAA,IAAO,MAAA;AAC3D,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,IAAA,CAAK,EAAA,EAAI,KAAK,EAAE,CAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,IAAA,CAAK,KAAA,EAAO,KAAK,KAAK,CAAA;AACtC,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,IAAA,CAAK,IAAA,EAAM,KAAK,IAAI,CAAA;AACnC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA;AAGvD,EAAA,MAAM,IAAA,GACJ,KAAK,EAAA,KAAO,IAAA,CAAK,MACjB,EAAA,KAAO,IAAA,CAAK,EAAA,IACZ,KAAA,KAAU,IAAA,CAAK,KAAA,IACf,SAAS,IAAA,CAAK,IAAA,IACd,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,MAAM,CAAA,KAAM,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAA;AACzC,EAAA,OAAO,IAAA,GAAO,OAAO,EAAE,EAAA,EAAI,KAAK,EAAA,EAAI,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK;AAC5D;AAgBA,SAAS,mBAAA,CAAoB,UAAyB,QAAA,EAA2B;AAC/E,EAAA,OAAO,aAAa,CAAA,GAAI,QAAA,CAAS,QAAA,IAAY,SAAA,GAAY,SAAS,QAAA,GAAW,WAAA;AAC/E;AAwBO,SAAS,iBAAiB,IAAA,EAA6B;AAC5D,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAyB;AAC7C,EAAA,IAAI,KAAA,GAA2B,IAAA;AAC/B,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,MAAM,UAAU,MAA4B;AAC1C,IAAA,MAAM,OAAO,SAAA,CAAU,CAAC,GAAG,OAAA,CAAQ,MAAA,EAAQ,CAAC,CAAA;AAC5C,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,KAAA,GAAQ,IAAA;AAER,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,KAAA,GAAQ,WAAA,CAAY,KAAA,EAAO,IAAA,CAAK,KAAK,CAAA;AAErC,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,CAAO,EAAA,EAAI,CAAA,EAAG,CAAA,EAAG,QAAQ,UAAA,EAAY;AACnC,MAAA,OAAA,CAAQ,IAAI,EAAA,EAAI,EAAE,GAAG,CAAA,EAAG,MAAA,EAAQ,YAAY,CAAA;AAC5C,MAAA,MAAM,WAAW,OAAA,EAAQ;AACzB,MAAA,IAAI,CAAC,QAAA,EAAU;AACf,MAAA,IAAI,CAAC,mBAAA,CAAoB,QAAA,EAAU,QAAQ,CAAA,EAAG;AAC5C,QAAA,OAAA,GAAU,CAAA;AACV,QAAA;AAAA,MACF;AACA,MAAA,OAAA,IAAW,CAAA;AACX,MAAA,IAAI,UAAU,aAAA,EAAe;AAC7B,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,QAAA,GAAW,QAAA,KAAa,IAAI,CAAA,GAAI,CAAA;AAChC,MAAA,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,IACpB,CAAA;AAAA;AAAA;AAAA;AAAA,IAIA,QAAQ,EAAA,EAAI;AACV,MAAA,IAAI,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAA,EAAG,OAAA,EAAQ;AAAA,IAClC,CAAA;AAAA,IACA,OAAO,MAAM,KAAA;AAAA,IACb,UAAU,MAAM,QAAA;AAAA,IAChB,eAAe,MAAM;AAAA,GACvB;AACF;;;ACtLO,SAAS,gBAAA,CACd,OAAA,EACA,IAAA,GAA0B,EAAC,EACT;AAClB,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,EAAA,MAAM,QAAQ,gBAAA,CAAiB;AAAA,IAC7B,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,IACd,IAAA,EAAM,CAAC,IAAA,KAAS;AACd,MAAA,QAAA,GAAW,IAAA;AAEX,MAAA,KAAA,MAAW,EAAE,MAAA,EAAO,IAAK,OAAA,SAAgB,MAAA,EAAO;AAAA,IAClD;AAAA,GACD,CAAA;AAOD,EAAA,SAAS,SAAA,CAAU,MAAc,IAAA,EAAuE;AACtG,IAAA,OAAA,CAAQ,QAAQ,CAAC,EAAE,EAAA,EAAI,MAAA,IAAU,KAAA,KAAU;AACzC,MAAA,IAAI,UAAU,IAAA,EAAM;AACpB,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,MAAA,CAAO,iBAAiB,IAAI,CAAA;AAC5B,QAAA;AAAA,MACF;AACA,MAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,KAAA,GAAQ,CAAA;AACpC,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,MAAA,GAAS,CAAA;AACpC,MAAA,MAAM,KAAA,GAAS,KAAK,GAAA,CAAI,IAAA,CAAK,OAAO,IAAA,CAAK,MAAM,CAAA,GAAI,CAAA,GAAK,KAAA,CAAM,SAAA;AAC9D,MAAA,MAAM,QAAA,GAAW,KAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,EAAA,EAAI,IAAA,CAAK,QAAQ,EAAE,CAAA;AAG5D,MAAA,MAAM,OAAA,GAAU,QAAQ,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,EAAG,CAAA,GAAI,QAAA,GAAW,KAAK,CAAA,GAAI,CAAA;AAChE,MAAA,MAAA,CAAO,gBAAA,CAAiB,OAAA,IAAW,CAAA,GAAI,IAAA,GAAO,EAAE,GAAG,IAAA,EAAM,QAAA,EAAU,IAAA,CAAK,QAAA,GAAW,OAAA,EAAS,CAAA;AAAA,IAC9F,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,OAAA,GAAgB;AACvB,IAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AAChC,MAAA,KAAA,CAAM,MAAA,GAAS,CAAC,IAAA,KAAS,SAAA,CAAU,OAAO,IAAI,CAAA;AAAA,IAChD,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,MAAA,GAAe;AACtB,IAAA,IAAI,SAAA,EAAW;AACf,IAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,aAAA;AAC5B,IAAA,OAAA,CAAQ,QAAQ,CAAC,EAAE,EAAA,EAAI,UAAA,IAAc,KAAA,KAAU;AAC7C,MAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AAGtC,MAAA,IAAI,IAAA,CAAK,KAAA,IAAS,CAAA,IAAK,IAAA,CAAK,UAAU,CAAA,EAAG;AACvC,QAAA,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAA;AAC3B,QAAA;AAAA,MACF;AACA,MAAA,KAAA,CAAM,MAAA;AAAA,QACJ,OAAO,KAAK,CAAA;AAAA,QACZ,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,KAAA,GAAQ,CAAA;AAAA,QACzB,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,MAAA,GAAS,CAAA;AAAA,QACzB,MAAM,EAAE,CAAA;AAAA,QACR,UAAA,IAAc;AAAA,OAChB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAA,EAAQ;AACR,EAAA,MAAA,EAAO;AAEP,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,KAAK,MAAM,QAAA;AAAA,IACX,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA,EAAM;AAAA,IACzB,SAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,SAAA,CAAU,IAAI,IAAI,CAAA;AAClB,MAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAA,EAAG,KAAA,KAAU,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,IAC5D;AAAA,GACF;AACF;;;ACxEA,IAAM,MAAA,GAAS,4BAAA;AACf,IAAM,gBAAA,GAAmB,wBAAA;AAEzB,IAAI,aAAA,GAAgB,CAAA;AAIpB,IAAM,QAAA,uBAAe,OAAA,EAAkC;AAEvD,IAAM,wBAAwB,KAAA,CAAM,gBAAA;AAEpC,IAAM,iBAAiB,KAAA,CAAM,YAAA;AAC7B,IAAM,eAAe,KAAA,CAAM,WAAA;AAE3B,SAAS,YAAY,CAAA,EAA8B;AACjD,EAAA,OAAO,SAAA,CAAU,CAAC,CAAA,GAAI,WAAA,GAAc,cAAA;AACtC;AAEA,IAAM,UAAA,GAAa,uBAAA;AAuBnB,SAAS,QAAQ,EAAA,EAAoC;AACnD,EAAA,MAAM,IAAA,GAAO,GAAG,WAAA,EAAY;AAC5B,EAAA,OAAO,IAAA,YAAgB,UAAA,GAAa,IAAA,GAAO,EAAA,CAAG,aAAA,IAAiB,QAAA;AACjE;AAGA,SAAS,YAAY,IAAA,EAAmC;AACtD,EAAA,OAAO,IAAA,YAAgB,UAAA,GAAa,IAAA,GAAO,IAAA,CAAK,IAAA;AAClD;AAEA,SAAS,gBAAgB,IAAA,EAAmC;AAC1D,EAAA,IAAI,IAAA,CAAK,aAAA,CAAc,CAAA,MAAA,EAAS,UAAU,GAAG,CAAA,EAAG;AAChD,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,EAAA,KAAA,CAAM,YAAA,CAAa,YAAY,EAAE,CAAA;AACjC,EAAA,KAAA,CAAM,WAAA,GACJ,CAAA,CAAA,EAAI,UAAU,CAAA,yWAAA,EAGV,UAAU,CAAA,uKAAA,CAAA;AAChB,EAAA,WAAA,CAAY,IAAI,CAAA,CAAE,WAAA,CAAY,KAAK,CAAA;AACrC;AAEA,SAAS,cAAc,IAAA,EAA4C;AACjE,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,aAAA,CAA6B,CAAA,IAAA,EAAO,gBAAgB,CAAA,CAAA,CAAG,CAAA;AAC7E,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,KAAK,CAAA;AAClD,EAAA,GAAA,CAAI,YAAA,CAAa,kBAAkB,EAAE,CAAA;AACrC,EAAA,GAAA,CAAI,YAAA,CAAa,SAAS,GAAG,CAAA;AAC7B,EAAA,GAAA,CAAI,YAAA,CAAa,UAAU,GAAG,CAAA;AAC9B,EAAA,GAAA,CAAI,YAAA,CAAa,eAAe,MAAM,CAAA;AACtC,EAAA,GAAA,CAAI,MAAM,QAAA,GAAW,UAAA;AACrB,EAAA,GAAA,CAAI,MAAM,aAAA,GAAgB,MAAA;AAC1B,EAAA,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,MAAM,CAAC,CAAA;AAExD,EAAA,CAAC,gBAAgB,UAAA,GAAa,IAAA,GAAO,IAAA,CAAK,IAAA,EAAM,YAAY,GAAG,CAAA;AAC/D,EAAA,OAAO,GAAA;AACT;AAOA,SAAS,kBAAA,CACP,EAAA,EACA,MAAA,EACA,MAAA,EACA,OACA,QAAA,EACkB;AAClB,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,QAAQ,CAAA;AACxD,EAAA,MAAA,CAAO,YAAA,CAAa,MAAM,EAAE,CAAA;AAC5B,EAAA,MAAA,CAAO,YAAA,CAAa,eAAe,mBAAmB,CAAA;AACtD,EAAA,MAAA,CAAO,YAAA,CAAa,KAAK,GAAG,CAAA;AAC5B,EAAA,MAAA,CAAO,YAAA,CAAa,KAAK,GAAG,CAAA;AAC5B,EAAA,MAAA,CAAO,YAAA,CAAa,SAAS,GAAG,CAAA;AAChC,EAAA,MAAA,CAAO,YAAA,CAAa,UAAU,GAAG,CAAA;AAIjC,EAAA,MAAA,CAAO,YAAA,CAAa,+BAA+B,MAAM,CAAA;AAEzD,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,SAAS,CAAA;AAC1D,EAAA,OAAA,CAAQ,YAAA,CAAa,QAAQ,MAAM,CAAA;AACnC,EAAA,OAAA,CAAQ,YAAA,CAAa,uBAAuB,MAAM,CAAA;AAClD,EAAA,OAAA,CAAQ,YAAA,CAAa,UAAU,KAAK,CAAA;AAIpC,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,gBAAgB,CAAA;AAChE,EAAA,MAAA,CAAO,YAAA,CAAa,MAAM,eAAe,CAAA;AACzC,EAAA,MAAA,CAAO,YAAA,CAAa,gBAAgB,MAAA,CAAO,IAAA,CAAK,IAAI,MAAA,CAAO,IAAA,EAAM,CAAC,CAAC,CAAC,CAAA;AACpE,EAAA,MAAA,CAAO,YAAA,CAAa,UAAU,SAAS,CAAA;AAEvC,EAAA,MAAA,CAAO,MAAA,CAAO,SAAS,MAAM,CAAA;AAO7B,EAAA,MAAM,SAAS,MAAA,CAAO,SAAA;AACtB,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,MAAA,CAAO,GAAG,CAAA;AAC1C,IAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,KAAmB,IAAA,GAAO,CAAA,GAAI,mBAAmB,MAAA,CAAO,GAAA,GAAM,KAAK,CAAA,GAAI,IAAA,GAAO,CAAA;AAC7F,IAAA,MAAM,QAAA,GAA4C;AAAA,MAChD,CAAC,MAAM,KAAA,GAAQ,KAAA,CAAM,WAAW,QAAA,GAAW,MAAM,GAAG,4CAA4C,CAAA;AAAA,MAChG,CAAC,IAAA,EAAM,KAAA,EAAO,4CAA4C,CAAA;AAAA,MAC1D,CAAC,MAAM,KAAA,GAAQ,KAAA,CAAM,WAAW,SAAA,GAAY,MAAM,GAAG,4CAA4C;AAAA,KACnG;AACA,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,OAAA,EAAS,MAAM,KAAK,QAAA,EAAU;AAC9C,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,mBAAmB,CAAA;AACjE,MAAA,IAAA,CAAK,YAAA,CAAa,MAAM,SAAS,CAAA;AACjC,MAAA,IAAA,CAAK,YAAA,CAAa,OAAO,KAAK,CAAA;AAC9B,MAAA,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,MAAA,CAAO,OAAO,CAAC,CAAA;AAC1C,MAAA,IAAA,CAAK,YAAA,CAAa,oBAAoB,GAAG,CAAA;AACzC,MAAA,IAAA,CAAK,YAAA,CAAa,oBAAoB,GAAG,CAAA;AACzC,MAAA,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,CAAA,EAAG,IAAI,CAAA,GAAA,CAAK,CAAA;AAIxC,MAAA,IAAA,CAAK,YAAA,CAAa,wBAAwB,MAAA,CAAO,KAAA,GAAQ,IAAI,OAAA,GAAU,KAAA,GAAQ,CAAC,CAAC,CAAA;AACjF,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,eAAe,CAAA;AAC7D,MAAA,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM,CAAA,EAAG,IAAI,CAAA,GAAA,CAAK,CAAA;AACpC,MAAA,IAAA,CAAK,YAAA,CAAa,QAAQ,QAAQ,CAAA;AAClC,MAAA,IAAA,CAAK,YAAA,CAAa,UAAU,MAAM,CAAA;AAClC,MAAA,IAAA,CAAK,YAAA,CAAa,UAAU,IAAI,CAAA;AAChC,MAAA,MAAA,CAAO,MAAA,CAAO,MAAM,IAAI,CAAA;AAAA,IAC1B;AAGA,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,aAAa,CAAA;AACzD,IAAA,EAAA,CAAG,YAAA,CAAa,MAAM,IAAI,CAAA;AAC1B,IAAA,EAAA,CAAG,YAAA,CAAa,OAAO,IAAI,CAAA;AAC3B,IAAA,EAAA,CAAG,YAAA,CAAa,YAAY,YAAY,CAAA;AACxC,IAAA,EAAA,CAAG,YAAA,CAAa,MAAM,GAAG,CAAA;AACzB,IAAA,EAAA,CAAG,YAAA,CAAa,MAAM,GAAG,CAAA;AACzB,IAAA,EAAA,CAAG,YAAA,CAAa,MAAM,GAAG,CAAA;AACzB,IAAA,EAAA,CAAG,YAAA,CAAa,MAAM,GAAG,CAAA;AACzB,IAAA,EAAA,CAAG,YAAA,CAAa,UAAU,KAAK,CAAA;AAC/B,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,aAAa,CAAA;AAC1D,IAAA,GAAA,CAAI,YAAA,CAAa,MAAM,KAAK,CAAA;AAC5B,IAAA,GAAA,CAAI,YAAA,CAAa,OAAO,IAAI,CAAA;AAC5B,IAAA,GAAA,CAAI,YAAA,CAAa,YAAY,YAAY,CAAA;AACzC,IAAA,GAAA,CAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAC1B,IAAA,GAAA,CAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAC1B,IAAA,GAAA,CAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAC1B,IAAA,GAAA,CAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAC1B,IAAA,GAAA,CAAI,YAAA,CAAa,UAAU,WAAW,CAAA;AACtC,IAAA,MAAA,CAAO,MAAA,CAAO,IAAI,GAAG,CAAA;AACrB,IAAA,OAAO,YAAA,CAAa,QAAQ,QAAQ,CAAA;AAAA,EACtC;AAEA,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,mBAAmB,CAAA;AACvE,EAAA,UAAA,CAAW,YAAA,CAAa,MAAM,SAAS,CAAA;AACvC,EAAA,UAAA,CAAW,YAAA,CAAa,OAAO,KAAK,CAAA;AACpC,EAAA,UAAA,CAAW,YAAA,CAAa,OAAA,EAAS,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9C,EAAA,UAAA,CAAW,YAAA,CAAa,oBAAoB,GAAG,CAAA;AAC/C,EAAA,UAAA,CAAW,YAAA,CAAa,oBAAoB,GAAG,CAAA;AAC/C,EAAA,UAAA,CAAW,YAAA,CAAa,UAAU,WAAW,CAAA;AAC7C,EAAA,MAAA,CAAO,OAAO,UAAU,CAAA;AACxB,EAAA,OAAO,YAAA,CAAa,QAAQ,QAAQ,CAAA;AACtC;AAOA,SAAS,YAAA,CAAa,QAA0B,QAAA,EAAgD;AAC9F,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA;AACtB,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,SAAS,CAAA;AACxD,EAAA,KAAA,CAAM,YAAA,CAAa,MAAA,EAAQ,QAAA,CAAS,GAAG,CAAA;AACvC,EAAA,KAAA,CAAM,YAAA,CAAa,uBAAuB,MAAM,CAAA;AAChD,EAAA,KAAA,CAAM,YAAA,CAAa,UAAU,KAAK,CAAA;AAClC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,aAAa,CAAA;AAC9D,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,WAAW,CAAA;AACtC,EAAA,OAAA,CAAQ,YAAA,CAAa,OAAO,KAAK,CAAA;AACjC,EAAA,OAAA,CAAQ,YAAA,CAAa,YAAY,YAAY,CAAA;AAC7C,EAAA,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,MAAA,CAAO,QAAA,CAAS,QAAQ,CAAC,CAAA;AACpD,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,GAAG,CAAA;AAC9B,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,GAAG,CAAA;AAC9B,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,GAAG,CAAA;AAC9B,EAAA,MAAA,CAAO,MAAA,CAAO,OAAO,OAAO,CAAA;AAC5B,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,gBAAgB,EAAA,EAAoC;AAC3D,EAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AAGtC,EAAA,MAAM,SAAS,UAAA,CAAW,gBAAA,CAAiB,EAAE,CAAA,CAAE,mBAAmB,CAAA,IAAK,CAAA;AACvE,EAAA,OAAO,mBAAA,CAAoB,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,QAAQ,MAAM,CAAA;AAC5D;AAEA,SAAS,gBAAA,GAA2B;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,gBAAA,GAAmB,OAAO,gBAAA,GAAmB,CAAA;AAC9F;AAQA,SAAS,kBAAkB,MAAA,EAAiC;AAC1D,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAM,GAAG,CAAA;AACxC,EAAA,MAAM,QAAA,GAAW,IAAI,MAAA,CAAO,WAAA;AAC5B,EAAA,OAAO,CAAA,KAAA,EAAQ,MAAM,CAAA,aAAA,EAAgB,QAAQ,CAAA,CAAA,CAAA;AAC/C;AAEA,IAAMA,MAAAA,GAAQ,CAAC,CAAA,KAAc,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,IAAI,GAAG,CAAA;AAEzE,SAAS,MAAA,CAAO,CAAA,EAAW,CAAA,EAAW,CAAA,EAAmB;AACvD,EAAA,OAAO,CAAA,IAAA,EAAOA,MAAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,CAAC,CAAC,CAAA,CAAA,CAAA;AAChD;AAQA,SAAS,OAAA,CACP,MAAA,EACA,MAAA,EACA,GAAA,EACA,MAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,aAAa,WAAA,CAAY,MAAA,EAAQ,QAAQ,GAAG,CAAA,EAAG,QAAQ,MAAM,CAAA;AAK1E,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,CAACC,IAAGC,EAAAA,EAAGC,EAAC,IAAI,UAAA,CAAW,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,IAAI,CAAA;AACtD,IAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,aAAa,MAAM,CAAA,EAAG,KAAK,OAAO,CAAA;AAC1D,IAAA,OAAO,QAAQH,MAAAA,CAAMC,EAAC,CAAC,CAAA,EAAA,EAAKD,OAAME,EAAC,CAAC,CAAA,EAAA,EAAKF,MAAAA,CAAMG,EAAC,CAAC,CAAA,EAAA,EAAK,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAAA,EACzE;AAEA,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,YAAY,MAAM,CAAA;AACpC,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAc,IAAA,CAAK,YAAY,CAAA,GAAI,IAAA,CAAK,YAAY,MAAA,CAAO,WAAA;AACxE,EAAA,OAAO,CAAA,KAAA,EAAQH,OAAM,GAAA,CAAI,CAAC,CAAC,CAAC,CAAA,EAAA,EAAKA,MAAAA,CAAM,GAAA,CAAI,CAAC,CAAC,CAAC,CAAA,EAAA,EAAKA,MAAAA,CAAM,GAAA,CAAI,CAAC,CAAC,CAAC,KAAK,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAC9F;AAqFO,SAAS,WAAA,CAAY,EAAA,EAAiB,IAAA,GAA2B,EAAC,EAAgB;AACvF,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACnC,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACrE;AAKA,EAAA,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,EAAG,OAAA,EAAQ;AAE1B,EAAA,MAAM,EAAA,GAAK,CAAA,iBAAA,EAAqB,aAAA,IAAiB,CAAE,CAAA,CAAA;AACnD,EAAA,MAAM,eAAe,yBAAA,EAA0B;AAC/C,EAAA,IAAI,QAAA,GAAA,CAAY,IAAA,CAAK,QAAA,EAAU,GAAA,IAAO,mBAAmB,GAAA,IAAO,GAAA;AAChE,EAAA,IAAI,QAAA,GAAoC,IAAA;AACxC,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,IAAI,KAAA,GAA2B,IAAA;AAC/B,EAAA,MAAM,eAAA,GAAkB,KAAK,OAAA,KAAY,aAAA;AACzC,EAAA,IAAI,MAAA,GAAS,eAAA,GAAkB,CAAA,GAAK,IAAA,CAAK,MAAA,IAAU,CAAA;AACnD,EAAA,IAAI,SAAS,IAAA,CAAK,MAAA;AAGlB,EAAA,IAAI,OAAO,mBAAA,EAAoB;AAC/B,EAAA,MAAM,gBAAA,GAAmB,kBAAA,CAAmB,CAAC,IAAA,KAAS;AACpD,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,MAAA,GAAS,EAAA;AACT,IAAA,MAAA,CAAO,UAAA,CAAW,cAAA,CAAe,IAAA,CAAK,aAAA,IAAiB,IAAI,CAAC,CAAA;AAC5D,IAAA,KAAA,EAAM;AAAA,EACR,CAAC,CAAA;AAED,EAAA,YAAA,CAAa,EAAE,CAAA;AAGf,EAAA,MAAM,IAAA,GAAO,QAAQ,EAAE,CAAA;AACvB,EAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,EAAA,EAAA,CAAG,YAAA,CAAa,YAAY,EAAE,CAAA;AAG9B,EAAA,MAAM,iBAAA,GAAoB,gBAAA,CAAiB,EAAE,CAAA,CAAE,QAAA,KAAa,QAAA;AAC5D,EAAA,IAAI,iBAAA,EAAmB,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,YAAY,UAAU,CAAA;AAQlE,EAAA,SAAS,OAAO,KAAA,EAAqD;AACnE,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,IAAS,IAAA,CAAK,QAAQ,CAAA;AACjD,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,IAAA,CAAK,SAAS,mBAAmB,CAAA;AACtE,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ,IAAA,CAAK,iBAAiB,IAAI,CAAA;AAGrE,IAAA,OAAO,WAAA,CAAY,SAAS,MAAM,CAAA;AAAA,EACpC;AAEA,EAAA,SAAS,UAAA,GAAa;AACpB,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,IAAA,OAAO,EAAE,SAAA,EAAW,KAAA,CAAM,SAAA,EAAW,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO;AAAA,EACtG;AAEA,EAAA,SAAS,QAAA,GAAmB;AAC1B,IAAA,IAAI,CAAC,OAAO,OAAO,GAAA;AACnB,IAAA,MAAM,OAAO,CAAC,CAAA,KACZ,IAAI,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,CAAA,EAAI,CAAA,CAAE,OAAO,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,CAAA,EAAI,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,YAAY,CAAA,CAAA,GAAK,GAAA;AAC7E,IAAA,OAAO,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA,CAAA;AAAA,EACtE;AAEA,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,IAAI,SAAA,EAAW;AACf,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AACpD,IAAA,MAAM,YAAY,MAAA,EAAO;AACzB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,IAAU,aAAA,CAAc,EAAE,CAAA;AAE9C,IAAA,IAAI,YAAA,EAAc;AAIhB,MAAA,MAAM,GAAA,GAAM,CAAA,CAAA,EAAI,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,EAAK,QAAA,EAAU,CAAA,CAAA,EAAI,QAAA,CAAS,KAAK,CAAA,CAAA,EAAI,SAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,YAAY,CAAA,CAAA,EAAI,gBAAA,EAAkB,CAAA,CAAA,EAAI,UAAU,UAAU,CAAA,CAAA,EAAI,SAAA,CAAU,eAAe,CAAA,CAAA,EAAI,SAAA,CAAU,OAAO,CAAA,CAAA,EAAI,UAAU,IAAI,CAAA,CAAA;AAChO,MAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,CAAC,QAAA,EAAU;AAE/B,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA,EAAI,MAAM,oBAAA,CAAqB,SAAA,EAAW,QAAA,EAAU,gBAAA,EAAiB,EAAG,UAAA,EAAY,CAAC,CAAA;AAChH,QAAA,MAAM,IAAA,GAAO,aAAA,CAAc,IAAI,CAAA,CAAE,cAAc,MAAM,CAAA;AACrD,QAAA,MAAM,GAAA,GAAM,eAAA,CAAgB,SAAS,CAAA,GACjC,OAAO,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA,EAAI,MAAM,iBAAiB,SAAA,EAAW,QAAA,EAAU,gBAAA,EAAkB,CAAC,CAAA,GAClF,IAAA;AACJ,QAAA,MAAM,IAAA,GAAO,mBAAmB,EAAA,EAAI,GAAA,CAAI,KAAK,SAAA,EAAW,GAAA,CAAI,OAAO,GAAG,CAAA;AACtE,QAAA,IAAI,QAAA,EAAU,UAAA,EAAY,IAAA,CAAK,YAAA,CAAa,MAAM,QAAQ,CAAA;AAAA,aACrD,IAAA,CAAK,YAAY,IAAI,CAAA;AAC1B,QAAA,QAAA,GAAW,IAAA;AACX,QAAA,MAAA,GAAS,GAAA;AAAA,MACX;AACA,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,iBAAA,EAAmB,CAAA,KAAA,EAAQ,EAAE,CAAA,CAAA,CAAG,CAAA;AACrD,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,yBAAA,EAA2B,CAAA,KAAA,EAAQ,EAAE,CAAA,CAAA,CAAG,CAAA;AAAA,IAC/D,CAAA,MAAO;AACL,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,iBAAA,EAAmB,iBAAA,CAAkB,SAAS,CAAC,CAAA;AACpE,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,yBAAA,EAA2B,iBAAA,CAAkB,SAAS,CAAC,CAAA;AAC5E,MAAA,EAAA,CAAG,KAAA,CAAM,kBAAkB,OAAA,CAAQ,SAAA,EAAW,QAAQ,QAAA,GAAW,CAAA,GAAI,GAAG,MAAM,CAAA;AAAA,IAChF;AAEA,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,MAAA,EAAQ,QAAQ,CAAA;AAC/C,IAAA,QAAA,GAAW,KAAA;AACX,IAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAI,YAAY,MAAM,CAAA;AACvC,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,iBAAA,EAAmB,KAAA,GAAQ,MAAM,GAAG,CAAA;AACzD,IAAA,EAAA,CAAG,KAAA,CAAM,YAAY,kBAAA,EAAoB,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA;AAC5D,IAAA,EAAA,CAAG,MAAM,WAAA,CAAY,0BAAA,EAA4B,MAAA,CAAO,SAAA,CAAU,WAAW,CAAC,CAAA;AAK9E,IAAA,MAAM,WAAW,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,GAAQ,SAAA,GAAY,YAAY,GAAG,CAAA;AAChE,IAAA,EAAA,CAAG,KAAA,CAAM,YAAY,uBAAA,EAAyB,CAAA,IAAA,EAAO,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,CAAG,CAAA;AACxF,IAAA,EAAA,CAAG,MAAM,WAAA,CAAY,wBAAA,EAA0B,OAAO,EAAA,EAAI,EAAA,EAAI,EAAE,CAAC,CAAA;AACjE,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,wBAAA,EAA0B,OAAA,CAAQ,SAAA,EAAW,QAAQ,KAAA,GAAQ,CAAA,GAAI,CAAA,EAAG,MAAM,CAAC,CAAA;AAQhG,IAAA,MAAM,IAAA,GAAO,YAAA,CAAa,WAAA,CAAY,SAAA,EAAW,MAAA,EAAQ,KAAA,GAAQ,CAAA,GAAI,CAAC,CAAA,EAAG,SAAA,EAAW,MAAM,CAAA,CAAE,QAAA;AAC5F,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA;AAAA,MACP,iBAAA;AAAA,MAAA,CACC,IAAA,CAAK,iBAAiB,IAAA,EAAM,gBAAA,GACzB,eAAe,IAAA,EAAM,eAAA,CAAgB,IAAI,CAAC,CAAA,GAC1C,eAAe,SAAA,EAAW,CAAC,IAAI,EAAA,EAAI,EAAE,GAAG,IAAA,CAAK,KAAA,IAAS,YAAY,MAAM;AAAA,KAC9E;AACA,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,uBAAA,EAAyB,CAAA,EAAG,YAAY,CAAA,EAAA,CAAI,CAAA;AAIjE,IAAA,EAAA,CAAG,MAAM,WAAA,CAAY,oBAAA,EAAsB,CAAA,EAAG,QAAA,CAAS,YAAY,CAAA,EAAA,CAAI,CAAA;AACvE,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,wBAAA,EAA0B,CAAA,EAAG,gBAAA,CAAiB,QAAA,CAAS,YAAA,EAAc,QAAA,CAAS,YAAA,EAAc,CAAC,CAAC,CAAA,EAAA,CAAI,CAAA;AAEvH,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,QAAA,EAAU,MAAA,EAAQ,MAAM,CAAA;AACpD,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,oBAAA,EAAsB,MAAM,CAAA;AACjD,IAAA,IAAI,KAAK,MAAA,KAAW,KAAA,KAAU,KAAA,CAAM,WAAA,CAAY,cAAc,MAAM,CAAA;AAAA,EACtE;AAEA,EAAA,KAAA,EAAM;AAKN,EAAA,MAAM,MAAA,GAAS,aAAa,EAAE,OAAA,EAAS,eAAe,IAAA,CAAK,aAAA,IAAiB,IAAI,CAAA,EAAG,CAAA;AACnF,EAAA,IAAI,KAAA,GAAuB,IAAA;AAC3B,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,WAAA,GAAc,KAAA;AAElB,EAAA,SAAS,WAAW,CAAA,EAAmC;AACrD,IAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,IAAA,OAAO,CAAC,CAAA,CAAE,OAAA,GAAU,IAAA,CAAK,OAAO,IAAA,CAAK,KAAA,GAAQ,CAAA,EAAG,CAAA,CAAE,OAAA,GAAU,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EACxF;AAEA,EAAA,SAAS,iBAAiB,SAAA,EAA+B;AACvD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AACpD,IAAA,MAAM,OAAO,MAAA,EAAO;AAEpB,IAAA,MAAM,IAAA,GAAO,cAAA,CAAe,SAAA,CAAU,KAAK,CAAA;AAG3C,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,EAAE,GAAG,KAAK,QAAA,EAAU,SAAA,EAAA,CAAY,IAAA,CAAK,QAAA,EAAU,SAAA,IAAa,kBAAA,CAAmB,SAAA,IAAa,IAAA,CAAK,OAAO,CAAA;AAK7H,IAAA,MAAM,MAAM,oBAAA,CAAqB,KAAA,EAAO,UAAU,WAAA,GAAc,CAAA,GAAI,kBAAiB,EAAG;AAAA,MACtF,GAAG,UAAA,EAAW;AAAA,MACd,KAAA,EAAO;AAAA,QACL,GAAG,SAAA,CAAU,MAAA;AAAA,QACb,GAAG,SAAA,CAAU,MAAA;AAAA,QACb,OAAO,SAAA,CAAU,KAAA;AAAA,QACjB,OAAO,SAAA,CAAU,KAAA;AAAA,QACjB,OAAO,SAAA,CAAU,KAAA;AAAA,QACjB,MAAA,EAAQ,SAAA,CAAU,QAAQ,CAAA,GAAI,qBAAA;AAAA,QAC9B,SAAS,SAAA,CAAU,OAAA;AAAA,QACnB,WAAW,SAAA,CAAU;AAAA;AACvB,KACD,CAAA;AACD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,SAAS,CAAA;AAChD,MAAA,OAAA,EAAS,YAAA,CAAa,MAAA,EAAQ,GAAA,CAAI,GAAG,CAAA;AAIrC,MAAA,KAAA,MAAW,IAAA,IAAQ,QAAA,CAAS,gBAAA,CAAiB,mBAAmB,CAAA,EAAG;AACjE,QAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,YAAA,CAAa,sBAAsB,KAAK,CAAC,CAAA;AACnE,QAAA,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,MAAA,CAAO,GAAA,CAAI,KAAA,IAAS,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAA,CAAE,CAAC,CAAA;AAAA,MACrF;AAAA,IACF;AACA,IAAA,MAAA,GAAS,EAAA;AAET,IAAA,SAAA,CAAU,SAAA,CAAU,QAAQ,SAAA,CAAU,MAAA,EAAQ,UAAU,MAAA,GAAS,IAAA,CAAK,WAAW,QAAQ,CAAA;AAIzF,IAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,OAAO,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,KAAA,GAAQ,IAAI,SAAA,CAAU,MAAA;AAAA,MAC9C,OAAO,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,MAAA,GAAS,IAAI,SAAA,CAAU,MAAA;AAAA,MAC9C,UAAU,SAAA,CAAU;AAAA,KACrB,CAAA;AAAA,EACH;AAUA,EAAA,SAAS,SAAA,CAAU,CAAA,EAAW,CAAA,EAAW,QAAA,EAAkB,QAAA,EAAmC;AAC5F,IAAA,IAAI,YAAY,IAAA,EAAO;AACrB,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,0BAAA,EAA4B,GAAG,CAAA;AACpD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAI,YAAY,IAAA,CAAK,MAAA,IAAU,aAAA,CAAc,EAAE,CAAC,CAAA;AACjE,IAAA,MAAM,MAAO,CAAA,GAAI,QAAA,CAAS,KAAA,GAAQ,CAAA,IAAK,SAAS,KAAA,GAAS,GAAA;AACzD,IAAA,MAAM,MAAO,CAAA,GAAI,QAAA,CAAS,MAAA,GAAS,CAAA,IAAK,SAAS,MAAA,GAAU,GAAA;AAC3D,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,QAAQ,CAAA,GAAI,qBAAA;AACpC,IAAA,EAAA,CAAG,KAAA,CAAM,WAAA;AAAA,MACP,kBAAA;AAAA,MACA,0BAA0B,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,SAAS,EAAA,CAAG,OAAA,CAAQ,CAAC,CAAC,KAAK,EAAA,CAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAWA,OAAM,EAAE,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,EAAE,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,EAAE,CAAC,CAAA,aAAA,EAAgBA,MAAAA,CAAM,EAAE,CAAC,IAAIA,MAAAA,CAAM,EAAE,CAAC,CAAA,CAAA,EAAIA,MAAAA,CAAM,EAAE,CAAC,CAAA,SAAA;AAAA,KACrL;AACA,IAAA,EAAA,CAAG,MAAM,WAAA,CAAY,0BAAA,EAA4B,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,EACtE;AAEA,EAAA,SAAS,KAAK,GAAA,EAAmB;AAC/B,IAAA,IAAI,SAAA,EAAW;AACf,IAAA,MAAM,EAAA,GAAK,WAAA,GAAA,CAAe,GAAA,GAAM,WAAA,IAAe,MAAO,CAAA,GAAI,EAAA;AAC1D,IAAA,WAAA,GAAc,GAAA;AACd,IAAA,MAAA,CAAO,KAAK,EAAE,CAAA;AACd,IAAA,MAAM,CAAA,GAAI,OAAO,MAAA,EAAO;AAIxB,IAAA,IAAI,eAAA,WAA0B,CAAA,CAAE,MAAA;AAChC,IAAA,gBAAA,CAAiB,CAAC,CAAA;AAClB,IAAA,IAAI,MAAA,CAAO,MAAK,EAAG;AACjB,MAAA,WAAA,GAAc,KAAA;AACd,MAAA,KAAA,GAAQ,IAAA;AACR,MAAA,WAAA,GAAc,CAAA;AAEd,MAAA,EAAA,CAAG,KAAA,CAAM,WAAA,CAAY,0BAAA,EAA4B,GAAG,CAAA;AACpD,MAAA,IAAA,CAAK,SAAS,IAAI,CAAA;AAClB,MAAA,KAAA,EAAM;AACN,MAAA;AAAA,IACF;AACA,IAAA,KAAA,GAAQ,sBAAsB,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,SAAS,GAAA,GAAY;AACnB,IAAA,IAAI,UAAU,IAAA,IAAQ,CAAC,SAAA,EAAW,KAAA,GAAQ,sBAAsB,IAAI,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,CAAA;AAEZ,EAAA,SAAS,OAAO,CAAA,EAAuB;AACrC,IAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,WAAW,CAAC,CAAA;AAC3B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AACpD,IAAA,WAAA,GAAc,IAAA;AACd,IAAA,KAAA,GAAQ,CAAA;AACR,IAAA,KAAA,GAAQ,CAAA;AAGR,IAAA,EAAA,CAAG,iBAAA,GAAoB,EAAE,SAAS,CAAA;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,CAAA,EAAG,WAAA,CAAY,QAAQ,CAAC,CAAA;AACvC,IAAA,GAAA,EAAI;AAAA,EACN;AACA,EAAA,SAAS,OAAO,CAAA,EAAuB;AACrC,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,WAAW,CAAC,CAAA;AAC3B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AAEpD,IAAA,MAAA,CAAO,IAAA,CAAK,IAAI,KAAA,EAAO,CAAA,GAAI,OAAO,SAAA,CAAU,QAAQ,IAAI,WAAW,CAAA;AACnE,IAAA,GAAA,EAAI;AAAA,EACN;AACA,EAAA,SAAS,KAAK,CAAA,EAAwB;AACpC,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AACpD,IAAA,IAAI,CAAA,EAAG,EAAA,CAAG,qBAAA,GAAwB,CAAA,CAAE,SAAS,CAAA;AAG7C,IAAA,MAAA,CAAO,OAAA,CAAQ,WAAA,CAAY,QAAQ,CAAA,GAAI,YAAY,CAAA;AACnD,IAAA,GAAA,EAAI;AAAA,EACN;AAEA,EAAA,IAAI,IAAA,CAAK,gBAAgB,KAAA,EAAO;AAC9B,IAAA,EAAA,CAAG,gBAAA,CAAiB,eAAe,MAAM,CAAA;AACzC,IAAA,EAAA,CAAG,gBAAA,CAAiB,eAAe,MAAM,CAAA;AACzC,IAAA,EAAA,CAAG,gBAAA,CAAiB,aAAa,IAAI,CAAA;AACrC,IAAA,EAAA,CAAG,gBAAA,CAAiB,iBAAiB,IAAI,CAAA;AACzC,IAAA,EAAA,CAAG,gBAAA,CAAiB,gBAAgB,IAAI,CAAA;AAAA,EAC1C;AAKA,EAAA,IAAI,cAAA,GAAwC,IAAA;AAC5C,EAAA,IAAI,CAAC,IAAA,CAAK,QAAA,IAAY,OAAO,mBAAmB,WAAA,EAAa;AAC3D,IAAA,cAAA,GAAiB,IAAI,cAAA,CAAe,MAAM,KAAA,EAAO,CAAA;AACjD,IAAA,cAAA,CAAe,QAAQ,EAAE,CAAA;AAAA,EAC3B;AAEA,EAAA,SAAS,OAAA,GAAgB;AACvB,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA,gBAAA,EAAiB;AACjB,IAAA,IAAI,SAAS,GAAA,CAAI,EAAE,MAAM,MAAA,EAAQ,QAAA,CAAS,OAAO,EAAE,CAAA;AACnD,IAAA,IAAI,KAAA,KAAU,IAAA,EAAM,oBAAA,CAAqB,KAAK,CAAA;AAC9C,IAAA,KAAA,GAAQ,IAAA;AACR,IAAA,EAAA,CAAG,mBAAA,CAAoB,eAAe,MAAM,CAAA;AAC5C,IAAA,EAAA,CAAG,mBAAA,CAAoB,eAAe,MAAM,CAAA;AAC5C,IAAA,EAAA,CAAG,mBAAA,CAAoB,aAAa,IAAI,CAAA;AACxC,IAAA,EAAA,CAAG,mBAAA,CAAoB,iBAAiB,IAAI,CAAA;AAC5C,IAAA,EAAA,CAAG,mBAAA,CAAoB,gBAAgB,IAAI,CAAA;AAC3C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,kBAAkB,CAAA;AAC1C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,0BAA0B,CAAA;AAClD,IAAA,cAAA,EAAgB,UAAA,EAAW;AAC3B,IAAA,cAAA,GAAiB,IAAA;AACjB,IAAA,IAAI,QAAA,EAAU,UAAA,EAAY,QAAA,CAAS,UAAA,CAAW,YAAY,QAAQ,CAAA;AAClE,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,MAAA,GAAS,EAAA;AACT,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,iBAAiB,CAAA;AACzC,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,yBAAyB,CAAA;AACjD,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,kBAAkB,CAAA;AAC1C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,iBAAiB,CAAA;AACzC,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,kBAAkB,CAAA;AAC1C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,0BAA0B,CAAA;AAClD,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,uBAAuB,CAAA;AAC/C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,wBAAwB,CAAA;AAChD,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,wBAAwB,CAAA;AAChD,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,iBAAiB,CAAA;AACzC,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,uBAAuB,CAAA;AAC/C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,oBAAoB,CAAA;AAC5C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,oBAAoB,CAAA;AAC5C,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,wBAAwB,CAAA;AAChD,IAAA,EAAA,CAAG,KAAA,CAAM,eAAe,YAAY,CAAA;AACpC,IAAA,EAAA,CAAG,gBAAgB,UAAU,CAAA;AAC7B,IAAA,IAAI,iBAAA,EAAmB,EAAA,CAAG,KAAA,CAAM,cAAA,CAAe,UAAU,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,MAAA,GAAsB;AAAA,IAC1B,MAAA,EAAQ,KAAA;AAAA,IACR,UAAU,CAAA,EAAG;AACX,MAAA,MAAM,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACrC,MAAA,IAAI,SAAS,MAAA,EAAQ;AACrB,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,KAAA,EAAM;AAAA,IACR,CAAA;AAAA,IACA,UAAU,IAAA,EAAM;AACd,MAAA,MAAA,GAAS,IAAA,IAAQ,MAAA;AACjB,MAAA,KAAA,EAAM;AAAA,IACR,CAAA;AAAA,IACA,iBAAiB,IAAA,EAAM;AACrB,MAAA,IAAI,aAAa,WAAA,EAAa;AAC9B,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,eAAA,CAAgB,EAAE,CAAA;AACpD,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,SAAA,CAAU,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,QAAQ,CAAA;AAC3B,QAAA;AAAA,MACF;AACA,MAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,MAAA,SAAA;AAAA,QACE,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,IAAA,GAAO,KAAK,KAAA,GAAQ,CAAA,CAAA;AAAA,QACvC,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,GAAA,GAAM,KAAK,MAAA,GAAS,CAAA,CAAA;AAAA,QACvC,IAAA,CAAK,QAAA;AAAA,QACL;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,SAAS,IAAA,EAAM;AACb,MAAA,KAAA,GAAQ,IAAA,IAAQ,IAAA,CAAK,SAAA,GAAY,CAAA,GAAI,IAAA,GAAO,IAAA;AAC5C,MAAA,MAAA,GAAS,EAAA;AACT,MAAA,KAAA,EAAM;AAAA,IACR,CAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,QAAA,CAAS,GAAA,CAAI,IAAI,MAAM,CAAA;AACvB,EAAA,OAAO,MAAA;AACT","file":"dom.cjs","sourcesContent":["\n/**\n * Automatic content polarity above the glass.\n *\n * The glass adjusts its own body to the backdrop — but that has a limit. When the backdrop is\n * light AND the ink over it is light, no amount of body density can separate them by contrast\n * anymore: the body hits its own ceiling, and the letters drown. Past that point the decision is\n * no longer the glass's to make but the app's — it recolors the ink to the opposite side, and all\n * of the glass's own automation reflows behind it, because it depends on that same polarity.\n *\n * The app has nowhere to get the lightness of the backdrop UNDER the glass from — only the native\n * capture can see it. That's where it comes from: the `onBackdropSample` event (a probe in\n * `GlassBackdropView`).\n *\n * The decision is made BY LIGHTNESS with hysteresis: computing body density here with the\n * shader's formula would mean keeping a second implementation of the model that silently drifts\n * from the first. Whether the body and the ink actually separate by contrast is checked by\n * `check:optics` — against a real render, not a copy of the formula.\n */\n\nexport type BackdropSample = {\n /** Average lightness of the backdrop under the glass, 0..1, on the same (sRGB-encoded) scale\n * as the screen. */\n luma: number;\n /** Variegation: twice the mean deviation of lightness, 0 on a flat fill, 1 at the limit.\n * Exactly the same quantity the probe computes on the web — otherwise the platforms would\n * drift apart silently. */\n busy: number;\n /** The darkest and lightest spots under the glass. The legibility decision is made from these,\n * not the average: right over a black/white border the average reads as \"everything's fine\". */\n lo: number;\n hi: number;\n r: number;\n g: number;\n b: number;\n};\n\n/** Quantization step for the ambient color — for platforms where the measurement flows through\n * state: every probe sample would otherwise trigger a surface repaint. The shadow is tinted\n * coarsely, it doesn't need precision either. The web draws uniforms imperatively every frame\n * and takes the color as is. */\nconst AMBIENT_STEP = 32;\n\n/** The element's ambient color from a probe sample — the one that bleeds into its shadow\n * (docs/reference.md §7). */\nexport function ambientFrom(sample: { r: number; g: number; b: number }): [number, number, number] {\n const step = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * AMBIENT_STEP) / AMBIENT_STEP;\n return [step(sample.r), step(sample.g), step(sample.b)];\n}\n\n/** Ink lightness at the ends of the scale. The kit keeps light text nearly white and dark text\n * nearly black; there's no in-between polarity state by construction. */\nexport const INK_LIGHT = 0.95;\nexport const INK_DARK = 0.08;\n\n/**\n * Ink polarity from a backdrop sample — ONE place for every platform. A small element and its\n * glyphs switch between light and dark so that contrast is maximized (docs/reference.md §3): over\n * a yellow flower the reference already has black glyphs on light glass. Holding a light ink with\n * body density over a light backdrop just turns the element into a painted plaque.\n *\n * The decision is by lightness with a bias toward the light side — not by average (a white screen\n * with a dark stripe would otherwise never flip) and not by maximum (one light cover peeking under\n * the edge would recolor the whole panel). Hysteresis lives inside; the caller decides how many\n * confirmations it takes.\n */\nexport function shouldInkBeLight(sample: { luma: number; hi?: number }, wasLight: boolean): boolean {\n return decisiveLuma(sample) < (wasLight ? FLIP_LUMA : RETURN_LUMA);\n}\n\nexport const decisiveLuma = (sample: { luma: number; hi?: number }) =>\n sample.luma * 0.75 + (sample.hi ?? sample.luma) * 0.25;\n\n/** Lighter than this, a light ink flips to dark. */\nexport const FLIP_LUMA = 0.62;\n/** The way back triggers noticeably earlier than the way forward: without the gap the ink would\n * flicker on every light cover sliding under the glass edge. */\nexport const RETURN_LUMA = 0.5;\n/** How many consecutive samples have to demand a change. The probe samples ~5 times a second, so\n * three samples is roughly half a second of a stable backdrop, not a random cover flashing by\n * under the edge. */\nexport const CONFIRMATIONS = 3;\n/** Duration of the recolor. Slow enough not to read as an event, fast enough that the illegible\n * in-between state doesn't linger noticeably. */\nexport const FADE_MS = 420;\n","/**\n * THE LAW: every calibrated number the material obeys, in one place.\n *\n * A value here is written ONCE and read by everything that needs it — the shader text interpolates\n * it, the JS twins import it. The alternative is what this file replaces: the same number typed\n * into a GLSL string and again into a TypeScript function, drifting apart the first time one side\n * is tuned. `VG_FALLOFF` already worked this way; the rest now does too.\n *\n * Each entry carries where it came from. `§N` is a section of `docs/reference.md`, which is itself\n * drawn from Apple's public sessions; `M 2:32` and the like are the timestamps those sections cite.\n * A number with no provenance is marked as such, and that marking is a debt, not a decoration.\n *\n * Structural constants — 0, 1, 0.5, 2, π — are not laws and do not belong here.\n */\n\n/** Rim optics: the silhouette's light (§2). */\nexport const RIM = {\n /**\n * The key-light lobe's exponent. Two opposing arcs come out of one expression, which is why\n * they are opposed rather than placed: `pow(max(facing, 0), n) + 0.45 * pow(max(-facing, 0), n)`.\n *\n * MEASURED off two close-ups of real end caps, frames/crops/cap158-left and cap158-right. The\n * bright arc's full width at half its peak is 53 degrees in the first and 30 in the second; this\n * exponent's own width is `2·acos(0.5^(1/n))`, so they imply 6 and 20. It was 3, whose arc is 75\n * degrees wide — broader than either measurement, and the error is in the same direction in both.\n *\n * 6 is the conservative end: it reproduces the wider crop exactly, and a broader arc is the more\n * forgiving error. One exponent cannot serve both, and that is not noise — a specular lobe's\n * width depends on the light's angular size as well as the surface, and those are two different\n * scenes. The model has no term for the light's size.\n */\n lobeExponent: 6,\n /** The far arc, weaker than the one facing the light (§2). */\n opposingArc: 0.45,\n /**\n * The dark edge along the whole silhouette, as a multiplicative darkening. iOS 27 made it a\n * layer of its own, and it does not rule out the highlight sitting on top of it (§2).\n */\n darkEdge: 0.22,\n /** Width of the hairline, CSS px. \"About a point, not a band and not a bevel\" (§2). */\n widthPx: 1,\n} as const;\n\n/** How the medium stands between the backdrop and the eye (§3). */\nexport const BODY = {\n /** Lightness ceiling for the body when legibility is loose. */\n capLoose: 0.62,\n /** …and when it is strict. The model is calibrated at these two, not in between (E-43). */\n capTight: 0.38,\n /** The two ends the body tints toward. Glass has no colour of its own (HIG \"Color\"). */\n tintDark: 0.07,\n tintLight: 0.94,\n /** How far the backdrop's spread reaches past its mean when deciding what the ink needs. */\n busyEdge: 0.75,\n /** Fine texture the body has to stop being a window for. */\n groundSpan: 0.06,\n /** Where the tint flips direction, by the element's AVERAGE lightness — a local threshold cuts\n * a diagonal step across the body on a gradient. */\n darkSideFrom: 0.42,\n darkSideTo: 0.58,\n /** Ceiling on any single demand, so one requirement cannot make the glass opaque on its own. */\n maxDemand: 0.92,\n /**\n * And a tighter one for presence specifically. It is a FLOOR on visibility, not a licence to go\n * opaque: wherever the body's tint sits close to the backdrop, the density that would deliver the\n * separation is the ceiling, and glass at `maxDemand` has stopped being a window. Better to\n * separate as far as transparency allows and no further. UNMEASURED.\n */\n presenceDemand: 0.5,\n} as const;\n\n/** Shadow (§4). The density law lives in `geometry.ts`; these are its measured ends. */\nexport const SHADOW = {\n /**\n * Measured off reference frames 711–723: 4.0% over a flat light backdrop, 19.9% over text.\n *\n * REPRODUCED independently off frames/verify/m-707 and m-711 — the same capsule in the same scene\n * at the same scale, once below the text over plain background and once scrolled up over it.\n * Comparing the rows under the capsule against the same rows far to either side, so the\n * background's own gradient cancels: 3.5% and 19.2%, peaking about 140 px below the capsule.\n * Two passes, different frames and a different method, agreeing to within 0.7 of a point.\n */\n alphaFlat: 0.04,\n alphaBusy: 0.199,\n} as const;\n\n/** Dispersion: the channels refract at different indices (§1, Cauchy). */\nexport const DISPERSION = {\n /** Red bends less than the base index, blue more — and not symmetrically. */\n redShift: -0.4,\n blueShift: 0.6,\n} as const;\n\n/** Response to a finger (§5). The springs and decay live in `touch-response.ts`; these shape the\n * field the finger deforms. */\nexport const TOUCH = {\n /**\n * The element grows under pressure (M 3:51; HIG: interactive \"expands\").\n *\n * CHECKED, not measured: across frames/knob/switch-press, a 4x5 sheet of one switch being\n * pressed, the control's extent runs 764 px in the three settled frames and 787 to 822 under the\n * finger — 3 to 8 per cent. This value sits inside that, which is a consistency check and not a\n * derivation: the measurement cannot separate the knob stretching from the track growing, and the\n * settled frames agreeing to the pixel is the only part of it that is tight.\n */\n pressGrow: 0.06,\n /** The ridge around the contact blob: material displaced from under the finger ends up\n * somewhere. Without it the shape balloons, and a dense medium does not do that. */\n ridge: 0.42,\n /** How far press pulls the field toward the finger. */\n pressPull: 0.16,\n /** Wavelength and decay of the ripple, as fractions of its span. Short and quick: in a dense\n * medium ripples are frequent and small; long shallow swells are water. */\n waveLength: 0.17,\n waveDecay: 0.7,\n /** The ripple's span, as a multiple of the contact radius. It has to reach the far edge, or it\n * reads as jitter under the finger rather than a wave across the surface. */\n waveSpan: 2,\n /**\n * Contact radius as a fraction of the element's half-size. UNMEASURED: §5 says the response has\n * to be visible UNDER the finger, which is why the blob is wide, but gives no figure.\n */\n radiusOfHalfSize: 1.1,\n /**\n * Wave impulse as a fraction of the travel limit. UNMEASURED: the core carries the ripple's\n * decay and frequency, but nothing says how hard a finger strikes it.\n */\n waveOfTravel: 0.18,\n /** The lift-off ring is weaker than the one from touching down (§5). UNMEASURED ratio. */\n releaseWave: 0.6,\n /**\n * How far a glow reaches past the element it started on, as a multiple of that element's\n * half-size. UNMEASURED: §5 says the glow spreads \"onto any Liquid Glass elements nearby\" and\n * names no distance. This is the reach at which a neighbour in a tab bar still lights and one\n * across the screen does not.\n */\n glowReach: 3,\n /**\n * How much of an element's \"active\" state a touch alone raises — the fraction the glow and the\n * ink lift ride on when nothing else is driving them. UNMEASURED.\n *\n * It was a private constant on the Android surface whose comment said it matched the web's, and\n * nothing enforced that: the web renderer takes `active` from the host as a field and has no\n * constant to match. Two renderers agreeing by a comment is exactly what this file is for.\n */\n activeOnTouch: 0.3,\n} as const;\n\n/** The bevel's profile — spherical, like a cap: `t / sqrt(1 - t² · k)`, clamped. A plain `t²` kept\n * the slope near zero through most of the bevel and then shot up at the edge, so the optics\n * bunched into a ring and the element read as a puck. */\nexport const BEVEL = {\n sphere: 0.94,\n floor: 0.02,\n slopeMax: 3.2,\n} as const;\n\n/** Where two shapes meet head-on their normals cancel exactly and the blend lands on zero. */\nexport const EPSILON = 1e-5;\n\n/** What the medium does to light passing through it (§3). */\nexport const MEDIUM = {\n /** The lightness content under the glass is pulled toward, and how hard. The medium both removes\n * light and mixes scattered light back in: over a light backdrop the body darkens, over a dark\n * one it lightens. A layer that only ADDED light pushed the body the wrong way over light\n * backdrops (M 2:35). */\n luma: 0.4,\n pull: 0.07,\n /** Ambient light reaching the body on top of that pull. */\n ambientSpill: 0.01,\n /** Glass concentrates light: the body is a touch lighter than what lies beneath it (M 2:29). */\n concentrate: 0.01,\n /** Scattered light on a frosted element is an ADDITION over the backdrop, not a fraction of the\n * way to the tint — a fraction goes to zero once the backdrop reaches the tint's lightness and\n * darkens past it (docs/benchmarks.md). */\n matteLift: 0.1,\n /** How far scattering reaches, as a fraction of the gather radius, over a busy backdrop under\n * ink. Set against the reference: structure under the capsule fades by a factor of nine or ten\n * there, not thirty (M 11:47). */\n scatterMax: 0.2,\n scatterBase: 0.1,\n /** The response to structure saturates early: what competes with the ink is not the AREA of\n * foreign text but the fact of it — a line under a tile measures about 0.12 of busy. */\n structureGain: 20,\n /** Tint density in the flat middle; the bevel multiplies it by the edge density. */\n bodyDensityFlat: 0.19,\n} as const;\n\n/** The lens itself (§1). */\nexport const LENS = {\n /** Backdrop compression at the rim goes to infinity at the silhouette, so the radius correction\n * is capped. */\n footprintMax: 1.8,\n /** Same reason, for the profile's slope. */\n slopeMax: 40,\n /** Every thin film on glass sits around this index. */\n filmIor: 1.35,\n /** Reference channel wavelengths in nm — red, green, blue — for diffraction and interference. */\n lambdaR: 610,\n lambdaG: 550,\n lambdaB: 460,\n} as const;\n\n/** The shadow's shape in the gap under the element (§4). */\nexport const SHADOW_GAP = {\n /** How much weaker the shadow is right at the outline than under the middle of the gap, and what\n * fraction of the offset it takes to reach full depth. In the reference the shadow's minimum\n * sits BELOW the rim, not at it. */\n light: 0.76,\n reach: 0.2,\n /** Fraction of the ambient hue the shadow carries. It has to stay a shadow, not a coloured blob. */\n tint: 1,\n} as const;\n\n/** Ink drawn inside the material (§5). */\nexport const INK = {\n /** Depth beneath the surface, dp. The normal displaces it by exactly this much at the rim. */\n depth: 4,\n /** Defocus under a finger, as a FRACTION of the touch blob rather than a length: the blob\n * already arrives in device units, so this follows both screen density and element size. At\n * rest it is zero and the sample stays a single one. */\n defocus: 0.08,\n} as const;\n\n/** The spectral edge (§1): dispersion, diffraction and interference are one cause — a dependence\n * on wavelength — and one hue multiplier, normalised to its own mean. They colour the reflection\n * without brightening it. */\nexport const SPECTRAL = {\n /** How far into the bevel the fringes reach, as a fraction of it measured from the silhouette.\n * Diffraction is an EDGE effect; past this the bevel is plain glass. */\n diffractionOnset: 0.45,\n /**\n * The same window for interference, which had none. §2 puts the iridescence on the opposing ARC —\n * \"the opposing arc carries an iridescent fringe\" — and a fringe is a thing at an edge.\n *\n * Without it the term applies wherever the surface angle puts it, and across the inner bevel the\n * angle barely changes, so a film that should read as a fringe reads as a flat colour filter.\n * Measured on a 680x64 bar with the default preset: a multiplier of 1.68, 1.26, 0.05 held CONSTANT\n * from a third of the way through the bevel to its inner edge — red boosted by two thirds and blue\n * removed outright. UNMEASURED window; wider than diffraction's because interference reaches\n * further in than the fringes do.\n */\n iridescenceOnset: 0.25,\n /** Fringes across the bevel. Denser as the bevel sharpens, which is what the phase term does. */\n diffractionFringes: 4,\n /** The channel the hue is measured against, nm. Green is the eye's own reference. */\n referenceLambda: 550,\n} as const;\n\n/** Tinting (§7): a colour that is a property of the medium, not a fill over it. */\nexport const ACCENT = {\n /** The tone the colour takes over a dark backdrop and over a light one. \"A range of tones mapped\n * to content brightness underneath\", rather than one flat colour. */\n deep: 0.88,\n light: 1.08,\n /** How much of the medium the colour occupies by default. Short of one, because the content has\n * to keep coming through: a fill \"breaks the visual character of Liquid Glass\" (@17:03). */\n amount: 0.8,\n} as const;\n\n/**\n * The system accessibility settings (§9). They are modifiers on the material's layers, so their\n * calibration belongs in the law next to the layers they move — not as private constants in the\n * module that happens to apply them.\n */\nexport const ACCESSIBILITY = {\n /** Frost floor under reduced transparency: the glass gets \"frostier\" (§9). */\n frostMinDp: 14,\n /**\n * Body floor under reduced transparency. B @10:07 is the stricter statement of the two — a bar\n * \"gets a background when reduce transparency is enabled\" — so this is a background, not a\n * thicker haze. UNMEASURED: neither source gives a figure.\n */\n obscureMin: 0.82,\n /** Under increased contrast the element is \"predominantly black or white\" (§9): the body goes to\n * whichever pole its ink already points at, at a density that leaves it reading as that pole. */\n contrastDensity: 0.94,\n /** …and separates from the backdrop on its own, whatever is behind it. */\n contrastPresence: 0.5,\n /**\n * The contrasting border §9 asks for, in units of lightness away from the body's own pole. The\n * rim stops taking its colour from the environment and takes it from the element instead — an\n * ambient hairline is not a contrasting border. UNMEASURED.\n */\n contrastRim: 0.85,\n /**\n * Press that survives reduced motion. §9 \"decreases the intensity of some effects and disables\n * any elastic properties\": the spring and the ripple are elastic and go to zero, the press is an\n * ease that carries the element's light, so it is damped rather than removed — an element that\n * stops answering a finger altogether is not reduced motion, it is no feedback. UNMEASURED.\n */\n stillPress: 0.6,\n} as const;\n\n/**\n * Morphing (§5). Apple's design leads name their own model for it out loud (S 1:25:30, fireside\n * chat with the Apple design team): \"we also had a refresher from biology class. It's called\n * mitosis and meiosis. When these things are coming together or materialization and\n * dematerialization and morphing.\"\n *\n * Which is the right physics and not a metaphor: a dividing cell is one body throughout. It never\n * has a moment of being two bodies that happen to touch, and it never pops a second body into\n * existence beside the first. The neck is continuous from start to finish, and it is the neck that\n * carries the whole transition.\n */\nexport const MORPH = {\n /**\n * Width of the neck between two lobes, as a fraction of the smaller one's half-size. On a large\n * element the bridge has to be wider or the seam keeps a sharp corner, which a liquid does not\n * have. UNMEASURED: the reference names the behaviour and no figure.\n */\n neck: 0.35,\n /**\n * How far past merely touching a completed fusion goes, as a multiple of the bridge width that\n * just closes the gap. At exactly the bridge width the two surfaces meet at a point, which is two\n * shapes kissing rather than one body.\n *\n * MEASURED, frames/morph/s03, the one panel where the necks are still attached. Apple's\n * silhouette there: lobes 72 and 82 px with their centres 92 px apart — 15 px of space between\n * their surfaces — joined by a neck 28 px tall. Rendering the same geometry through this model\n * gives 29.0. The measurement discriminates: 1.2 gives 23.5, 1.4 gives 33.5, and at 1.0 the neck\n * closes to nothing.\n */\n fuse: 1.3,\n} as const;\n\n/**\n * CAUSE TO EFFECT. The normalisations that turn what the medium IS — index, thickness, bevel,\n * roughness, film — into what a renderer needs. They lived as literals inside `optics.ts`, half of\n * them not even named, which meant the heart of the model was the one part of it the law could not\n * see.\n *\n * Almost all of them are stylisations and say so. Literal physical values put every effect at the\n * threshold of visibility: real glass reflects four per cent at normal incidence, and a rim drawn\n * at four per cent is not a rim. Each is monotonic in its own cause, so \"denser medium, brighter\n * rim\" holds whatever the constant is; what no one has measured is where on the scale Apple's\n * material sits. Hence UNMEASURED on nearly all of it — that is the honest state of this file, and\n * the gate now says so out loud instead of the number hiding in a module.\n */\nexport const DERIVE = {\n /** Physical 4% reflectance into the render's working range. UNMEASURED. */\n fresnelGain: 17.5,\n /** Schlick's exponent. A constant of the approximation, not a knob. */\n fresnelExponent: 5,\n /** The index at which ray bending is at full strength, measured from air. UNMEASURED. */\n iorFullBend: 0.6,\n /** Magnification behind a plane-parallel plate, per dp of thickness. UNMEASURED. */\n magnifyPerDp: 0.006,\n /** In ordinary glasses the Abbe number falls as the index rises, so dispersion grows with it.\n * UNMEASURED slope. */\n dispersionPerIor: 1.1,\n /** Index spread between the red and blue channels. The physical value (~0.01 at an Abbe number\n * of 55) is at the threshold of visibility. UNMEASURED. */\n iorSpreadPerDispersion: 0.045,\n /** Beer–Lambert absorption per dp of path. UNMEASURED. */\n absorbPerDp: 0.017,\n /** Ceiling on how much denser the bevel may read than the body. The rim's ray travels further\n * through the medium; past this the rim is milk rather than glass. UNMEASURED. */\n edgeDensityMax: 4,\n /**\n * Frost ceiling, dp. Deliberately low: blur is a SUPPORTING device here, and past about a dozen\n * dp letters under the glass stop being letters. Separating content from ink is the body's job.\n *\n * UNMEASURED, and an attempt is recorded here so the next one does not repeat it.\n * frames/verify/m-711 has the same paragraph sharp beside the capsule and behind it, which looks\n * like the measurement: match the blur that takes the sharp patch's detail down to the glassed\n * one's. It gives 2 to 3 px at that frame's scale, and the figure is not trustworthy. Detail is\n * lost to three things at once there — the frost, the magnification (`refractionScale` lowers the\n * text's spatial frequency without blurring anything), and the body veiling its contrast — and\n * the method cannot separate them. What it does bound is the total: the text behind the glass\n * keeps 68% of the detail it has beside it.\n *\n * A clean measurement needs a frame where the glass does not magnify, or a feature of known size\n * behind it to normalise the magnification out.\n */\n blurMaxDp: 12,\n /** Highlight width from a smooth surface and from a fully rough one, as a specular exponent.\n * UNMEASURED. */\n specularPowerSmooth: 160,\n specularPowerRough: 8,\n /** How much roughness damps the highlight's brightness. UNMEASURED. */\n specularRoughDamping: 0.6,\n /**\n * The medium's own hue by density. Water absorbs red and skews cool, ordinary glass is nearly\n * neutral with a faint green, dense high-index media skew warm. Glass has no colour of its own\n * (HIG \"Color\"), so this is never set by hand — it is tied to the index.\n */\n hueCool: [0.86, 1.0, 1.08],\n hueNeutral: [1.0, 1.02, 0.99],\n hueWarm: [1.08, 1.0, 0.88],\n /** The index range the hue sweeps across, and where it starts. UNMEASURED. */\n hueFromIor: 1.2,\n hueSpan: 0.55,\n /** Body lightness follows reflectance: the denser the medium, the more of its surroundings it\n * returns. UNMEASURED base and slope. */\n bodyLiftBase: 0.34,\n bodyLiftPerF0: 2.4,\n /**\n * How far past the bevel the rim gathers its surroundings, as a multiple of the bevel. At a\n * grazing angle the eye receives the vicinity rather than what is under the glass, and without\n * this, glass on an empty black background has no source at all. UNMEASURED.\n */\n gatherPerBevel: 4,\n /** Floor and ceiling on that radius, dp. Unbounded, a wide bevel gathers from fifty dp away and\n * a READABLE copy of the neighbourhood appears inside the glass — eight samples cannot blur a\n * disc that large (E-33, E-37). */\n gatherMinDp: 4,\n gatherMaxDp: 28,\n /** The body's own density from absorption through its thickness. Small: the body only moves\n * toward the tint under the legibility requirement, otherwise it dims the content. UNMEASURED. */\n bodyDensity: 0.05,\n /**\n * Rim light on the physical scale rather than the rim highlight's. `fresnelGain` saturates at one\n * for dense media, and applying it here too would raise body lightness harder than the glass had\n * just separated it from the ink — eating its own legibility work. UNMEASURED.\n */\n edgeLightGain: 6,\n /**\n * Iridescence rides the REFLECTED ray, so it is tied to Fresnel and has no knob of its own.\n *\n * MEASURED against how coloured a real rim is. In frames/crops the brightest rim pixels have a\n * channel spread — (max − min) / max — of 13% in cap158-left and 20% in cap158-right, against\n * their own backdrops' 14.6% and 14.3%. So the rim is no more coloured than the scene it stands\n * in: §2's \"iridescent fringe\" adds a few points at most, and in one of the two crops it adds\n * nothing measurable.\n *\n * At 1.6 this put ordinary glass at 0.945 iridescence and the spectral multiplier reached a 97%\n * channel spread — red boosted by two thirds and blue removed. Rendered over a coloured page that\n * is a neon tube around every control, which is what sent me to measure it.\n */\n iridescencePerFresnel: 0.042,\n /** Edge diffraction shares dispersion's λ-dependence, at the stylised amplitude: at the physical\n * one the fringes are not visible at all. MEASURED with the same crops and the same target as\n * iridescence — on its own it was reaching a 93% channel spread. */\n diffractionPerDispersion: 0.05,\n /** Multiple internal reflection — the denser the medium, the more light it circulates and the\n * more it is tinted by its surroundings. UNMEASURED slope. */\n colorPickupPerFresnel: 0.9,\n /**\n * The ceiling, which keeps it a medium rather than a fill.\n *\n * MEASURED, frames/concentric/shadow-zoom: the same sidebar twice, over a yellow cover and over a\n * pink one, so the difference between the panels is the pickup with the sidebar's own colour\n * subtracted out. Sampling a band of rows clear of the text, the bar's hue offset against the\n * cover's own reaches 0.31 of it at the edge nearest the content in the yellow panel and 0.28 in\n * the pink one. It was 0.42, which nothing measured.\n *\n * Reality is not uniform: the bleed falls to nothing about ninety pixels in, and both panels show\n * the same falloff. The DOM path has one backdrop sample per element and cannot reproduce that,\n * so it applies the ceiling across the whole body — right at the edge, too strong in the middle.\n * That limit is in docs/dom.md rather than papered over with a lower number.\n */\n colorPickupMax: 0.3,\n} as const;\n\n/**\n * SIZE AND SHADOW. What changes when an element gets bigger, and how dense its shadow reads over\n * what is behind it. 219 @6:36: as glass \"flexes and morphs to larger sizes, it simulates a\n * thicker material with deeper shadows and more pronounced lensing and refraction\".\n */\nexport const SIZE = {\n /** Half-size at which bevel and thickness are specified as given; they grow as its square root\n * from there. UNMEASURED reference size. */\n referenceDp: 24,\n /** Floor and ceiling on that growth. UNMEASURED. */\n gainMin: 0.8,\n gainMax: 2.4,\n /** A bevel wider than this fraction of the half-size breaks the SDF — the roundings converge in\n * the middle. A property of the geometry, not a taste. */\n maxBevelFraction: 0.65,\n} as const;\n\n/**\n * Shadow density by what is behind the element. 219 @11:47, verbatim: it \"increases the opacity of\n * its shadow when it is over text… lowers the opacity of its shadow when it is over a solid light\n * background.\" About content BEHIND the element, so one value per element rather than a field over\n * the shadow's area. Endpoints checked against the reference by the depth of the dip under the\n * element (docs/benchmarks.md).\n */\nexport const SHADOW_DENSITY = {\n /** Over a flat background. */\n flat: 0.8,\n /** How fast it rises with structure behind the element, and how far it may rise. */\n busyGain: 6,\n busyRise: 1.2,\n /** Quantisation of the emitted value: a shadow that changes on every pixel of scroll re-lays-out\n * the native view every frame. */\n step: 0.05,\n} as const;\n\n/**\n * THE MEDIUM'S RESPONSE TO A FINGER (§5). Part of the material, exactly as `ior` is: keeping these\n * with the consumer would mean web and Android ended up with two different glasses under one name.\n *\n * Press is viscous — it dents shallow and releases slowly. Drag is thick: the body noticeably lags\n * the finger, travel is short, and on release it snaps back fast with almost no overshoot, because\n * a wide springy overshoot would be liquid jelly rather than dense glass.\n */\nexport const SPRING = {\n /** Stiffness and damping while the finger is down. UNMEASURED. */\n holdStiffness: 260,\n holdDamping: 46,\n /** …and after it lifts. Stiffer, and damped hard: a dense medium snaps back without ringing. */\n releaseStiffness: 420,\n releaseDamping: 34,\n /** Time constants for the press dent, in and out, seconds. UNMEASURED. */\n pressAttack: 0.07,\n pressRelease: 0.16,\n /** How fast the touch point catches up to the finger. Not instant: an instant jump tears the\n * deformation, and on rapid taps that reads as jitter. */\n pointFollow: 0.045,\n /** …and how fast the element registers as being touched at all, which is what the glow rides. */\n activeFollow: 0.09,\n /** The ripple decays within a quarter second rather than oscillating: in a viscous medium ripples\n * are short and weak. UNMEASURED. */\n waveDecay: 0.22,\n waveTurnsPerSecond: 3,\n /** Ceilings on the accumulated ripple, as multiples of a single impulse. Impulses add up rather\n * than restart — restarting cuts a running wave mid-period, which is what jolts on rapid taps. */\n waveCapOnGrab: 1.6,\n waveCapOnRelease: 2,\n} as const;\n\n/** The user's clear-to-tinted preference (§3). */\nexport const SCALE = {\n /** Where on the scale the material stays exactly as it is by default. */\n default: 0.35,\n /** Body density at the fully tinted end: content under the glass has to be hidden. UNMEASURED. */\n tintedDensity: 0.9,\n} as const;\n\n/**\n * The scroll edge (§10). 219 @9:16: as content scrolls under a glass element \"the effect gently\n * DISSOLVES the content into the background, lifting the glass visually above the moving content,\n * and allowing floating elements like titles to always remain clear.\"\n *\n * 356 @11:32 says what it is not, and the first implementation here did exactly that: \"they don't\n * block or darken like overlays. They simply clarify where UI and content meet.\"\n */\nexport const SCROLL_EDGE = {\n /** How far the content has to slide under the panel for the effect to fully engage, dp. */\n engageDp: 24,\n /**\n * How far the blur reaches BELOW the bar's lower lip, as a multiple of the bar's own height.\n *\n * MEASURED, frames/scroll-edge/z576 at 320x413. High-frequency energy (mean |laplacian| per row,\n * which a brightness gradient in the content cannot fake) reads 1.4 through the zone under the\n * bar and 14 in the sharp content below — a factor of ten. The bar's lip is at y≈45 and the zone\n * runs to y≈130, so the reach is about 1.9 times the bar's own height.\n *\n * The same frame confirms 219 @9:22 in passing: the floating title sits inside that zone at 32,\n * twenty times its surroundings. Titles stay crisp while everything behind them dissolves, which\n * is why the effect belongs behind the glass in the stack rather than over the content.\n */\n reachOfBarHeight: 1.9,\n /** The blur the content dissolves into at the edge, dp. This is the effect itself — the content\n * goes out of focus into the background rather than being covered by anything. UNMEASURED. */\n dissolveBlurDp: 10,\n /**\n * Over dark content the glass turns dark and 219 @9:33 switches the effect \"to apply a subtle\n * dimming instead\". Dimming is a reduction in luminance: dark content under dark glass merges\n * with it, and pushing the content down is what lets the glass sit above it. UNMEASURED.\n */\n dimAlpha: 0.1,\n /** A pinned view under the panel (column headers) gets a flat band instead of a gradual fade\n * (219 @9:41) — \"a stronger, more opaque boundary\" (356 @12:12). UNMEASURED. */\n hardBlurDp: 14,\n hardAlpha: 0.18,\n} as const;\n","import type { VireGlassOptics } from './material';\nimport { SHADOW_DENSITY, SIZE } from './law';\n\n/** Glass shape in dp. Circle and capsule are special cases of a rounded rectangle. */\nexport type VireGlassGeometry = {\n width: number;\n height: number;\n cornerRadius: number;\n};\n\nexport const circleGeometry = (size: number): VireGlassGeometry => ({\n width: size,\n height: size,\n cornerRadius: size / 2,\n});\n\nexport const capsuleGeometry = (width: number, height: number): VireGlassGeometry => ({\n width,\n height,\n cornerRadius: Math.min(width, height) / 2,\n});\n\nexport const roundedRectGeometry = (\n width: number,\n height: number,\n cornerRadius: number,\n): VireGlassGeometry => ({ width, height, cornerRadius });\n\nexport const halfMinDp = (g: VireGlassGeometry) => Math.max(Math.min(g.width, g.height) / 2, 1);\n\n/** Viewport margin for a drop that overshoots past the finger: a fraction of the element's half\n * size beyond the drag travel itself. The drop overshoots the body by no more than `dragLimit`,\n * and stitching adds smoothing on top of that — this term covers it too. */\nexport const MAX_STRETCH = 0.34;\n\n/**\n * How big this element reads, for the purpose of how thick its glass is.\n *\n * Not `halfMinDp`, which is half the narrower side and is the right measure for a bevel limit or a\n * contact radius but not for this: a 390x420 sheet and a 390x780 one have the same narrow side and\n * are not the same surface. Not the area either: a 900x8 rule has more area than a toolbar button\n * and is the thinnest glass in the interface.\n *\n * The geometric mean of the two respects both facts — the narrow side caps how much glass there\n * can be, and among shapes that share it, more surface reads as more glass. Derived, not\n * calibrated: it introduces no constant.\n */\nexport const sizeDp = (g: VireGlassGeometry) =>\n Math.sqrt(halfMinDp(g) * Math.max(Math.sqrt(g.width * g.height) / 2, 1));\n\n/**\n * Bigger element, thicker glass: a stronger lens, a deeper shadow (219 @6:36 — as glass \"flexes and\n * morphs to larger sizes, it simulates a thicker material with deeper shadows and more pronounced\n * lensing and refraction effects\"). Bevel and material thickness are specified for an element at a\n * reference size and grow as the square root of it.\n *\n * The ceiling is approached, never reached. A hard clip made every surface above it the same glass,\n * and above it was where the interface lives: a half-open sheet, a full-screen sheet, an iPad\n * sidebar and a 900px Mac panel all sat at exactly 2.4. The reference names sidebars as the LARGE\n * end of the range, so a model that stops responding before them has stopped obeying it.\n *\n * The curve below is the same square root; the join at `gainMin` is continuous in value and in\n * slope, and the asymptote is `gainMax` exactly as before. Both constants keep their values —\n * what changed is that saturation is smooth instead of a clip.\n */\nexport const sizeGain = (g: VireGlassGeometry) => {\n const raw = Math.sqrt(sizeDp(g) / SIZE.referenceDp);\n if (raw <= SIZE.gainMin) return SIZE.gainMin;\n const span = SIZE.gainMax - SIZE.gainMin;\n return SIZE.gainMin + span * (1 - Math.exp(-(raw - SIZE.gainMin) / span));\n};\n\n/** A bevel wider than this fraction of the half-size breaks the SDF: the roundings converge in\n * the middle. */\nexport const MAX_BEVEL_FRACTION = SIZE.maxBevelFraction;\n\nexport const bevelFraction = (g: VireGlassGeometry, o: VireGlassOptics) =>\n Math.min(MAX_BEVEL_FRACTION, (o.bevelDp * sizeGain(g)) / halfMinDp(g));\n\nexport const bevelDp = (g: VireGlassGeometry, o: VireGlassOptics) =>\n Math.max(bevelFraction(g, o) * halfMinDp(g), 1);\n\nexport const thicknessDp = (g: VireGlassGeometry, o: VireGlassOptics) =>\n o.thicknessDp * sizeGain(g);\n\n/** Glass height right at the silhouette, a fraction of thickness: without it there's nothing at\n * the edge to bend the ray. */\nexport const RIM_FRACTION = 0.85;\n\nexport const rimDp = (g: VireGlassGeometry, o: VireGlassOptics) => thicknessDp(g, o) * RIM_FRACTION;\n\n/** Bigger element, deeper and wider shadow (M 7:14). */\nexport const shadowReachDp = (g: VireGlassGeometry) =>\n Math.min(Math.max(halfMinDp(g) * 0.65, 6), 36);\n\n/** How far the second morph shape reaches past the first one's bounds. Without this margin the\n * fused shape gets clipped by the canvas edge and the experiment shows the wrong thing. */\nexport function morphReachDp(\n g: VireGlassGeometry,\n morph?: { offsetX: number; offsetY: number; width: number; height: number; smoothing: number },\n): number {\n if (!morph || morph.smoothing <= 0) return 0;\n return Math.max(\n 0,\n Math.abs(morph.offsetX) + morph.width / 2 - g.width / 2,\n Math.abs(morph.offsetY) + morph.height / 2 - g.height / 2,\n );\n}\n\n/**\n * Quantization step for the margin. The margin only needs to cover the sampling — its exact value\n * doesn't matter, but changing it every frame is expensive: the native lens view gets re-laid-out\n * and re-sets its `RenderEffect`. While dragging a panel or morphing, the margin used to drift\n * continuously, and that produced visible stutter. Round up to the step — size changes rarely.\n */\nconst PAD_STEP = 8;\nconst quantise = (v: number) => Math.ceil(v / PAD_STEP) * PAD_STEP;\n\n/**\n * Margin around the lens view on each side: beyond it, the shader has nothing to sample.\n *\n * FOUR things have to fit in here. The refraction sample with aberrations. The blur radius —\n * it also samples around the point. The gather radius — the rim picks it up from outside the\n * shape, and without the margin it goes black exactly where it should be catching the\n * surroundings. And drag travel: the lens view moves with the finger, but its bounds don't, and\n * the sample falls off the edge, which is how layers from under the glass leak through.\n */\nexport function lensPadDp(\n g: VireGlassGeometry,\n o: VireGlassOptics,\n morph?: Parameters<typeof morphReachDp>[1],\n dragLimit = 0,\n): number {\n const sampling = Math.max(o.blur, o.gatherRadiusDp);\n const stretch = halfMinDp(g) * MAX_STRETCH;\n return quantise(sampling + dragLimit + stretch + morphReachDp(g, morph) + 2);\n}\n\n/**\n * Margin around the surface canvas: the shadow reaches outside the shape, and dragging shifts it\n * further still.\n *\n * The multiplier is smaller than the shadow's full reach: under the finger, the shader for a\n * rising element multiplies the radius by 1.55, and the very end of that tail falls outside the\n * margin. Left that way on purpose — at the margin's edge it's at 1.2% alpha (2.5% before the\n * shadow was softened), and raising the multiplier means growing every surface view's area. If\n * that tail ever shows up on a device, fix it here.\n */\nexport function surfacePadDp(\n g: VireGlassGeometry,\n dragLimit = 0,\n morph?: Parameters<typeof morphReachDp>[1],\n): number {\n return quantise(shadowReachDp(g) * 1.2 + dragLimit + morphReachDp(g, morph) + 2);\n}\n\n/**\n * SHADOW DENSITY BY WHAT'S UNDER THE ELEMENT. Reference 219 @11:47, verbatim: \"increases the\n * opacity of its shadow when it is over text… lowers the opacity of its shadow when it is over a\n * solid light background.\" This is about content BEHIND THE ELEMENT, so it's a single value per\n * element, not a field over the shadow's area.\n *\n * The law lives here, not at the bench: while it was baked into the web renderer, shadows on\n * Android never adapted at all. The endpoints were checked against the reference by the depth of\n * the dip under the element — docs/benchmarks.md.\n */\nexport function shadowOpacity(busy: number): number {\n return (\n SHADOW_DENSITY.flat +\n Math.min(Math.max(busy, 0) * SHADOW_DENSITY.busyGain, SHADOW_DENSITY.busyRise)\n );\n}\n\n/** Same thing for platforms where the measurement flows through state: quantized coarsely, like\n * the ambient color, otherwise every probe sample would trigger a surface repaint. */\nexport function shadowOpacityFrom(sample: { busy: number }): number {\n return Math.round(shadowOpacity(sample.busy) / SHADOW_DENSITY.step) * SHADOW_DENSITY.step;\n}\n","// The single description of VireGlass geometry. Both shaders draw it from here: the SKSL surface\n// (`surface-shader.ts`) and the AGSL lens (`lens-shader.ts`, shipped as a string into the native\n// view). AGSL and SKSL are the same language, so the SDF no longer needs duplicating in Kotlin:\n// before, the surface's circle and the lens's rounded rectangle described different pieces of\n// glass, and the bevel constant had to be kept in sync by hand (docs/adr-001-rendering.md §3).\nimport { BEVEL, EPSILON, TOUCH } from './law';\n\n/** 2π. Structural, not a law — but the shader has no built-in for it. */\nconst VG_TAU = 6.28318530718;\n\nexport const VG_SDF = `\nfloat vgRoundRect(float2 p, float2 halfSize, float corner) {\n float2 q = abs(p) - halfSize + corner;\n return min(max(q.x, q.y), 0.0) + length(max(q, float2(0.0))) - corner;\n}\n\nfloat vgSmin(float a, float b, float k) {\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n return mix(b, a, h) - k * h * (1.0 - h);\n}\n\n// A scene is a single shape, and when k > 0 a smooth union with one or two neighbors. A third\n// shape exists to break the control into pieces (docs/reference.md §5): there are two bridges\n// there. It's turned off with a zero size, not its own k: the fused body shares one bridge.\nfloat vgScene(float2 p, float2 halfSize, float corner,\n float2 offsetB, float2 halfB, float cornerB, float k,\n float2 offsetC, float2 halfC, float cornerC) {\n float a = vgRoundRect(p, halfSize, corner);\n if (k <= 0.0) { return a; }\n float ab = vgSmin(a, vgRoundRect(p - offsetB, halfB, cornerB), k);\n if (halfC.x <= 0.0) { return ab; }\n return vgSmin(ab, vgRoundRect(p - offsetC, halfC, cornerC), k);\n}\n\n// Response to a finger. It's the FIELD around the touch point that deforms, not the shape's\n// bounding box: scaling width to pull the right edge would also pull the left one — liquid\n// doesn't behave that way. Here the displacement falls off with distance from the finger, so the\n// far edge stays put.\n//\n// The order of the terms matters: drag shifts the field, press pulls it toward the finger, the\n// wave rides on top of the already-shifted field — otherwise the ripple decouples from the\n// deformation and lives a life of its own.\nfloat2 vgTouchWarp(float2 p, float2 touch, float2 pull, float press, float radius,\n float waveAmp, float wavePhase) {\n if (radius <= 0.0) { return p; }\n // Under the finger the whole element grows (M 3:51; HIG: interactive \"expands\").\n p /= 1.0 + ${TOUCH.pressGrow} * press;\n float2 d = p - touch;\n float r = length(d);\n\n // The finger is a BLOB, not a point, but not a hard stamp either: a wide peak, soft edges. A\n // flat plateau with a sharp cutoff at the edge shifts the region as a block, and a straight\n // line under the glass breaks into a step — the deformation reads as rectangular even though\n // the finger is round. A double smoothstep gives the same contact width without that step.\n //\n // The influence cuts off at the radius rather than fading into an infinite tail like a\n // Gaussian: with a tail the deformation spreads into a \"rubber mattress\" bulge.\n float k = clamp((radius - r) / radius, 0.0, 1.0);\n float s = k * k * (3.0 - 2.0 * k);\n float core = s * s * (3.0 - 2.0 * s);\n // A ring around the blob: material displaced from under the finger has to end up somewhere.\n // Without this ridge the shape just balloons, and a dense medium doesn't behave that way.\n float rim = k * k * (1.0 - k) * 4.0;\n\n float2 q = p - pull * (core - ${TOUCH.ridge} * rim);\n q -= d * (press * ${TOUCH.pressPull} * core);\n\n // The wave has its own scale, twice the drag radius: the ripple has to reach the far edge,\n // otherwise it reads as jitter under the finger rather than a wave across the surface. The\n // wavelength is short: in a dense medium ripples are frequent and small, long shallow swells\n // are water.\n if (waveAmp > 0.0 && r > 0.0001) {\n float span = radius * ${TOUCH.waveSpan}.0;\n float ring = sin(r / (span * ${TOUCH.waveLength}) - wavePhase * ${VG_TAU}) * exp(-r / (span * ${TOUCH.waveDecay}));\n q -= (d / r) * ring * waveAmp;\n }\n return q;\n}\n\n// Analytical normal of a single shape: radial on the rounded part, axis-aligned on the straight\n// segments.\nfloat2 vgRoundRectNormal(float2 p, float2 halfSize, float corner) {\n float2 q = abs(p) - halfSize + corner;\n float2 g = (q.x > 0.0 && q.y > 0.0)\n ? normalize(max(q, float2(0.0001)))\n : (q.x > q.y ? float2(1.0, 0.0) : float2(0.0, 1.0));\n return g * sign(p);\n}\n\n// Normal of the union — ANALYTICAL, no more finite differences here.\n//\n// Derivation: smin has two terms, mix(b,a,h) and −k·h·(1−h). Their derivatives with respect to h\n// contain a factor of (1−2h) with opposite signs and cancel exactly, because h is linear in\n// (b−a)/k. What's left is mix(∇b, ∇a, h) — that is, the two shapes' normals, blended with the\n// same weight that blends the distances themselves.\n//\n// The previous version took four ADDITIONAL scene evaluations per pixel (each one — two shapes\n// plus smin) and was still an approximation. Here there are two shapes, exactly.\nfloat2 vgSceneNormal(float2 p, float2 halfSize, float corner,\n float2 offsetB, float2 halfB, float cornerB, float k,\n float2 offsetC, float2 halfC, float cornerC) {\n float2 na = vgRoundRectNormal(p, halfSize, corner);\n if (k <= 0.0) { return na; }\n float2 q = p - offsetB;\n float a = vgRoundRect(p, halfSize, corner);\n float b = vgRoundRect(q, halfB, cornerB);\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n float2 nab = normalize(mix(vgRoundRectNormal(q, halfB, cornerB), na, h) + float2(${EPSILON}, ${EPSILON}));\n if (halfC.x <= 0.0) { return nab; }\n // Same derivation as for the pair: normals blend with the same weight as the distances.\n float2 qc = p - offsetC;\n float ab = vgSmin(a, b, k);\n float c = vgRoundRect(qc, halfC, cornerC);\n float hc = clamp(0.5 + 0.5 * (c - ab) / k, 0.0, 1.0);\n return normalize(mix(vgRoundRectNormal(qc, halfC, cornerC), nab, hc) + float2(${EPSILON}, ${EPSILON}));\n}\n\n// Position within the bevel: 0 is the flat middle, 1 is the very edge. This one value feeds the\n// mask, thickness, refraction, aberrations and the width of the light rim.\nfloat vgBevelT(float sd, float bevel) {\n return clamp((sd + bevel) / bevel, 0.0, 1.0);\n}\n\n// Slope of the bevel profile — spherical: t / sqrt(1 - t²), like a spherical cap. The previous t²\n// kept the slope near zero through almost the whole bevel and then shot up right at the edge, so\n// all the optics bunched into a narrow ring and the element read as a PUCK — a flat top and a\n// wall around the rim. Here curvature is spread across the bevel, and the rim stops being a line.\n//\n// This still doesn't control the field of view: only the bevel bends, the middle stays flat,\n// otherwise the surface reads as a soap bubble.\nfloat vgBevelSlope(float t) {\n return min(t * inversesqrt(max(1.0 - t * t * ${BEVEL.sphere}, ${BEVEL.floor})), ${BEVEL.slopeMax});\n}\n\n// PROGRESS FRACTION. Progress is an active state turned into a FIELD: to the left of the boundary\n// the element is active, to the right it stays regular glass, and the boundary moves. A negative\n// value turns the field off entirely — zero is taken by the start of the track and can't also\n// mean off.\n//\n// The boundary is SOFT. A hard seam reads as two different materials glued together rather than\n// two states of one; the transition width is a fraction of the half-width, so it doesn't read as\n// a thread on a large element and doesn't swallow a small one whole.\nfloat vgProgress(float2 p, float2 halfSize, float progress) {\n if (progress < 0.0) { return 0.0; }\n float edge = mix(-halfSize.x, halfSize.x, clamp(progress, 0.0, 1.0));\n float soft = max(halfSize.x * 0.05, 1.0);\n return 1.0 - smoothstep(edge - soft, edge + soft, p.x);\n}\n`;\n\n/** Rate at which the offset builds toward the rim. Shared between the lens (actual sampling\n * offset) and the surface (visualizing the displacement field in debug mode) — otherwise they'd\n * drift apart. */\nexport const VG_FALLOFF = 2.6;\n\n// JS twin of `vgRoundRect`/`vgRoundRectNormal` above, for targets with no GPU to run the shader on\n// (the DOM displacement map). Term-for-term against the GLSL text: a second geometry that behaves\n// differently is exactly the class of bug `check:optics` exists to catch on the shader side, and\n// there is no such gate for this one.\n\n/** Signed distance from `(x, y)` to a rounded rect of size `w`×`h` centered on the origin. */\nexport function sdfRoundedRect(x: number, y: number, w: number, h: number, r: number): number {\n const qx = Math.abs(x) - w / 2 + r;\n const qy = Math.abs(y) - h / 2 + r;\n return Math.min(Math.max(qx, qy), 0) + Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) - r;\n}\n\n/**\n * Closed-form gradient of `sdfRoundedRect`, unit length everywhere except the exact center (where\n * it's genuinely undefined — the medial axis of the shape). NOT finite differences: differencing\n * quantizes the gradient to the sampling step, and the displacement map needs sub-pixel accuracy\n * right at the rim.\n */\nexport function sdfRoundedRectGradient(x: number, y: number, w: number, h: number, r: number): [number, number] {\n const qx = Math.abs(x) - w / 2 + r;\n const qy = Math.abs(y) - h / 2 + r;\n let gx: number;\n let gy: number;\n if (qx > 0 && qy > 0) {\n const cx = Math.max(qx, 0.0001);\n const cy = Math.max(qy, 0.0001);\n const len = Math.hypot(cx, cy);\n gx = cx / len;\n gy = cy / len;\n } else if (qx > qy) {\n gx = 1;\n gy = 0;\n } else {\n gx = 0;\n gy = 1;\n }\n return [gx * Math.sign(x), gy * Math.sign(y)];\n}\n\n// ---------------------------------------------------------------------------\n// JS twins of the shader functions above. The DOM renderer needs this geometry\n// as numbers, not as a string it hands to a compiler. Each mirrors its `vg*`\n// counterpart term for term — a second geometry that drifts is the failure the\n// platform-parity gate exists to catch.\n// ---------------------------------------------------------------------------\n\n/** Mirrors `vgSmin`. */\nexport function smin(a: number, b: number, k: number): number {\n const h = Math.min(Math.max(0.5 + (0.5 * (b - a)) / k, 0), 1);\n return b + (a - b) * h - k * h * (1 - h);\n}\n\n/**\n * The smallest `k` at which `smin` joins two surfaces `gap` apart into one body. Exact for this\n * smin rather than fitted: at the midpoint the two distances are both gap/2, so h = 0.5 and the\n * result is gap/2 − k/4, which reaches zero at k = 2·gap.\n *\n * It is the number `morphBetween` was missing. A neck sized only as a fraction of the element's\n * own half-size has nothing to do with the distance it has to span, so two controls a hundred\n * pixels apart stayed two controls at every t — including t = 1, where the contract says they are\n * one shared medium.\n */\nexport function neckToBridge(gap: number): number {\n return gap > 0 ? gap * 2 : 0;\n}\n\nexport type MorphShape = {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n cornerRadius: number;\n};\n\n/**\n * Mirrors the scene distance: one shape, smoothly unioned with any number of neighbours when\n * `smoothing` is positive. §5's merging and splitting are this union opening and closing.\n *\n * A fold, not a pair. The count used to be in the ARGUMENT NAMES — `b` and `c`, and a fourth\n * shape would have been `d` — which is not a limit the material has. Several independent elements\n * flowing into one whole is the behaviour; how many of them there happen to be is the host's.\n */\nexport function sceneDistance(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n smoothing = 0,\n ...shapes: (MorphShape | undefined)[]\n): number {\n let d = sdfRoundedRect(x, y, w, h, r);\n if (smoothing <= 0) return d;\n for (const s of shapes) {\n if (!s || s.width <= 0) continue;\n d = smin(d, sdfRoundedRect(x - s.offsetX, y - s.offsetY, s.width, s.height, s.cornerRadius), smoothing);\n }\n return d;\n}\n\n/**\n * Mirrors `vgSceneNormal`: normals blend with the same weight that blends the distances, which the\n * shader derives rather than approximates. The same fold as `sceneDistance`, carrying the running\n * distance alongside the running normal because each step's weight is measured against it.\n */\nexport function sceneGradient(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n smoothing = 0,\n ...shapes: (MorphShape | undefined)[]\n): [number, number] {\n let d = sdfRoundedRect(x, y, w, h, r);\n let [gx, gy] = sdfRoundedRectGradient(x, y, w, h, r);\n let blended = false;\n if (smoothing > 0) {\n for (const s of shapes) {\n if (!s || s.width <= 0) continue;\n const sx = x - s.offsetX;\n const sy = y - s.offsetY;\n const ds = sdfRoundedRect(sx, sy, s.width, s.height, s.cornerRadius);\n const weight = Math.min(Math.max(0.5 + (0.5 * (ds - d)) / smoothing, 0), 1);\n const [nx, ny] = sdfRoundedRectGradient(sx, sy, s.width, s.height, s.cornerRadius);\n gx = nx + (gx - nx) * weight;\n gy = ny + (gy - ny) * weight;\n d = smin(d, ds, smoothing);\n blended = true;\n }\n }\n // With nothing blended in, the base gradient is already a unit vector and is returned untouched —\n // the shader takes the same early exit (`if (k <= 0.0) return na;`), and nudging it here instead\n // would put the two renderers a rounding step apart on every flat edge in the material.\n if (!blended) return [gx, gy];\n // The shader's `+ float2(${EPSILON}, ${EPSILON})` before normalising, and it is not decoration:\n // where two shapes meet head-on their normals cancel exactly and the blend lands on zero.\n gx += EPSILON;\n gy += EPSILON;\n const len = Math.hypot(gx, gy) || 1;\n return [gx / len, gy / len];\n}\n\nexport type TouchWarp = {\n x: number;\n y: number;\n pullX: number;\n pullY: number;\n press: number;\n radius: number;\n waveAmp: number;\n wavePhase: number;\n};\n\n/**\n * Mirrors `vgTouchWarp`. The FIELD around the finger deforms, not the bounding box: scaling the\n * width to pull the right edge would pull the left one too, and liquid does not do that.\n *\n * Term order is load-bearing — drag shifts the field, press pulls it toward the finger, the wave\n * rides on the already-shifted field. Reordered, the ripple decouples and lives its own life.\n */\nexport function touchWarp(x: number, y: number, t: TouchWarp): [number, number] {\n if (t.radius <= 0) return [x, y];\n const grow = 1 + TOUCH.pressGrow * t.press;\n let px = x / grow;\n let py = y / grow;\n const dx = px - t.x;\n const dy = py - t.y;\n const r = Math.hypot(dx, dy);\n\n const k = Math.min(Math.max((t.radius - r) / t.radius, 0), 1);\n const s = k * k * (3 - 2 * k);\n const core = s * s * (3 - 2 * s);\n // The ridge around the blob: material pushed out from under the finger has to go somewhere.\n const rim = k * k * (1 - k) * 4;\n\n px -= t.pullX * (core - TOUCH.ridge * rim);\n py -= t.pullY * (core - TOUCH.ridge * rim);\n px -= dx * (t.press * TOUCH.pressPull * core);\n py -= dy * (t.press * TOUCH.pressPull * core);\n\n if (t.waveAmp > 0 && r > 0.0001) {\n const span = t.radius * TOUCH.waveSpan;\n const ring = Math.sin(r / (span * TOUCH.waveLength) - t.wavePhase * VG_TAU) * Math.exp(-r / (span * TOUCH.waveDecay));\n px -= (dx / r) * ring * t.waveAmp;\n py -= (dy / r) * ring * t.waveAmp;\n }\n return [px, py];\n}\n","// The DOM renderer's own optics: an `feDisplacementMap` source built from the same causes as the\n// GL/AGSL shaders, so a page refracting live content still reads as the same material. See\n// `docs/superpowers/specs/2026-09-19-vireglass-over-live-dom.md` for the technique this encodes.\nimport { bevelDp, thicknessDp, type VireGlassGeometry } from '../geometry';\nimport { BEVEL } from '../law';\nimport type { VireGlassOptics } from '../material';\nimport {\n sceneDistance,\n sceneGradient,\n touchWarp,\n type MorphShape,\n type TouchWarp,\n} from '../sdf';\n\nexport type DisplacementMap = { url: string; width: number; height: number; scale: number };\n\n/** dp of rim displacement per dp of size-adjusted thickness, at full refraction strength (ior →\n * 1.6). Tuned so the product default (V5: ior 1.5, thickness 28dp) lands well under `MAX_SCALE`\n * before it's ever clamped — the ceiling below is what actually limits denser glass. */\nconst SCALE_GAIN = 0.75;\n\n/**\n * `feDisplacementMap` displaces by `scale * (channel / 255 - 0.5)`: a full channel swing spans\n * ±scale/2, and one 8-bit step is `scale/255` px — not `scale/127`, which an earlier version of\n * this file assumed and which rendered every material at half its derived refraction.\n *\n * Measured in Chromium on 2026-09-19: at scale 40 (0.157 px/step) a high-contrast edge visibly\n * terraces; at scale 12 (0.047 px/step) it does not. The ceiling sits between them and nearer\n * the clean end — thick, high-index glass is flattened to it instead of its derived scale,\n * trading rim depth for an edge without stairs.\n */\nconst MAX_STEP_PX = 0.09;\nconst MAX_SCALE = 255 * MAX_STEP_PX;\n\n/**\n * Samples across the bevel band, which is the only place the map carries anything. Everything\n * inside it is a constant, and `feImage` stretches whatever it is given over the element anyway,\n * so resolving the element is wasted work: a sheet at device resolution is 197 000 pixels of\n * per-pixel maths and a PNG encode, 120 ms on attach and far past a frame during interaction.\n *\n * Eight samples describe a profile that is smooth by construction. The measured cost falls with\n * the square of the reduction, and `check:dom` measures the displacement afterwards to say\n * whether anything was lost.\n */\nconst BEVEL_SAMPLES = 8;\n\n/** Resolution the map is built at: enough to resolve the bevel, never more than the element. */\nfunction mapDensity(geometry: VireGlassGeometry, bevel: number, dpr: number): number {\n if (bevel <= 0) return dpr;\n return Math.min(dpr, BEVEL_SAMPLES / bevel);\n}\n\n/** True neutral is the unrepresentable 127.5; 128 is the nearest byte and leaves a residual\n * 0.002 of the scale, far below one step and below a pixel at any usable scale. */\nfunction encode(displacement: number, scale: number): number {\n const channel = Math.round(255 * (displacement / scale + 0.5));\n return channel < 0 ? 0 : channel > 255 ? 255 : channel;\n}\n\n/** Mirrors the shader's `vgBevelSlope`, renormalized into 0..1: curvature concentrated at the\n * rim, the middle left flat. A plain linear ramp from `vgBevelT` alone reads as a chamfer, not a\n * lens — the same reason the shader doesn't use it raw either. */\nfunction bevelProfile(t: number): number {\n const raw = Math.min(t / Math.sqrt(Math.max(1 - t * t * BEVEL.sphere, BEVEL.floor)), BEVEL.slopeMax);\n return raw / BEVEL.slopeMax;\n}\n\nexport type DisplacementState = {\n /** Finger response (docs/reference.md §5): the field around the touch deforms, so the silhouette\n * the backdrop bends along deforms with it. */\n touch?: TouchWarp;\n /** Smooth-union neighbours (§5): shapes merging into one and splitting apart. */\n smoothing?: number;\n morph?: MorphShape;\n morph2?: MorphShape;\n /** Any number of shapes flowing into this one. `morph`/`morph2` are the first two, kept so a\n * caller that only ever had two does not have to change. */\n morphs?: readonly MorphShape[];\n};\n\n/**\n * The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.\n * `buildDisplacementMap` below is a thin DOM wrapper around this.\n *\n * Encoding: R = x offset, G = y offset, 128 = no shift, one step = `scale/255` px; B = 128\n * (unused), A = 255 (opaque, `feImage` would otherwise composite the map against page black).\n * The offset points INWARD — the rim samples the backdrop from inside the shape, a convex thick\n * lens. Displacement lives only in the bevel band (`bevelDp`); the flat middle is exactly 128/128.\n */\nexport function renderDisplacementPixels(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n state: DisplacementState = {},\n): { data: Uint8ClampedArray; width: number; height: number; scale: number } {\n const bevel = bevelDp(geometry, optics);\n const density = mapDensity(geometry, bevel, dpr);\n const width = Math.max(1, Math.round(geometry.width * density));\n const height = Math.max(1, Math.round(geometry.height * density));\n const rawScale = optics.refraction * thicknessDp(geometry, optics) * SCALE_GAIN;\n const scale = Math.min(rawScale, MAX_SCALE);\n const smoothing = state.smoothing ?? 0;\n // One list, whichever way the caller expressed it.\n const shapes: (MorphShape | undefined)[] = [state.morph, state.morph2, ...(state.morphs ?? [])];\n\n const data = new Uint8ClampedArray(width * height * 4);\n const halfW = geometry.width / 2;\n const halfH = geometry.height / 2;\n\n for (let py = 0; py < height; py += 1) {\n const y = (py + 0.5) / density - halfH;\n for (let px = 0; px < width; px += 1) {\n const x = (px + 0.5) / density - halfW;\n const i = (py * width + px) * 4;\n // Warp the FIELD first, then read the scene at the warped point — the shader's own order.\n const [wx, wy] = state.touch ? touchWarp(x, y, state.touch) : [x, y];\n const sd = sceneDistance(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);\n const t = Math.min(Math.max((sd + bevel) / bevel, 0), 1);\n if (t <= 0 || scale <= 0) {\n data[i] = 128;\n data[i + 1] = 128;\n data[i + 2] = 128;\n data[i + 3] = 255;\n continue;\n }\n const [gx, gy] = sceneGradient(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);\n // The rim reaches half the scale: the encoding can only span ±scale/2, so the derived\n // displacement is expressed as a fraction of that half-range.\n const magnitude = bevelProfile(t) * (scale / 2);\n const dx = -gx * magnitude;\n const dy = -gy * magnitude;\n // Inverse of the spec's own formula: channel = 255 * (displacement / scale + 0.5).\n data[i] = encode(dx, scale);\n data[i + 1] = encode(dy, scale);\n data[i + 2] = 128;\n data[i + 3] = 255;\n }\n }\n\n return { data, width, height, scale };\n}\n\nfunction hasCanvasSupport(): boolean {\n return typeof document !== 'undefined' && typeof document.createElement === 'function';\n}\n\n/** Builds the map at device-pixel resolution so it stays sharp once the browser stretches it back\n * over the element's CSS-px box (`feImage` fills the filter region regardless of source size). */\nexport function buildDisplacementMap(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n state: DisplacementState = {},\n): DisplacementMap {\n if (!hasCanvasSupport()) {\n throw new Error('vireglass/dom: buildDisplacementMap requires a DOM (canvas)');\n }\n const { data, width, height, scale } = renderDisplacementPixels(optics, geometry, dpr, state);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('vireglass/dom: 2D canvas context unavailable');\n const imageData = ctx.createImageData(width, height);\n imageData.data.set(data);\n ctx.putImageData(imageData, 0, 0);\n return { url: canvas.toDataURL('image/png'), width, height, scale };\n}\n","// The spectral edge (docs/reference.md §1). Dispersion, diffraction and interference are ONE\n// cause — a dependence on wavelength — and one hue multiplier, normalised to its own mean, so they\n// colour what passes through without brightening it.\n//\n// JS twins of the lens shader's `vgInterference`, `vgDiffraction` and the rim profile they read\n// from. Same reason as the SDF's twins: the DOM path needs this geometry as numbers, and a second\n// version that drifts is the defect the parity gate exists for.\nimport { LENS, SPECTRAL } from './law';\n\nconst TAU = 6.28318530718;\nconst LAMBDA: readonly [number, number, number] = [LENS.lambdaR, LENS.lambdaG, LENS.lambdaB];\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/** Normalises a triple to its own mean — the step that makes these hues rather than gains. */\nfunction toHue(v: [number, number, number]): [number, number, number] {\n const mean = Math.max((v[0] + v[1] + v[2]) / 3, 0.001);\n return [v[0] / mean, v[1] / mean, v[2] / mean];\n}\n\n/** Mirrors `vgRimQd`: the derivative of the rim's height profile. */\nexport function rimSlopeCurve(x: number): number {\n const k = 1 - clamp01(x);\n return (k * k * k) / Math.pow(Math.max(1 - k * k * k * k, 1e-5), 0.75);\n}\n\n/** Mirrors `vgSlope`: the top face's slope at distance `e` inside the silhouette. */\nexport function surfaceSlope(e: number, bevel: number, rim: number, thick: number): number {\n if (e >= bevel || bevel <= 0) return 0;\n return Math.min(((thick - rim) / bevel) * rimSlopeCurve(e / bevel), LENS.slopeMax);\n}\n\n/** The normal's z, which is what both spectral terms are measured against. `N = normalize([n·s, 1])`\n * in the shader, so its z is simply the slope resolved back to unit length. */\nexport function surfaceCosine(slope: number): number {\n return 1 / Math.sqrt(1 + slope * slope);\n}\n\n/** Thin-film interference: optical path difference 2·n·d·cosθt, each channel with its own λ. */\nexport function interference(cosI: number, filmNm: number): [number, number, number] {\n const sinT2 = (1 - cosI * cosI) / (LENS.filmIor * LENS.filmIor);\n const cosT = Math.sqrt(Math.max(1 - sinT2, 0));\n const opd = 2 * LENS.filmIor * filmNm * cosT;\n return toHue([\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[0] + Math.PI),\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[1] + Math.PI),\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[2] + Math.PI),\n ]);\n}\n\n/** Edge diffraction: fringes get denser as the bevel sharpens. A hue, not a brightness. */\nexport function diffraction(distFromEdge: number, bevel: number): [number, number, number] {\n const phase = (TAU * SPECTRAL.diffractionFringes * distFromEdge) / Math.max(bevel, 1);\n const f = (lambda: number) => 0.5 + 0.5 * Math.cos((phase * SPECTRAL.referenceLambda) / lambda);\n return toHue([f(LAMBDA[0]), f(LAMBDA[1]), f(LAMBDA[2])]);\n}\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n const t = clamp01((x - edge0) / (edge1 - edge0));\n return t * t * (3 - 2 * t);\n}\n\n/**\n * Both terms at one point, weighted as the lens weights them: interference by `iridescence` across\n * the bevel, diffraction by its own strength but only within `diffractionOnset` of the silhouette.\n *\n * `e` is the distance inside the edge; everything else comes from the resolved optics.\n */\nexport function spectralHue(\n e: number,\n bevel: number,\n rim: number,\n thick: number,\n optics: { film: number; iridescence: number; diffraction: number },\n): [number, number, number] {\n let r = 1;\n let g = 1;\n let b = 1;\n\n // `t` is 1 at the silhouette and 0 at the inner edge of the bevel, as below.\n const t = 1 - clamp01(bevel > 0 ? e / bevel : 1);\n\n if (optics.iridescence > 0.001) {\n // Windowed to the edge, for the same reason diffraction is: §2 puts the iridescence on the\n // opposing arc, and an arc is at the silhouette. Unwindowed, the surface angle stops changing a\n // third of the way in and the film paints the rest of the bevel one flat colour.\n const w = optics.iridescence * smoothstep(SPECTRAL.iridescenceOnset, 1, t);\n if (w > 0) {\n const cosI = clamp01(surfaceCosine(surfaceSlope(e, bevel, rim, thick)));\n const i = interference(cosI, optics.film);\n r += (i[0] - 1) * w;\n g += (i[1] - 1) * w;\n b += (i[2] - 1) * w;\n }\n }\n\n if (optics.diffraction > 0.001) {\n // The fringes live at the outer end of the bevel, which is what makes this an EDGE effect\n // rather than a sheen over it.\n const w = optics.diffraction * smoothstep(SPECTRAL.diffractionOnset, 1, t);\n if (w > 0) {\n const d = diffraction(e, bevel);\n r += (d[0] - 1) * w;\n g += (d[1] - 1) * w;\n b += (d[2] - 1) * w;\n }\n }\n\n return [r, g, b];\n}\n","// The spectral edge, baked into an image (docs/reference.md §1).\n//\n// Diffraction and interference are hue multipliers that vary per pixel across the bevel, and an\n// SVG filter has no way to evaluate a function per pixel. But it can MULTIPLY by an image:\n// `feComposite operator=\"arithmetic\"` with k1 set is a product, so the hue can be baked and\n// applied in one pass.\n//\n// The multiplier exceeds 1 wherever a channel is boosted, and eight bits cannot carry that, so the\n// map stores the hue divided by a headroom the filter multiplies back. Without the headroom every\n// boosted channel would clip to white and the fringes would read as a bright rim rather than a\n// coloured one.\nimport { bevelDp, rimDp, thicknessDp, type VireGlassGeometry } from '../geometry';\nimport type { VireGlassOptics } from '../material';\nimport { sdfRoundedRect } from '../sdf';\nimport { spectralHue } from '../spectral';\n\nexport type SpectralMap = { url: string; width: number; height: number; headroom: number };\n\n/** A hue normalised to its own mean cannot exceed the number of channels; in practice it stays\n * well under two. Two is the smallest headroom that never clips. */\nconst HEADROOM = 2;\n\n/**\n * The hue map is sampled like the displacement map — across the bevel, not across the element. It\n * needs MORE samples than the displacement does, because fringes oscillate where the displacement\n * is monotonic, and undersampling a fringe pattern aliases it into a different one.\n */\nconst BEVEL_SAMPLES = 24;\n\nfunction mapDensity(bevel: number, dpr: number): number {\n if (bevel <= 0) return dpr;\n return Math.min(dpr, BEVEL_SAMPLES / bevel);\n}\n\nexport function renderSpectralPixels(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n): { data: Uint8ClampedArray; width: number; height: number; headroom: number } {\n const bevel = bevelDp(geometry, optics);\n const density = mapDensity(bevel, dpr);\n const width = Math.max(1, Math.round(geometry.width * density));\n const height = Math.max(1, Math.round(geometry.height * density));\n const rim = rimDp(geometry, optics);\n const thick = thicknessDp(geometry, optics);\n\n const data = new Uint8ClampedArray(width * height * 4);\n const halfW = geometry.width / 2;\n const halfH = geometry.height / 2;\n const neutral = Math.round((1 / HEADROOM) * 255);\n\n for (let py = 0; py < height; py += 1) {\n const y = (py + 0.5) / density - halfH;\n for (let px = 0; px < width; px += 1) {\n const x = (px + 0.5) / density - halfW;\n const i = (py * width + px) * 4;\n const sd = sdfRoundedRect(x, y, geometry.width, geometry.height, geometry.cornerRadius);\n const e = Math.max(-sd, 0);\n if (e >= bevel) {\n // Past the bevel the glass is plain: a neutral multiplier, not a missing one.\n data[i] = neutral;\n data[i + 1] = neutral;\n data[i + 2] = neutral;\n data[i + 3] = 255;\n continue;\n }\n const [r, g, b] = spectralHue(e, bevel, rim, thick, optics);\n data[i] = Math.round((r / HEADROOM) * 255);\n data[i + 1] = Math.round((g / HEADROOM) * 255);\n data[i + 2] = Math.round((b / HEADROOM) * 255);\n data[i + 3] = 255;\n }\n }\n\n return { data, width, height, headroom: HEADROOM };\n}\n\n/** Whether this material has a spectral edge at all. Three extra filter primitives and a per-pixel\n * bake are not worth paying for a multiplier that is flat 1. */\nexport function hasSpectralEdge(optics: VireGlassOptics): boolean {\n return optics.iridescence > 0.001 || optics.diffraction > 0.001;\n}\n\nexport function buildSpectralMap(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n): SpectralMap {\n if (typeof document === 'undefined' || typeof document.createElement !== 'function') {\n throw new Error('vireglass/dom: buildSpectralMap requires a DOM (canvas)');\n }\n const { data, width, height, headroom } = renderSpectralPixels(optics, geometry, dpr);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('vireglass/dom: 2D canvas context unavailable');\n const image = ctx.createImageData(width, height);\n image.data.set(data);\n ctx.putImageData(image, 0, 0);\n return { url: canvas.toDataURL('image/png'), width, height, headroom };\n}\n","// Maps are pure functions of geometry, optics and density — the same element twice, or four\n// identical buttons in a tab bar, produce byte-identical PNGs. Building each one again is the\n// single largest avoidable cost in this renderer: a sheet's hue map is tens of milliseconds, and\n// it happens on every attach, every remount and every re-attach after a theme change.\n//\n// Small and strict on purpose. A page has a handful of distinct glass shapes, not hundreds; a\n// cache that grew without bound would hold megabytes of data URIs alive for a screen nobody is\n// looking at any more.\nconst LIMIT = 24;\n\nconst store = new Map<string, unknown>();\n\nexport function cached<T>(key: string, build: () => T): T {\n const hit = store.get(key);\n if (hit !== undefined) {\n // Re-inserting moves it to the end: the oldest key is the one evicted, not the most used one.\n store.delete(key);\n store.set(key, hit);\n return hit as T;\n }\n const value = build();\n store.set(key, value);\n if (store.size > LIMIT) {\n const oldest = store.keys().next();\n if (!oldest.done) store.delete(oldest.value);\n }\n return value;\n}\n\n/** Test-only: the cache is process-wide, and a suite that measures build cost needs it cold. */\nexport function clearMapCache(): void {\n store.clear();\n}\n\nexport function mapCacheSize(): number {\n return store.size;\n}\n","// Deriving optics from the medium's properties. The material describes CAUSES (index of\n// refraction, thickness, bevel, roughness); the shaders need EFFECTS — this file translates one\n// into the other. Pure functions: the physics is checked by tests, not on a device.\n//\n// The normalisations themselves are in `law.ts` under DERIVE, with the rest of the calibration.\n// They are honestly labelled there: the rendering is stylised, and literal physical values (glass\n// reflects 4% at normal incidence) produce effects right at the threshold of visibility. Each is\n// monotonic in its own cause, so \"denser medium → more visible rim\" always holds, and no\n// impossible combination can arise.\nimport { DERIVE } from './law';\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\nconst clamp01 = (v: number) => clamp(v, 0, 1);\n\n/** Reflectance at normal incidence: ((n−1)/(n+1))². For glass, n=1.5 gives 0.04. */\nexport const fresnelF0 = (ior: number) => ((ior - 1) / (ior + 1)) ** 2;\n\nexport const fresnelStrength = (ior: number) => clamp01(fresnelF0(ior) * DERIVE.fresnelGain);\n\n/** Exponent in the Schlick approximation — a constant of the model, not a knob. */\nexport const FRESNEL_EXPONENT = DERIVE.fresnelExponent;\n\n/** Strength of ray bending. As n→1 the medium is indistinguishable from air; n=1.6 is taken as\n * full strength. */\nexport const refractionStrength = (ior: number) => clamp01((ior - 1) / DERIVE.iorFullBend);\n\nexport const refractionScale = (ior: number, thicknessDp: number) =>\n 1 + DERIVE.magnifyPerDp * thicknessDp * (1 - 1 / Math.max(ior, 1));\n\nexport const dispersion = (ior: number) => clamp01((ior - 1) * DERIVE.dispersionPerIor);\n\nexport const iorSpread = (ior: number) => dispersion(ior) * DERIVE.iorSpreadPerDispersion;\n\nexport const absorption = (pathDp: number) =>\n 1 - Math.exp(-DERIVE.absorbPerDp * Math.max(pathDp, 0));\n\n/**\n * Density at the bevel relative to the body. Not a separate quantity: at the rim the ray travels\n * LONGER through the medium by the bevel's width, and absorption over that path is greater. This\n * used to be a separate `edgeDensity` slider, which is how a thin bevel with a milky rim got\n * built — a state that doesn't occur in real glass.\n */\nexport const edgeDensity = (thicknessDp: number, bevelDp: number) => {\n const body = absorption(thicknessDp);\n if (body <= 0) return 1;\n return clamp(absorption(thicknessDp + bevelDp) / body, 1, DERIVE.edgeDensityMax);\n};\n\n/**\n * Backdrop haziness — surface roughness, not a separate blur setting.\n *\n * The ceiling is deliberately low. Blur in this model is a SUPPORTING device: it helps ink sit\n * over glass, but doesn't improve the picture on its own. Past roughly a dozen dp, letters under\n * the glass stop being letters and turn into a mush of pixels — no amount of legibility justifies\n * that. Separating content from the ink is body density's job, not blur's.\n */\nexport const blur = (roughness: number) => clamp01(roughness) * DERIVE.blurMaxDp;\n\n/** A smooth surface gives a narrow highlight, a rough one a spread-out one. */\nexport const specularPower = (roughness: number) =>\n DERIVE.specularPowerSmooth -\n clamp01(roughness) * (DERIVE.specularPowerSmooth - DERIVE.specularPowerRough);\n\n/** Highlight brightness — the same reflectance as Fresnel, damped by roughness. */\nexport const specularStrength = (ior: number, roughness: number) =>\n clamp01(fresnelStrength(ior) * (1 - clamp01(roughness) * DERIVE.specularRoughDamping));\n\n/**\n * Color of the medium. Never set by hand: in transparent media, hue is tied to density. Water\n * absorbs red and skews cool, ordinary glass is nearly neutral with a faint green, dense\n * high-index media skew warm. Lightness follows reflectance: the denser the medium, the more of\n * its surroundings it returns, and the lighter its body reads.\n */\ntype Hue = readonly [number, number, number];\nconst mixHue = (a: Hue, b: Hue, t: number): Hue => [\n a[0] + (b[0] - a[0]) * t,\n a[1] + (b[1] - a[1]) * t,\n a[2] + (b[2] - a[2]) * t,\n];\n\nexport function mediumTint(ior: number): { r: number; g: number; b: number } {\n const t = clamp01((ior - DERIVE.hueFromIor) / DERIVE.hueSpan);\n const hue =\n t < 0.5\n ? mixHue(DERIVE.hueCool, DERIVE.hueNeutral, t * 2)\n : mixHue(DERIVE.hueNeutral, DERIVE.hueWarm, (t - 0.5) * 2);\n const lift = DERIVE.bodyLiftBase + fresnelF0(ior) * DERIVE.bodyLiftPerF0;\n return { r: clamp01(hue[0] * lift), g: clamp01(hue[1] * lift), b: clamp01(hue[2] * lift) };\n}\n\n/**\n * How far the rim gathers light AROUND the element.\n *\n * On real glass, at a grazing angle the eye receives not what's under the glass but the\n * surroundings: an object on a black table next to a lamp catches the lamp. So the radius is\n * noticeably larger than the bevel — it's the element's vicinity, not its rim. Without this,\n * glass on an empty black background has no source at all and honestly disappears.\n */\n/**\n * Ceiling on the radius. Without it, a wide bevel would gather its surroundings from fifty-odd dp\n * away, and a READABLE copy of whatever sits nearby would appear inside the glass: eight samples\n * aren't enough to blur a disc that large (E-33, E-37). Real rims also gather light mostly from\n * nearby — an unbounded radius was a modeling mistake.\n */\nexport const gatherRadius = (bevelDp: number) =>\n clamp(Math.max(bevelDp, 1) * DERIVE.gatherPerBevel, DERIVE.gatherMinDp, DERIVE.gatherMaxDp);\n\n/**\n * The body's own density from absorption through its thickness. Small: glass has no color of its\n * own, the body only moves toward the tint under the legibility requirement (HIG \"Color\"),\n * otherwise it dims the content.\n */\nexport const bodyDensity = (thicknessDp: number) =>\n DERIVE.bodyDensity * absorption(thicknessDp);\n\n/**\n * Highlight normalization. `fresnelStrength`'s ×17.5 factor is tuned for the rim highlight's\n * visibility and saturates at one for dense media; applying it to the highlight too would raise\n * body lightness harder than the glass had just separated it from the ink — eating its own\n * legibility work. This uses the physical scale instead.\n */\n/** How much the rim picks up the light and color of its surroundings. The same reflectance as\n * Fresnel: no separate knob — a dense medium returns more of its surroundings by construction. */\n\nexport const edgeLight = (ior: number) => clamp01(fresnelF0(ior) * DERIVE.edgeLightGain);\n\n/**\n * THE SPECTRAL PART. Three phenomena — dispersion, diffraction and interference — share one\n * cause: index of refraction and phase both depend on wavelength. So there are no separate\n * \"rainbow strength\" knobs here: everything is derived from the medium's density and film\n * thickness.\n */\n\n/**\n * Rim iridescence is visible exactly as much as the REFLECTION is bright: interference lives in\n * the reflected ray, not the transmitted one. Hence the tie to Fresnel — there's no strength knob\n * of its own.\n */\nexport const iridescence = (ior: number, filmNm: number) =>\n filmNm <= 0 ? 0 : clamp01(fresnelStrength(ior) * DERIVE.iridescencePerFresnel);\n\n/**\n * Edge diffraction. Same λ-dependence as dispersion, so it shares its strength; the bevel sets\n * the fringe frequency — wide bevels give sparse fringes, sharp ones frequent (in the shader this\n * is divided by bevel width). The 0.5 normalization reflects the stylized render: at the physical\n * amplitude the fringes aren't visible at all.\n */\nexport const diffraction = (ior: number) =>\n clamp01(dispersion(ior) * DERIVE.diffractionPerDispersion);\n\n/**\n * How much the body picks up the COLOR of its surroundings. This is multiple internal reflection:\n * the denser the medium, the more light it circulates inside itself, and the more strongly it's\n * tinted by what's around it. The ceiling is deliberately low — the tint has to stay a medium, not\n * become a flat color fill.\n */\nexport const colorPickup = (ior: number) =>\n clamp(fresnelStrength(ior) * DERIVE.colorPickupPerFresnel, 0, DERIVE.colorPickupMax);\n","// VireGlass material model.\n//\n// Two distinct objects, and they must not be confused:\n//\n// VireGlassMaterial — CAUSES. What a piece of glass is described by: index of refraction,\n// thickness, bevel width, roughness, absorption color. This is what gets\n// configured.\n// VireGlassOptics — EFFECTS. Eighteen values the shaders need. Not configured: they're\n// derived (`resolveOptics`, physics in `optics.ts`).\n//\n// Before v4, what was exposed were the effects themselves — eighteen independent sliders. Half of\n// them are physically dependent, so combining them produced states that don't occur in real\n// glass: a thin bevel with a dense white rim, rim optics as a fraction of the element's own size.\n// Every such case was patched by adding yet another slider (`edgeDensity`, a size compensation) —\n// that is, compensating for physics that wasn't there. Here there's one cause, and the effects\n// are derived.\n\nimport {\n absorption,\n blur as blurFrom,\n dispersion as dispersionFrom,\n edgeDensity as edgeDensityFrom,\n gatherRadius as gatherRadiusFrom,\n fresnelStrength,\n FRESNEL_EXPONENT,\n mediumTint,\n refractionScale as refractionScaleFrom,\n refractionStrength,\n specularPower as specularPowerFrom,\n bodyDensity as bodyDensityFrom,\n edgeLight as edgeLightFrom,\n iridescence as iridescenceFrom,\n diffraction as diffractionFrom,\n colorPickup as colorPickupFrom,\n specularStrength,\n iorSpread as iorSpreadFrom,\n} from './optics';\n\nexport type VireGlassTint = { r: number; g: number; b: number };\n\nexport type VireGlassMaterial = {\n /** Index of refraction of the medium. Water 1.33, glass 1.5, sapphire 1.77. */\n ior: number;\n /** Glass thickness, dp. Drives center magnification and absorption. */\n thickness: number;\n /** Bevel width, dp. Absolute: on real glass the rim doesn't depend on the piece's size. */\n bevel: number;\n /** Surface roughness: backdrop haziness and highlight blur. */\n roughness: number;\n /** Response to device orientation, 0 means the light is locked to the screen. */\n environment: number;\n /** Not physics but a legibility requirement: how strongly the glass has to separate its own\n * lightness from the ink drawn over it. 0 means the glass is simply transparent. */\n legibility: number;\n /** Dimming layer UNDER the glass, 0..1. For the transparent (Clear) variant this is what\n * provides legibility: that glass has no adaptation, and without dimming the ink drowns over\n * bright content.\n *\n * Not to be confused with the mobile surface's `dim` prop: that one compensates for a platform\n * capture quirk (BlurView can't see a scrim drawn over the content), while this is a property\n * of the material itself. */\n dimming: number;\n /** Lightness of what the app draws OVER the glass: 1 is light icons and text, 0 is dark. A\n * cause, not a knob: the calling screen knows it. */\n ink: number;\n /** Minimum PRESENCE of the element itself: how far its body must stand off in lightness from\n * the backdrop behind it. Not the same as `legibility` — that's about the ink OVER the glass,\n * this is about the element itself. Over a uniform backdrop the glass has nothing to refract,\n * and the element disappears; for a control that's unacceptable. 0 means no presence is\n * required.\n *\n * The sign is taken FROM THE BACKDROP, not from ink polarity: over dark the body lightens,\n * over light it darkens. So the requirement works the same way on any backdrop. */\n presence: number;\n /** Surface film thickness, nm. This is where interference comes from: the optical path\n * difference in the film becomes comparable to the wavelength, and the reflection picks up\n * iridescence. 0 means no film. */\n film: number;\n};\n\nexport const MATERIAL_RANGES = {\n ior: [1, 2],\n thickness: [0, 60],\n bevel: [0, 40],\n roughness: [0, 1],\n environment: [0, 1],\n legibility: [0, 1],\n dimming: [0, 0.5],\n ink: [0, 1],\n presence: [0, 0.6],\n film: [0, 900],\n} as const satisfies Record<string, readonly [number, number]>;\n\nexport type VireGlassNumericKey = keyof typeof MATERIAL_RANGES;\n\n/** Radius over which the LOCAL backdrop lightness is taken, dp. Not per-pixel: otherwise the\n * glass chases individual strokes and a halo appears around letters beneath it. */\nexport const ADAPT_RADIUS = 22;\n\n/** Lens dimming on product surfaces — a flat fill over the backdrop. */\nexport const PRODUCT_DIM = 0.2;\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\n\n/** The values the shaders need. Assembled from the material, never set by hand. */\nexport type VireGlassOptics = {\n blur: number;\n refraction: number;\n refractionScale: number;\n /** Bevel width in dp — an absolute property of the medium. */\n bevelDp: number;\n /** Radius over which the rim gathers light around the element. */\n gatherRadiusDp: number;\n fresnel: number;\n fresnelPower: number;\n specular: number;\n specularPower: number;\n dispersion: number;\n tint: VireGlassTint;\n tintStrength: number;\n edgeDensity: number;\n environment: number;\n legibility: number;\n /** Dimming of the content under the glass — the very layer of the Clear variant. */\n dimming: number;\n ink: number;\n /** Minimum presence of the element against the backdrop — in units of lightness. */\n presence: number;\n adaptRadius: number;\n bodyDensity: number;\n edgeLight: number;\n /** Film thickness, nm — passed straight to the shader: the path difference is computed in the\n * same units. */\n film: number;\n /** Strength of reflection iridescence. */\n iridescence: number;\n /** Strength of the edge diffraction fringes. */\n diffraction: number;\n /** How much the body is tinted by the color of its surroundings. */\n colorPickup: number;\n /** Index of refraction: the shader computes ray bending from it via Snell's law. */\n ior: number;\n /** Plate thickness, dp — before the correction for element size. */\n thicknessDp: number;\n /** Spread of the index between the red and blue channels — dispersion. */\n iorSpread: number;\n};\n\n// The product default — \"water\": lower index of refraction, thinner medium and bevel, an almost\n// smooth surface. Chosen on-device at the bench.\nexport const VIREGLASS_MATERIAL_V4: VireGlassMaterial = {\n ior: 1.33,\n thickness: 14,\n bevel: 5,\n roughness: 0.05,\n environment: 0.27,\n legibility: 0.26,\n dimming: 0,\n ink: 1,\n presence: 0.05,\n film: 340,\n};\n\n\n/**\n * Glass, not water. v4's index of refraction, 1.33, is water: almost no reflection at the rim,\n * almost no dispersion, 2% magnification. On screen that surface honestly reads as \"nothing much\",\n * and it was being mistaken for glass that wasn't rendering at all.\n *\n * 1.5 is ordinary glass. The effects follow from it on their own: reflection at the rim twice as\n * strong, dispersion one and a half times, ambient color pickup at its ceiling. Thickness is\n * raised a little too: it drives magnification, but absorption comes along with it, and\n * absorption is blackness.\n */\nexport const VIREGLASS_MATERIAL_V5: VireGlassMaterial = {\n ior: 1.5,\n thickness: 28,\n bevel: 6,\n roughness: 0.06,\n environment: 0.27,\n legibility: 0.26,\n dimming: 0,\n ink: 1,\n presence: 0.05,\n film: 340,\n};\n\n/**\n * Frosted sheet glass. The sheet sits over a LIVE screen, and it can't be transparent: transport\n * buttons and progress used to read right through it — the layout looked broken. Dimming doesn't\n * fix this (a flat scrim over a sharp picture doesn't hide it), so roughness is raised instead: it\n * drives `u_frost`, a floor on backdrop blur that the adaptive-blur ceiling doesn't reach.\n */\nexport const VIREGLASS_SHEET_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n roughness: 0.85,\n};\n/** The product's material. Consumers use this, not a specific version by name. */\n/**\n * Glass under large text (the lyrics panel in the player).\n *\n * The product material with NO change to optics — only `legibility` is raised. That's exactly its\n * reason to exist: \"text on me must stay readable.\" It adds density locally — denser over light\n * and busy backdrops, more transparent over an even dark one.\n *\n * A dedicated thick material (thickness 52, ior 1.58) used to sit here and was removed: medium\n * absorption grows with thickness, and the panel picked up a black fringe around its perimeter —\n * a sooty plate instead of glass. Don't turn thickness into a legibility knob; that's what\n * `legibility` is for.\n */\nexport const VIREGLASS_LYRICS_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n legibility: 0.95,\n};\n\n/**\n * Glass for controls — buttons, tiles, anything that gets pressed.\n *\n * THICK AND CLEAR, not the baseline: wider bevel, thickness up by half, higher index of\n * refraction and almost no roughness. Baseline glass is a lens over a calm backdrop; a control has\n * to read as an object you can pick up, and that's not done by a fill but by volume: a wide bevel\n * gives the rim something to catch, and thickness gives it depth.\n *\n * Thickness is set by BUILDUP AT THE RIM: on the reference control the stripe image under the\n * element bulges there by a factor of 1.85; ours came out at 1.36 at 30. Saturation sets in around\n * 44, and any extra thickness past that only adds absorption — hence 44, not more.\n *\n * It also drags `tintStrength` (= `absorption(thickness)`) along with it, and on the path WITHOUT\n * a native lens that sets body density: there the element is denser by 2.4 percentage points. On\n * the web the surface has no body at all; the effect only shows on Android below 13.\n *\n * `presence` is raised for the same reason: a piece of background is allowed to disappear over a\n * uniform canvas, a control isn't — it has to be visible before it's been tapped.\n *\n * IMPORTANT about size. The bevel is specified by the medium in dp and doesn't depend on the\n * element's size, but the geometry clamps it to half the smaller half-size (`MAX_BEVEL_FRACTION`).\n * On a 52 dp button that's 13 instead of 16 — a small element made of this glass ends up being\n * bevel all the way through. That's by design: a small piece of thick glass is supposed to look\n * like a lens, not a slab.\n */\nexport const VIREGLASS_CONTROL_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n ior: 1.69,\n thickness: 44,\n bevel: 8,\n roughness: 0.035,\n presence: 0.176,\n};\n\nexport const VIREGLASS_MATERIAL = VIREGLASS_MATERIAL_V5;\n\n/**\n * An element that CARRIES app ink (an icon, a line of text, cover art) has to keep it legible —\n * that's the reason `legibility` exists. An element with no ink has nothing to separate lightness\n * from, so the requirement is turned off for it: the model just promises it plain transparent\n * glass.\n *\n * The rule lives here, not with the consumer: otherwise the same icon button would get different\n * legibility on the web and on Android.\n */\nexport function materialForInk(material: VireGlassMaterial, carriesInk: boolean): VireGlassMaterial {\n // For the transparent variant, legibility is held by the dimming layer, not the body. Raising\n // its requirement would just turn it into ordinary glass, and the variants don't mix (219 §Clear).\n if (material.dimming > 0) return material;\n return { ...material, legibility: carriesInk ? VIREGLASS_LYRICS_MATERIAL.legibility : 0 };\n}\n\n/**\n * The transparent material variant (Clear). It has no adaptation — the glass stays consistently\n * more transparent, content beneath it shows through almost as-is, and legibility of the ink is\n * held by the dimming layer instead. Fit only where the reference's three conditions hold: the\n * element sits over media, the content can tolerate dimming, and the ink over it is large and\n * bright.\n */\nexport const VIREGLASS_CLEAR_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL,\n legibility: 0,\n presence: 0,\n // Apple's own numbers: 0.35 in the HIG Materials text, 0.3 in its own sample code. We take the\n // lower one — it comes from working code, not from prose, and Clear has to stay a window.\n dimming: 0.3,\n};\n\n/**\n * ACTIVE STATE as a state of the MEDIUM, not a highlight drawn over it.\n *\n * An active element is denser, clearer glass: higher index of refraction, thicker body, wider\n * bevel, less roughness. A bright rim, a strong highlight and greater presence all follow from\n * these causes on their own — assembling them separately would produce a state that doesn't occur\n * in real glass.\n *\n * `environment` is deliberately left untouched here. It sets how much the body is tinted by\n * what's beneath it, and at full strength an active button over cover art turned into a colored\n * blob: the state read as \"smudged\" rather than \"selected.\" A state indicator must not depend on\n * the backdrop — otherwise any image sliding underneath the element would fake it.\n */\nexport function activeMaterial(material: VireGlassMaterial, on: number): VireGlassMaterial {\n const k = Math.min(Math.max(on, 0), 1);\n return {\n ...material,\n ior: material.ior + 0.35 * k,\n thickness: material.thickness * (1 + 0.9 * k),\n bevel: material.bevel * (1 + 1.8 * k),\n roughness: material.roughness * (1 - 0.75 * k),\n presence: material.presence + 0.12 * k,\n };\n}\n\nexport function resolveMaterial(patch: Partial<VireGlassMaterial> = {}): VireGlassMaterial {\n const m = { ...VIREGLASS_MATERIAL, ...patch };\n const out = { ...m };\n for (const key of Object.keys(MATERIAL_RANGES) as VireGlassNumericKey[]) {\n const [lo, hi] = MATERIAL_RANGES[key];\n out[key] = clamp(out[key], lo, hi);\n }\n return out;\n}\n\n/** Causes → effects. All of the transition's physics lives in `optics.ts`. */\nexport function resolveOptics(patch: Partial<VireGlassMaterial> = {}): VireGlassOptics {\n const m = resolveMaterial(patch);\n return {\n blur: blurFrom(m.roughness),\n refraction: refractionStrength(m.ior),\n refractionScale: refractionScaleFrom(m.ior, m.thickness),\n bevelDp: m.bevel,\n gatherRadiusDp: gatherRadiusFrom(m.bevel),\n fresnel: fresnelStrength(m.ior),\n fresnelPower: FRESNEL_EXPONENT,\n specular: specularStrength(m.ior, m.roughness),\n specularPower: specularPowerFrom(m.roughness),\n dispersion: dispersionFrom(m.ior),\n tint: mediumTint(m.ior),\n tintStrength: absorption(m.thickness),\n edgeDensity: edgeDensityFrom(m.thickness, m.bevel),\n environment: m.environment,\n legibility: m.legibility,\n dimming: m.dimming,\n ink: m.ink,\n presence: m.presence,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: bodyDensityFrom(m.thickness),\n edgeLight: edgeLightFrom(m.ior),\n film: m.film,\n iridescence: iridescenceFrom(m.ior, m.film),\n diffraction: diffractionFrom(m.ior),\n colorPickup: colorPickupFrom(m.ior),\n ior: m.ior,\n thicknessDp: m.thickness,\n iorSpread: iorSpreadFrom(m.ior),\n };\n}\n\n/**\n * Frozen snapshots of the EFFECTS from the previous model. Kept as reference points until v4\n * settles: they can't be converted to causes — some of the values are internally inconsistent\n * (exactly why the move was made in the first place), and any \"equivalent\" material would be a\n * lie.\n */\nexport const LEGACY_OPTICS = {\n 'v3-manual': {\n blur: 4.32,\n refraction: 0.49,\n refractionScale: 1.05,\n bevelDp: 12.6,\n gatherRadiusDp: 40,\n fresnel: 0.77,\n fresnelPower: 2.86,\n specular: 0.3,\n specularPower: 74.58,\n dispersion: 0.54,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.35,\n edgeDensity: 1.5,\n environment: 0.27,\n legibility: 0.55,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n 'v2': {\n blur: 5,\n refraction: 0.95,\n refractionScale: 1.34,\n bevelDp: 14,\n gatherRadiusDp: 40,\n fresnel: 0.72,\n fresnelPower: 2.4,\n specular: 0.38,\n specularPower: 46,\n dispersion: 0.3,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.1,\n edgeDensity: 3.63,\n environment: 0,\n legibility: 0,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n 'v1': {\n blur: 12,\n refraction: 0.55,\n refractionScale: 1.14,\n bevelDp: 10,\n gatherRadiusDp: 40,\n fresnel: 0.5,\n fresnelPower: 3.2,\n specular: 0.42,\n specularPower: 58,\n dispersion: 0.22,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.16,\n edgeDensity: 3.63,\n environment: 0,\n legibility: 0,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n} as const satisfies Record<string, VireGlassOptics>;\n\nexport type LegacyOpticsName = keyof typeof LEGACY_OPTICS;\nexport const LEGACY_NAMES = Object.keys(LEGACY_OPTICS) as LegacyOpticsName[];\n\n/** Material presets: points in the space of CAUSES, not a set of ready-made effects. */\nexport const MATERIAL_PRESETS = {\n water: VIREGLASS_MATERIAL_V4,\n glass: { ...VIREGLASS_MATERIAL_V4, ior: 1.45, thickness: 25, bevel: 12.6, roughness: 0.17 },\n crystal: { ...VIREGLASS_MATERIAL_V4, ior: 1.7, thickness: 30, bevel: 16, roughness: 0.02 },\n frosted: { ...VIREGLASS_MATERIAL_V4, roughness: 0.55 },\n thick: { ...VIREGLASS_MATERIAL_V4, thickness: 48, bevel: 22 },\n thin: { ...VIREGLASS_MATERIAL_V4, thickness: 4, bevel: 3 },\n iridescent: { ...VIREGLASS_MATERIAL_V4, ior: 1.5, thickness: 8, bevel: 6, film: 620 },\n} as const satisfies Record<string, VireGlassMaterial>;\n\nexport type MaterialPresetName = keyof typeof MATERIAL_PRESETS;\nexport const PRESET_NAMES = Object.keys(MATERIAL_PRESETS) as MaterialPresetName[];\n\nexport const EFFECTS = [\n 'backdrop',\n 'blur',\n 'refraction',\n 'fresnel',\n 'bevel',\n 'specular',\n 'dispersion',\n 'tint',\n 'environment',\n 'legibility',\n 'interference',\n 'diffraction',\n] as const;\n\nexport type VireGlassEffect = (typeof EFFECTS)[number];\nexport type VireGlassToggles = Record<VireGlassEffect, boolean>;\n\nexport const ALL_EFFECTS_ON: VireGlassToggles = EFFECTS.reduce(\n (acc, e) => ({ ...acc, [e]: true }),\n {} as VireGlassToggles,\n);\n\n/**\n * A toggle zeroes out an EFFECT, it isn't a branch in the shader: the ON/OFF comparison runs on\n * one shader variant, otherwise two different programs would be getting compared. It operates on\n * optics, not on the material: a cause can't be zeroed out — it drags half a dozen effects along\n * with it. `backdrop` isn't handled by a toggle here: it decides whether to mount the BlurView at\n * all.\n */\nexport function applyToggles(\n optics: VireGlassOptics,\n toggles: Partial<VireGlassToggles> = {},\n): VireGlassOptics {\n const on = { ...ALL_EFFECTS_ON, ...toggles };\n const o = { ...optics, tint: { ...optics.tint } };\n if (!on.blur) o.blur = 0;\n if (!on.refraction) {\n o.refraction = 0;\n o.refractionScale = 1;\n o.ior = 1;\n }\n if (!on.fresnel) o.fresnel = 0;\n if (!on.bevel) o.bevelDp = 1;\n if (!on.specular) o.specular = 0;\n if (!on.dispersion) {\n o.dispersion = 0;\n o.iorSpread = 0;\n }\n if (!on.tint) o.tintStrength = 0;\n if (!on.environment) o.environment = 0;\n if (!on.legibility) {\n o.legibility = 0;\n // The dimming layer is the same answer to the legibility requirement, just for the\n // transparent variant.\n o.dimming = 0;\n }\n if (!on.interference) o.iridescence = 0;\n if (!on.diffraction) o.diffraction = 0;\n return o;\n}\n\n/** Order = the `u_debug` value in both shaders. Bench-only. */\nexport const DEBUG_MODES = [\n 'normal',\n 'sdf',\n 'mask',\n 'edge',\n 'fresnel',\n 'refraction',\n 'backdrop',\n 'specular',\n 'dispersion',\n 'normals',\n 'spectral',\n 'adapt',\n 'probe',\n] as const;\n\nexport type VireGlassDebugMode = (typeof DEBUG_MODES)[number];\n\nexport function debugIndex(mode: VireGlassDebugMode): number {\n return DEBUG_MODES.indexOf(mode);\n}\n","// Backdrop sample for the DOM renderer — the web-DOM counterpart to the WebGL downsample probe\n// (`web/probe.ts`) and the native capture on Android. The web canvas can read the pixels it just\n// drew; a page CANNOT read what's actually rendered behind an arbitrary element — that boundary\n// is the whole reason `backdrop-filter` exists as a browser primitive rather than a pixel API. So\n// this probes DECLARED STYLES instead: walk the stacking order under a grid of sample points and\n// read `background-color` (falling back to `color`) rather than any real pixel.\nimport type { BackdropSample } from '../adaptation';\n\n/** A modest grid: this runs on scroll, not per frame. `elementsFromPoint` walks the whole\n * stacking context at every sample point — a fine grid shows up in a profiler, a coarse one is\n * still plenty to tell \"flat\" from \"busy\" for the adaptation decision. */\nconst GRID_COLS = 5;\nconst GRID_ROWS = 5;\n\nexport type RgbColor = { r: number; g: number; b: number; a: number };\n\n/**\n * Parses `rgb()`/`rgba()` exactly as `getComputedStyle` emits them — every engine normalizes a\n * resolved color to one of these two forms, so there's nothing here worth a dependency for.\n * Returns `null` for anything else (a keyword that didn't resolve, a malformed value).\n */\nexport function parseColor(value: string): RgbColor | null {\n const match = /rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/i.exec(value);\n if (!match) return null;\n const r = Number(match[1]);\n const g = Number(match[2]);\n const b = Number(match[3]);\n const a = match[4] === undefined ? 1 : Number(match[4]);\n if (!Number.isFinite(r) || !Number.isFinite(g) || !Number.isFinite(b) || !Number.isFinite(a)) return null;\n return { r, g, b, a };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Same statistic the WebGL probe computes on its downsample grid (`web/probe.ts`, `rectStats`):\n * mean luma, twice the mean deviation for `busy`, 10th/90th percentile for `lo`/`hi`. A different\n * formula here would mean the ink-polarity decision quietly drifts between renderers on the same\n * page. `samples` are 0..255 per channel, matching what `parseColor` returns.\n */\nexport function statsFromSamples(samples: readonly RgbColor[]): BackdropSample {\n const n = samples.length;\n if (n === 0) return { luma: 0.5, busy: 0, lo: 0.5, hi: 0.5, r: 0.5, g: 0.5, b: 0.5 };\n\n const lumas: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n for (const s of samples) {\n const r = s.r / 255;\n const g = s.g / 255;\n const b = s.b / 255;\n lumas.push(luma(r, g, b));\n sr += r;\n sg += g;\n sb += b;\n }\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = Math.min((busy / n) * 2, 1);\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n return {\n luma: mean,\n busy,\n lo: percentile(0.1),\n hi: percentile(0.9),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\n/**\n * Composites a stack of backgrounds front to back, the way the compositor does.\n *\n * Taking the first layer with any alpha at all instead is wrong by a lot, not a little: a list row\n * tinted `rgba(255,255,255,0.028)` over a near-black page reads as pure WHITE, and the glass then\n * adapts to a backdrop that does not exist. That is most real interfaces.\n */\nexport function compositeLayers(layers: readonly RgbColor[]): RgbColor | null {\n let r = 0;\n let g = 0;\n let b = 0;\n let a = 0;\n for (const layer of layers) {\n const share = layer.a * (1 - a);\n if (share <= 0) continue;\n r += layer.r * share;\n g += layer.g * share;\n b += layer.b * share;\n a += share;\n if (a >= 0.999) break;\n }\n if (a <= 0.001) return null;\n // Normalised by coverage: what reached the eye, as an opaque colour. A stack that never became\n // opaque sits over the page's own background, which is the caller's floor layer.\n return { r: r / a, g: g / a, b: b / a, a };\n}\n\n/** Walks the stack at one point, skipping the glass element itself (it would otherwise probe its\n * own background) and its descendants. */\nfunction sampleColorAt(el: HTMLElement, x: number, y: number): RgbColor | null {\n const stack = document.elementsFromPoint(x, y);\n const behind = stack.filter((node) => node !== el && !el.contains(node));\n const layers: RgbColor[] = [];\n for (const node of behind) {\n const bg = parseColor(getComputedStyle(node).backgroundColor);\n // `rgba(0, 0, 0, 0)` is what \"transparent\" resolves to almost everywhere: it contributes\n // nothing and must not shadow a real colour further down.\n if (bg && bg.a > 0.001) layers.push(bg);\n }\n const composited = compositeLayers(layers);\n if (composited) return composited;\n return canvasColor(el);\n}\n\n/**\n * The page's own background — the floor everything else is composited over.\n *\n * Reached whenever nothing in the stack is opaque, which is not an edge case: CSS propagates the\n * body's background to the CANVAS, so `getComputedStyle` reports `<html>` and often `<body>` as\n * transparent on a perfectly ordinary white page. Any element past the end of the body's box —\n * a widget pinned to a corner, say — sees a stack of nothing.\n *\n * This used to fall back to the topmost element's `color`, which is its TEXT colour: a white page\n * with black text read as black, and the material dressed itself for a dark backdrop over a light\n * one. The propagation rule says where to look instead — the root element's background, then the\n * body's, then the user agent's white.\n */\nfunction canvasColor(el: HTMLElement): RgbColor | null {\n const doc = el.ownerDocument;\n for (const node of [doc.documentElement, doc.body]) {\n if (!node) continue;\n const bg = parseColor(getComputedStyle(node).backgroundColor);\n if (bg && bg.a > 0.001) return bg.a >= 0.999 ? bg : compositeLayers([bg, WHITE]);\n }\n return WHITE;\n}\n\n/** What a browser paints the canvas when nobody says otherwise. */\nconst WHITE: RgbColor = { r: 255, g: 255, b: 255, a: 1 };\n\nexport type ProbeOptions = {\n /** Grid density override — wider for a hero element, narrower for a tight control. */\n cols?: number;\n rows?: number;\n};\n\n/**\n * Backdrop sample for the glass element from its live surroundings, blind to images/video/canvas\n * by construction (the caller overrides with its own sample there — cover art already knows its\n * own accent; see `attachGlass`'s `sample` option).\n */\nexport function probeBackdrop(el: HTMLElement, opts: ProbeOptions = {}): BackdropSample {\n const cols = opts.cols ?? GRID_COLS;\n const rows = opts.rows ?? GRID_ROWS;\n const rect = el.getBoundingClientRect();\n // A hidden or not-yet-laid-out element has no backdrop to speak of. Sampling it anyway collapses\n // the whole grid onto one corner point and reports whatever unrelated thing sits there as a\n // confident, perfectly flat reading.\n if (rect.width <= 0 || rect.height <= 0) return statsFromSamples([]);\n const samples: RgbColor[] = [];\n for (let j = 0; j < rows; j += 1) {\n const y = rect.top + ((j + 0.5) / rows) * rect.height;\n for (let i = 0; i < cols; i += 1) {\n const x = rect.left + ((i + 0.5) / cols) * rect.width;\n const color = sampleColorAt(el, x, y);\n if (color) samples.push(color);\n }\n }\n return statsFromSamples(samples);\n}\n","// Feature detection BY MEASUREMENT, never by sniffing the user agent — the agent string is the\n// first thing to lie about this after an engine update.\n//\n// Firefox does not support `url()` inside `backdrop-filter` and has closed the request as not\n// planned (bug 1578503). Safari doesn't support `backdrop-filter` with `url()` yet either, though\n// WebKit has patches in flight. Both can change without notice, so this asks the engine directly.\n\nlet backdropFilterSupport: boolean | null = null;\nlet svgBackdropFilterSupport: boolean | null = null;\n\n// `CSS.supports`, not a detached element read back through `getComputedStyle`: Chromium resolves\n// no style at all for an element outside the document, so that probe answered \"unsupported\" in the\n// very engine where the displacement demonstrably works.\n//\n// This answers that the engine PARSES the value. An engine could in principle parse `url()` and\n// render nothing; a host that meets one can override the decision through `attachGlass` instead of\n// being stuck with a wrong automatic answer.\nfunction probeProperty(property: string, value: string): boolean {\n if (typeof CSS === 'undefined' || typeof CSS.supports !== 'function') return false;\n return CSS.supports(property, value);\n}\n\n/** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */\nexport function supportsBackdropFilter(): boolean {\n if (backdropFilterSupport === null) {\n backdropFilterSupport =\n probeProperty('backdrop-filter', 'blur(1px)') || probeProperty('-webkit-backdrop-filter', 'blur(1px)');\n }\n return backdropFilterSupport;\n}\n\n/** `url(#filter)` specifically — the SVG displacement path's requirement. Checked separately from\n * `supportsBackdropFilter()`: an engine can support plain blur without supporting a filter\n * reference, which is exactly the Firefox case. */\nexport function supportsSvgBackdropFilter(): boolean {\n if (svgBackdropFilterSupport === null) {\n svgBackdropFilterSupport = probeProperty('backdrop-filter', 'url(#vireglass-support-probe)');\n }\n return svgBackdropFilterSupport;\n}\n\n/** Test-only: the two probes above cache after their first call, and a suite that stubs the DOM\n * differently per test needs a way to invalidate that. */\nexport function resetSupportCache(): void {\n backdropFilterSupport = null;\n svgBackdropFilterSupport = null;\n}\n","// The colour that bleeds into a shadow (docs/reference.md §4, 219 @8:22): \"the light reflects,\n// scatters, and bleeds into the shadow as well — much like it would in the physical world.\"\n//\n// JS twin of the lens surface's `vgShadowTint`. A shadow that is simply black leaves an element\n// over colourful content hanging above a grey blob, which reads as pasted on rather than resting\n// there.\n\nconst LUMA: readonly [number, number, number] = [0.2126, 0.7152, 0.0722];\n\nconst luma = (c: readonly [number, number, number]) => c[0] * LUMA[0] + c[1] * LUMA[1] + c[2] * LUMA[2];\n\n/**\n * Hue without lightness, scaled by how much light there is to bleed. Lightness is subtracted out\n * of the hue on purpose: left in, the shadow PALES and loses its depth instead of warming up. And\n * over a nearly black backdrop there is nothing to spill, so the result goes to zero on its own.\n */\nexport function shadowTint(ambient: readonly [number, number, number]): [number, number, number] {\n const peak = Math.max(ambient[0], ambient[1], ambient[2], 0.001);\n const hue: [number, number, number] = [ambient[0] / peak, ambient[1] / peak, ambient[2] / peak];\n const grey = luma(hue);\n const available = luma(ambient);\n return [(hue[0] - grey) * available, (hue[1] - grey) * available, (hue[2] - grey) * available];\n}\n","// Adaptive shadow (docs/reference.md §4). The law itself — density keyed to what is behind the\n// element, size keyed to its own half-size — lives in `../geometry` as `shadowOpacityFrom` and\n// `shadowReachDp`; this turns those into a CSS `box-shadow`.\nimport { ambientFrom, type BackdropSample } from '../adaptation';\nimport { shadowOpacity, shadowOpacityFrom, shadowReachDp, type VireGlassGeometry } from '../geometry';\nimport { SHADOW, SHADOW_GAP } from '../law';\nimport { shadowTint } from '../shadow-tint';\n\n/**\n * The model carries shadow density as a multiplier the shader applies to its own per-pixel term,\n * so the DOM path has to convert it to one flat alpha. That conversion is not a taste constant:\n * §4 records both ends measured off reference frames 711–723 — 19.9% over text, 4.0% over a flat\n * light backdrop — and `shadowOpacity` spans exactly those two cases. Two measured points, one line.\n */\nconst FLAT_DENSITY = shadowOpacity(0);\nconst BUSY_DENSITY = shadowOpacity(1);\n\nexport function shadowAlphaFrom(sample: { busy: number }): number {\n const t = (shadowOpacityFrom(sample) - FLAT_DENSITY) / (BUSY_DENSITY - FLAT_DENSITY);\n const alpha = SHADOW.alphaFlat + t * (SHADOW.alphaBusy - SHADOW.alphaFlat);\n return Math.min(Math.max(alpha, 0), 1);\n}\n\nconst to255 = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * 255);\n\n/**\n * Symmetric and blur-only: §4 gives a density and a size, never a direction. The reference calls\n * the shadow \"soft, small\" — blur carries both.\n *\n * The colour is NOT black. \"The light reflects, scatters, and bleeds into the shadow as well —\n * much like it would in the physical world\" (219 @8:22). A black shadow leaves an element over\n * colourful content hanging above a grey blob, which is the one thing that reads as pasted on.\n */\n/**\n * `appear` is the same gate the surface shader puts on the shadow (`u_shadow * u_appear`, line\n * 176). An element that is not there yet does not cast: a shadow under nothing is the one part of\n * materialising that gives the trick away.\n */\nexport function boxShadowCss(\n geometry: VireGlassGeometry,\n sample: BackdropSample | { busy: number },\n appear = 1,\n): string {\n const reach = shadowReachDp(geometry);\n const present = appear < 0 ? 0 : appear > 1 ? 1 : appear;\n const alpha = shadowAlphaFrom(sample) * present;\n const ambient = 'luma' in sample ? ambientFrom(sample as BackdropSample) : null;\n if (!ambient) return `0 0 ${reach.toFixed(1)}px rgba(0, 0, 0, ${alpha.toFixed(3)})`;\n\n const [r, g, b] = shadowTint(ambient);\n const spill = SHADOW_GAP.tint;\n return (\n `0 0 ${reach.toFixed(1)}px ` +\n `rgba(${to255(r * spill)}, ${to255(g * spill)}, ${to255(b * spill)}, ${alpha.toFixed(3)})`\n );\n}\n","// The glass BODY (docs/reference.md §3): how dense the medium has to be over this particular\n// backdrop, and which way it tints.\n//\n// The law is the lens shader's, lines 444–482, ported to one value per element instead of one per\n// pixel — the DOM path has a single backdrop sample, not a plane. Constants keep their names from\n// the shader so the two stay comparable.\nimport { BODY } from '../law';\nimport type { VireGlassOptics } from '../material';\n\nconst {\n capLoose: BODY_CAP_LOOSE,\n capTight: BODY_CAP_TIGHT,\n tintDark: TINT_DARK,\n tintLight: TINT_LIGHT,\n groundSpan: GROUND_SPAN,\n busyEdge: BUSY_EDGE,\n darkSideFrom: DARK_SIDE_FROM,\n darkSideTo: DARK_SIDE_TO,\n maxDemand: MAX_DEMAND,\n} = BODY;\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\nconst mix = (a: number, b: number, t: number) => a + (b - a) * t;\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n const t = clamp((x - edge0) / (edge1 - edge0), 0, 1);\n return t * t * (3 - 2 * t);\n}\n\n/** Only the two figures the law reads — the same narrowing `shadowOpacityFrom` uses. */\nexport type BodyBackdrop = { luma: number; busy: number };\n\nexport type GlassBody = {\n /** How much medium stands between the backdrop and the eye, 0…1. */\n density: number;\n /** Lightness the body tints toward. */\n tintLuma: number;\n};\n\n/**\n * `ink` is POLARITY, 1 light and 0 dark, matching the shader's uniform. The requirements are\n * evaluated at both ends and blended by it — computing at the current polarity alone makes the\n * glass dip toward the middle while a recolor is in flight.\n */\nexport function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody {\n const strict = clamp(optics.legibility * 2, 0, 1);\n const capLight = mix(BODY_CAP_LOOSE, BODY_CAP_TIGHT, strict);\n const floorDark = 1 - capLight;\n const pol = clamp(ink, 0, 1);\n // With no ink on it, the model promises transparent glass: the requirement fades out with\n // legibility rather than standing at a floor.\n const demand = clamp(optics.legibility * 4, 0, 1);\n\n const mean = clamp(sample.luma, 0, 1);\n const busy = Math.max(sample.busy, 0);\n\n // Direction of the tint follows the element's AVERAGE lightness, not a local spot: on a\n // gradient a local threshold cuts a diagonal step across the body.\n const darkSide = smoothstep(DARK_SIDE_FROM, DARK_SIDE_TO, mean);\n const away = mix(TINT_LIGHT, TINT_DARK, darkSide);\n const tintLuma = mix(away, mix(TINT_LIGHT, TINT_DARK, pol), demand);\n\n // How much medium it takes to push the lightness under the ink past its threshold, measured\n // from whichever edge of the backdrop's spread is closer to the ink — a light ink drowns in a\n // light patch right beneath it, and the average knows nothing about that patch.\n const edge = busy * BUSY_EDGE;\n const inkHi = Math.min(mean + edge, 1);\n const inkLo = Math.max(mean - edge, 0);\n const needForLight = inkHi > capLight ? clamp((inkHi - capLight) / Math.max(inkHi - TINT_DARK, 1e-4), 0, MAX_DEMAND) : 0;\n const needForDark = inkLo < floorDark ? clamp((floorDark - inkLo) / Math.max(TINT_LIGHT - inkLo, 1e-4), 0, MAX_DEMAND) : 0;\n const needForInk = mix(needForDark, needForLight, pol) * demand;\n\n // Fine texture the body has to stop being a window for, the same way roughness does it.\n const ground = busy * optics.legibility * GROUND_SPAN;\n\n return { density: Math.max(Math.max(optics.bodyDensity, ground), needForInk), tintLuma };\n}\n\n/**\n * PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly\n * disappears — right for a piece of background, wrong for a control. It is a MINIMUM, not an\n * addition, so a body that already stands apart is left alone.\n *\n * The direction is the body's own. The previous version decided \"lighter over dark, darker over\n * light\" from the backdrop alone, and then, when the body disagreed, clamped `tintLuma` to the\n * backdrop's mean — the one value that separates from nothing. Light ink over a dark backdrop puts\n * the body at 0.07 against a backdrop of 0.12: already separating, downward, and the clamp pulled\n * it back onto the backdrop. Measured on the default material at presence 0.08: exactly 0.0000 at\n * backdrops of 0.12, 0.20 and 0.35.\n *\n * What the demand is DIVIDED by is deliberately the distance to the tint's pole rather than to the\n * body's own tint. Dividing by the latter is arithmetically tighter and asks for far more density\n * wherever the two are close — enough to drive it to the ceiling over a dark backdrop and stop the\n * glass being a window at all, which check:optics says plainly. Presence is a floor on visibility,\n * not a licence to go opaque.\n */\nexport function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody {\n if (optics.presence <= 0) return body;\n const mean = clamp(sample.luma, 0, 1);\n // Whichever side the body is already on; with nothing to go on, the side with more room.\n const above = Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma > mean : mean < 0.5;\n const pole = above ? TINT_LIGHT : TINT_DARK;\n const separation = Math.min(optics.presence, Math.abs(pole - mean));\n const reached = Math.abs(body.tintLuma - mean) * body.density;\n if (reached >= separation) return body;\n const needed = separation / Math.max(Math.abs(pole - mean), 1e-4);\n return {\n density: Math.max(body.density, Math.min(needed, BODY.presenceDemand)),\n // Left where the tint law put it, unless it landed exactly on the backdrop — which is the\n // case that used to be created here rather than avoided.\n tintLuma: Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma : pole,\n };\n}\n","// System accessibility settings change the material's LAYERS, they don't override it (reference\n// 219 @18:15). So what's adjusted here are EFFECTS, like with toggles: the shader knows nothing\n// about accessibility.\nimport { ACCESSIBILITY, BODY } from './law';\nimport type { VireGlassOptics } from './material';\n\nexport type VireGlassAccessibility = {\n /** The glass becomes more frosted and hides content beneath it more strongly (219 @18:22). */\n reduceTransparency: boolean;\n /** The element moves nearly to black or white and picks up a contrasting border (219 @18:29). */\n increaseContrast: boolean;\n /** The material's springiness is turned off, effects are quieter (219 @18:35). */\n reduceMotion: boolean;\n};\n\nexport const NO_ACCESSIBILITY: VireGlassAccessibility = {\n reduceTransparency: false,\n increaseContrast: false,\n reduceMotion: false,\n};\n\n/** A system setting acts on the whole glass and outranks the material preset (219 @18:45): even\n * a transparent preset moves to the edge of the scale under contrast — the user needs contrast\n * more than they need aesthetics. */\nexport function applyAccessibility(\n optics: VireGlassOptics,\n mods: VireGlassAccessibility = NO_ACCESSIBILITY,\n): VireGlassOptics {\n if (!mods.reduceTransparency && !mods.increaseContrast) return optics;\n const out = { ...optics };\n if (mods.reduceTransparency) {\n out.blur = Math.max(out.blur, ACCESSIBILITY.frostMinDp);\n out.bodyDensity = Math.max(out.bodyDensity, ACCESSIBILITY.obscureMin);\n }\n if (mods.increaseContrast) {\n out.bodyDensity = Math.max(out.bodyDensity, ACCESSIBILITY.contrastDensity);\n out.presence = Math.max(out.presence, ACCESSIBILITY.contrastPresence);\n out.legibility = 1;\n }\n return out;\n}\n\n/**\n * The lightness of the contrasting border §9 asks for, for a body sitting at `tintLuma`.\n *\n * It is the one place the rim stops being an environmental thing. Everywhere else the hairline\n * takes its colour from what is around the element — \"over a yellow flower the rim is yellow\"\n * (§2) — and a hairline the colour of its surroundings is not a border that contrasts with the\n * element it outlines. Under this setting it is measured from the body instead.\n */\nexport function contrastRimLuma(tintLuma: number): number {\n const light = tintLuma < 0.5;\n return light\n ? Math.min(tintLuma + ACCESSIBILITY.contrastRim, BODY.tintLight)\n : Math.max(tintLuma - ACCESSIBILITY.contrastRim, BODY.tintDark);\n}\n\n/**\n * Whether the material may deform. §9: reduced motion \"disables any elastic properties for the\n * material\" — the spring and the ripple. It does NOT disable the response: the press that lights\n * an element from within (§5) is light, not motion, and survives at reduced intensity.\n */\nexport function elasticAllowed(mods: VireGlassAccessibility = NO_ACCESSIBILITY): boolean {\n return !mods.reduceMotion;\n}\n","// System accessibility on the web (docs/reference.md §9). The three settings the reference names\n// all have media queries, so nothing here has to be asked of the host: the browser already knows.\n//\n// `reduceMotion` leaves optics alone — it is about motion, and motion is computed by the\n// deformation model, which takes it as `elastic: false`. The element keeps answering a finger; it\n// stops springing and rippling.\nimport { NO_ACCESSIBILITY, type VireGlassAccessibility } from '../accessibility';\n\nconst QUERIES = {\n reduceTransparency: '(prefers-reduced-transparency: reduce)',\n increaseContrast: '(prefers-contrast: more)',\n reduceMotion: '(prefers-reduced-motion: reduce)',\n} as const;\n\nfunction matches(query: string): boolean {\n if (typeof matchMedia !== 'function') return false;\n try {\n return matchMedia(query).matches;\n } catch {\n // An engine that does not know a query throws rather than answering false. Not knowing it is\n // an answer of \"not set\", not a reason to fail.\n return false;\n }\n}\n\nexport function systemAccessibility(): VireGlassAccessibility {\n if (typeof matchMedia !== 'function') return NO_ACCESSIBILITY;\n return {\n reduceTransparency: matches(QUERIES.reduceTransparency),\n increaseContrast: matches(QUERIES.increaseContrast),\n reduceMotion: matches(QUERIES.reduceMotion),\n };\n}\n\n/** Fires whenever any of the three changes. The material has to follow a setting turned on while\n * the page is open, not only one that was on when it loaded. */\nexport function watchAccessibility(onChange: (next: VireGlassAccessibility) => void): () => void {\n if (typeof matchMedia !== 'function') return () => {};\n const lists: MediaQueryList[] = [];\n const handler = () => onChange(systemAccessibility());\n for (const query of Object.values(QUERIES)) {\n try {\n const list = matchMedia(query);\n list.addEventListener('change', handler);\n lists.push(list);\n } catch {\n // Same as above: an unknown query simply has nothing to watch.\n }\n }\n return () => {\n for (const list of lists) list.removeEventListener('change', handler);\n };\n}\n","// User-facing glass transparency scale: iOS 26.1 gave a choice between two options (\"default clear\n// look\" or \"tinted look which increases opacity of the material\"), iOS 27 a continuous slider\n// \"ultra clear → fully tinted\", and apps get it without recompiling.\n//\n// It adjusts EFFECTS, not causes, and that's not a compromise. The cause \"medium density\" is\n// deliberately absent from the model: the glass has no color of its own, `bodyDensity` is derived\n// from absorption through the body and never exceeds 0.03, and the visible density is held by the\n// legibility requirement and scattering. A thickness scale would move a number that isn't visible\n// in the frame (measured by the `check:optics` gate).\nimport { SCALE } from './law';\nimport type { VireGlassOptics } from './material';\n\n/** The point on the scale where the material stays exactly as it is today. */\nexport const GLASS_SCALE_DEFAULT = SCALE.default;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * `scale` 0 is ultra clear, 1 is fully tinted. Toward the transparent end, the legibility\n * requirement and the dimming layer are relaxed (the user chose clarity); toward the tinted end,\n * body density grows.\n *\n * Accessibility settings apply AFTER the scale: they set floors, and the user's chosen clarity\n * does not override them (219 @18:45).\n */\nexport function applyGlassScale(optics: VireGlassOptics, scale: number): VireGlassOptics {\n const s = clamp01(scale);\n if (s === GLASS_SCALE_DEFAULT) return optics;\n if (s < GLASS_SCALE_DEFAULT) {\n const k = s / GLASS_SCALE_DEFAULT;\n return { ...optics, legibility: optics.legibility * k, dimming: optics.dimming * k };\n }\n const k = (s - GLASS_SCALE_DEFAULT) / (1 - GLASS_SCALE_DEFAULT);\n return { ...optics, bodyDensity: Math.max(optics.bodyDensity, SCALE.tintedDensity * k) };\n}\n","// Materialising in and out (docs/reference.md §1, 219 @2:55): \"Instead of fading, Liquid Glass\n// objects materialize in and out by gradually modulating the light bending and lensing, ensuring a\n// graceful transition that preserves the optical integrity of the material.\"\n//\n// So an element must not arrive by opacity. Fading it leaves a half-transparent picture OF glass;\n// modulating the lens leaves glass that is not yet bending much light. The difference is visible:\n// a faded element shows the backdrop through a veil, a materialising one shows it undistorted.\n//\n// JS twin of what `u_appear` multiplies in the lens: the lens strength itself, the frost, the\n// body, the dimming layer and the rim's light. Everything that makes the material present, and\n// nothing that makes it opaque.\nimport type { VireGlassOptics } from './material';\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * `t` of 0 is an element indistinguishable from the backdrop beneath it; 1 is the material at\n * full strength. Between them the glass bends progressively more light.\n */\nexport function applyAppear(optics: VireGlassOptics, t: number): VireGlassOptics {\n const a = clamp01(t);\n if (a === 1) return optics;\n return {\n ...optics,\n refraction: optics.refraction * a,\n blur: optics.blur * a,\n bodyDensity: optics.bodyDensity * a,\n dimming: optics.dimming * a,\n edgeLight: optics.edgeLight * a,\n // A floor on how far the element must stand out from its backdrop (§3). Left alone it holds\n // the element visible at t = 0, which is the opposite of what materialising means.\n presence: optics.presence * a,\n // The spectral trio is lensing too — §1's \"light bending and lensing\" is not only the\n // displacement. The fringe map and the per-channel split are drawn from these, and a filter\n // graph that still paints them is an element that is not there but is casting a rainbow.\n dispersion: optics.dispersion * a,\n iridescence: optics.iridescence * a,\n diffraction: optics.diffraction * a,\n tintStrength: optics.tintStrength * a,\n // Legibility is a REQUIREMENT, not an effect: an element still arriving has no ink on it yet,\n // and holding a demand it cannot meet would darken the body exactly while it should be\n // clearing. It fades with the rest.\n legibility: optics.legibility * a,\n };\n}\n","// Tinting (docs/reference.md §7, 219 @16:31): \"Selecting a color generates a range of tones that\n// are mapped to content brightness underneath the tinted element. It draws inspiration from how\n// colored glass works in reality: changing its hue, brightness and saturation depending on what's\n// behind without deviating too much from the intended color.\"\n//\n// So a tint is not a fill. @17:03 is explicit about what a fill costs: \"it is completely opaque\n// and breaks the visual character of Liquid Glass.\" The colour has to be a property of the medium,\n// and the content has to keep coming through it.\n//\n// JS twin of the accent block in the lens shader.\nimport type { VireGlassAccent } from './adapters';\nimport { ACCENT } from './law';\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * The tone this accent takes over a backdrop of the given lightness — deeper over dark, lighter\n * over light, which is what \"a range of tones mapped to content brightness\" means.\n *\n * @17:21: tinting is for the primary action, not for everything. \"When every element is tinted,\n * nothing stands out.\" That is the host's call, not this function's.\n */\nexport function accentTone(\n color: readonly [number, number, number],\n backdropLuma: number,\n): [number, number, number] {\n const k = ACCENT.deep + (ACCENT.light - ACCENT.deep) * clamp01(backdropLuma);\n return [clamp01(color[0] * k), clamp01(color[1] * k), clamp01(color[2] * k)];\n}\n\n/** The fraction of the medium the colour occupies, which is what keeps the content showing\n * through it rather than being covered by it. */\nexport function accentAmount(accent: VireGlassAccent): number {\n return clamp01(accent.amount ?? ACCENT.amount);\n}\n","// Concentricity (reference 219 @7:53): nested shapes share the CENTER of curvature, not the radius.\n// So the inner shape's radius is smaller by exactly the inset — otherwise the corners don't run\n// parallel and the gap between the shapes either gets eaten or spreads apart.\n\n/**\n * Radius of a nested shape: outer radius minus inset. Zero is a square corner; it never goes\n * negative — once the inset exceeds the outer radius, the corner is simply a right angle.\n *\n * `minimum` — a floor on the radius (analogous to `concentric(minimum:)` in SwiftUI): far from\n * the edge, honest concentricity yields zero and the nested element drops out of the family with\n * a sharp corner. The floor breaks concentricity on purpose — here kinship between shapes matters\n * more than a shared center of curvature.\n */\nexport function concentricRadius(outerRadius: number, inset: number, minimum = 0): number {\n return Math.max(outerRadius - inset, Math.max(minimum, 0));\n}\n\n/**\n * The inset at which an inner shape with a given radius stays concentric with the outer one.\n * The inverse problem: the element's radius is known (its size dictates it), and what's needed\n * is the margin around it.\n */\nexport function concentricInset(outerRadius: number, innerRadius: number): number {\n return Math.max(outerRadius - innerRadius, 0);\n}\n\n/**\n * The three shape types the design system builds concentric layouts from (356 @3:42): \"fixed\n * shapes have a constant corner radius. Capsules use a radius that's half the height of the\n * container. And concentric shapes calculate their radius by subtracting padding from the\n * parent's.\"\n *\n * Naming them is the point. 356 @5:09: \"using the three shape types we covered earlier helps keep\n * your components aligned with the system.\" A host that only has a number has to decide what that\n * number means every time the layout changes; a host that has the type gets the number recomputed\n * for it.\n */\nexport type ShapeSpec =\n | { type: 'fixed'; radius: number }\n | { type: 'capsule' }\n /**\n * `fallback` is 356 @6:00: \"a neat trick for managing components that need to work both inside a\n * container and on their own: use a concentric shape with a fallback radius. The concentric value\n * adapts when nested, and the fallback kicks in when the component stands alone.\"\n *\n * It is not the same as `minimum`. A minimum is a floor that applies while nested and breaks\n * concentricity on purpose; a fallback applies only when there is no parent to be concentric\n * with, and never overrides a parent that exists.\n */\n | { type: 'concentric'; inset: number; minimum?: number; fallback?: number };\n\n/** What is around a shape, when there is something around it. */\nexport type ShapeParent = { cornerRadius: number };\n\n/**\n * The corner radius a shape takes in the place it finds itself. `height` is the shape's own, which\n * is what a capsule's radius is measured from; `parent` is absent when the shape stands alone.\n */\nexport function resolveShape(spec: ShapeSpec, height: number, parent?: ShapeParent): number {\n switch (spec.type) {\n case 'fixed':\n return Math.max(spec.radius, 0);\n case 'capsule':\n return Math.max(height, 0) / 2;\n case 'concentric':\n return parent\n ? concentricRadius(parent.cornerRadius, spec.inset, spec.minimum)\n : Math.max(spec.fallback ?? 0, 0);\n }\n}\n\n/**\n * Whether two nested shapes are concentric, and which way they are wrong when they are not.\n * 356 @5:19: \"keep an eye out for corners that feel too pinched — or flared. They can create\n * tension and break the sense of balance.\"\n *\n * Pinched is an inner radius smaller than concentricity asks for: the gap between the corners\n * widens through the curve. Flared is larger: the gap narrows and the corners crowd each other.\n * The defect is visible to the eye and usually goes unnamed, which is why this names it.\n */\nexport function concentricFit(\n outerRadius: number,\n inset: number,\n innerRadius: number,\n tolerance = 0.5,\n): 'concentric' | 'pinched' | 'flared' {\n const want = concentricRadius(outerRadius, inset);\n if (innerRadius < want - tolerance) return 'pinched';\n if (innerRadius > want + tolerance) return 'flared';\n return 'concentric';\n}\n","// Rim light (docs/reference.md §2): a hairline along the silhouette — \"not a band and not a\n// bevel\" — carrying two opposing arcs, the rest of it outlined by a thin dark line, and its colour\n// taken from the environment.\n//\n// Every number here is the lens shader's own. The key-light lobe is `lens-shader.ts` line 375\n// verbatim (exponent 3, opposing arc at 0.45), and the dark edge is its line 528 (a 0.22\n// darkening at the silhouette). The only thing that differs is the primitive: a conic gradient\n// sampled at fixed angles instead of a per-pixel normal.\nimport { RIM } from '../law';\nimport type { VireGlassOptics } from '../material';\n\nconst { lobeExponent: LOBE_EXPONENT, opposingArc: OPPOSING_ARC, darkEdge: DARK_EDGE } = RIM;\n\n/** One stop every 7.5°. Fine enough that a cubic lobe reads as a smooth arc rather than a fan. */\nconst STOPS = 48;\n\n/**\n * Screen space has y pointing down; a CSS conic gradient starts at 12 o'clock and runs clockwise.\n * A point at conic angle φ therefore has outward normal `(sin φ, -cos φ)`, which is what the lobe\n * is measured against.\n */\nexport function lightConicAngle(light: readonly [number, number]): number {\n const [lx, ly] = light;\n const deg = (Math.atan2(lx, -ly) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\n/** The shader's key-light lobe, evaluated for a rim point whose normal sits `deltaDeg` away from\n * the light. Both arcs come out of this one expression — that is why they are opposed. */\nexport function rimLobe(deltaDeg: number, specular: number): number {\n const facing = Math.cos((deltaDeg * Math.PI) / 180);\n const front = facing > 0 ? Math.pow(facing, LOBE_EXPONENT) : 0;\n const back = facing < 0 ? Math.pow(-facing, LOBE_EXPONENT) : 0;\n return specular * (front + OPPOSING_ARC * back);\n}\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\nconst to255 = (v: number) => Math.round(clamp01(v) * 255);\n\nexport type RimAmbient = readonly [number, number, number];\n\n/**\n * The gradient for the hairline. Colour comes from the environment — \"over a yellow flower the rim\n * is yellow, over sky it is blue\" (§2) — lifted toward white where the key light lands. Away from\n * both arcs only the dark edge remains.\n *\n * The opposing arc carries an iridescent fringe (§2), so `iridescence` pulls its channels apart\n * rather than lifting them together.\n */\nexport function rimGradientCss(\n optics: VireGlassOptics,\n ambient: RimAmbient,\n light: readonly [number, number],\n appear = 1,\n): string {\n const present = clamp01(appear);\n const start = lightConicAngle(light);\n const [ar, ag, ab] = ambient;\n const stops: string[] = [];\n\n for (let i = 0; i <= STOPS; i += 1) {\n const angle = (i / STOPS) * 360;\n const key = rimLobe(angle, optics.specular);\n const facing = Math.cos((angle * Math.PI) / 180);\n // The far arc is where dispersion shows as a fringe; the near one is a clean specular.\n const fringe = facing < 0 ? optics.iridescence * OPPOSING_ARC : 0;\n const lift = clamp01(key * optics.fresnel);\n\n const r = ar + (1 - ar) * clamp01(lift + fringe);\n const g = ag + (1 - ag) * lift;\n const b = ab + (1 - ab) * clamp01(lift - fringe);\n\n // Scaled, not floored: the dark edge is the one part of the rim that survives facing away from\n // the light, so leaving it unscaled leaves a hairline drawn around an element that is not there.\n const alpha = clamp01(DARK_EDGE + lift * (1 - DARK_EDGE)) * present;\n // Below the arcs the line is the dark edge itself, not a dim copy of the environment.\n const colour = lift > 0.001\n ? `rgba(${to255(r)},${to255(g)},${to255(b)},${alpha.toFixed(3)})`\n : `rgba(0,0,0,${alpha.toFixed(3)})`;\n stops.push(`${colour} ${angle.toFixed(1)}deg`);\n }\n\n return `conic-gradient(from ${start.toFixed(1)}deg, ${stops.join(', ')})`;\n}\n\nexport const RIM_WIDTH_PX = RIM.widthPx;\n\n/**\n * The border for increased contrast (§9: elements become \"predominantly black or white\" and are\n * highlighted \"with a contrasting border\").\n *\n * Not a gradient: the two arcs above are a light source reflecting off a curved edge, and under\n * this setting the edge is not reporting where the light is, it is separating the element from\n * everything around it. It has to hold at every angle, including the one facing away from the key\n * light where the ordinary rim falls back to a dim dark line.\n */\nexport function contrastRimCss(bodyLuma: number, rimLuma: number): string {\n const v = to255(rimLuma);\n // Opaque on purpose. A border that lets the backdrop through is the thing this setting exists\n // to replace, and the body behind it is already at its own pole.\n void bodyLuma;\n return `conic-gradient(rgb(${v},${v},${v}) 0deg, rgb(${v},${v},${v}) 360deg)`;\n}\n","// Glass inside glass (docs/reference.md §6). 219 @11:50 puts it among the principles: \"avoid\n// putting [glass] within or on top of other glass elements to maintain hierarchy and prevent\n// clutter.\" S 32:54 (\"Building CNN for iOS 26\") is the same rule reported from the other side, by a\n// team that had already shipped it: \"Applying the glass effect to both a parent and child views led to visual redundancy.\n// Double translucency, layered blur, and unpredictable rendering.\"\n//\n// On this renderer it is not only a matter of hierarchy. `backdrop-filter` samples what is already\n// composited behind the element, so a nested pane's backdrop is the outer pane's OUTPUT: the\n// displacement is applied twice to the same pixels and the two blurs multiply. The inner element\n// does not look like thicker glass, it looks like a mistake.\n//\n// Overlap is a different case and not this function's business — a sheet over a bar is two panes in\n// the stacking order, which is what two panes of glass actually do. Only containment is wrong.\nconst WARNED = new WeakSet<Element>();\n\n/** Set by `attachGlass`; exported so the check does not have to know the attribute's spelling. */\nexport const GLASS_ATTR = 'data-vireglass';\n\nexport function warnIfNested(el: Element): void {\n if (WARNED.has(el)) return;\n const outer = el.parentElement?.closest(`[${GLASS_ATTR}]`);\n if (!outer) return;\n WARNED.add(el);\n // Warned, not refused: where an element sits is the host's layout, and a library that silently\n // declines to render is harder to debug than one that says what is wrong.\n const where = outer.tagName.toLowerCase() + (outer.id ? `#${outer.id}` : '');\n console.warn(\n `vireglass: glass inside glass — this element is a descendant of <${where}>, which is also glass. ` +\n `Its backdrop is the outer element's output, so the refraction is applied twice and the blurs ` +\n `multiply. Put the glass on one of the two.`,\n );\n}\n","import { ACCENT, MORPH } from './law';\nimport {\n bevelDp,\n bevelFraction,\n halfMinDp,\n rimDp,\n shadowReachDp,\n surfacePadDp,\n thicknessDp,\n type VireGlassGeometry,\n} from './geometry';\nimport { LENS_SHADER } from './lens-shader';\nimport { neckToBridge } from './sdf';\nimport { debugIndex, type VireGlassDebugMode, type VireGlassOptics } from './material';\n\n/** A second shape joined to the element by a smooth union: the geometry that merges and growth\n * transitions are built on (a capsule drawn into a drop, then grown into its menu). Offsets from\n * the element's centre and sizes in dp. */\nexport type VireGlassMorph = {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n cornerRadius: number;\n /** Seam smoothing radius in dp; 0 turns the second shape off. */\n smoothing: number;\n};\n\n\n/** Surface response to a finger: the field around the touch point deforms, not the shape's\n * bounding box (`vgTouchWarp` in `sdf.ts`). Lengths in dp; `radius` = 0 turns the response off\n * entirely. */\nexport type VireGlassTouch = {\n x: number;\n y: number;\n pullX: number;\n pullY: number;\n press: number;\n radius: number;\n waveAmp: number;\n wavePhase: number;\n};\n\nconst NO_TOUCH: VireGlassTouch = {\n x: 0, y: 0, pullX: 0, pullY: 0, press: 0, radius: 0, waveAmp: 0, wavePhase: 0,\n};\n\nconst NO_MORPH = { offsetX: 0, offsetY: 0, width: 0, height: 0, cornerRadius: 0, smoothing: 0 };\n\n/** No progress. Negative rather than zero: zero is the start of the track, a legitimate value. */\nconst NO_PROGRESS = -1;\n\n/** Tinted glass for the primary action (M 16:08). Color is RGB 0…1. */\nexport type VireGlassAccent = { color: readonly [number, number, number]; amount?: number };\n\n/** Default tint fraction: the color reads, but content beneath it is still visible. */\nexport const ACCENT_AMOUNT = ACCENT.amount;\nconst NO_ACCENT = [0, 0, 0, 0] as const;\n\n\n\n/** Magnification at the flat center. Kept separate from the uniform channel: it's also used by\n * the fallback below Android 13, where there's no RuntimeShader and only an affine magnifier is\n * left. */\nexport const lensMagnify = (o: VireGlassOptics) => 1 + (o.refractionScale - 1) * o.refraction;\n\n/**\n * Lens uniforms. Assembled as ONE channel: name, size and values travel together, so a mismatch\n * with the shader is caught immediately, with the name right there in the log. There used to be a\n * separate Kotlin `Prop` per value — Expo swallows an unknown prop silently, and the lens simply\n * never turned on (docs/material-lab.md E-01, which is how refraction ended up disabled for an\n * entire phase).\n *\n * Everything with a dimension is converted to PIXELS right here. The native view is left with\n * only the uniforms it alone knows: its own size and its own place on screen.\n */\n// The lens's uniform names and sizes are always the same — the set is fixed. They're handed over\n// as ONE instance for the whole process: otherwise every frame of a drag would send three dozen\n// fresh strings to the native side, React can't tell \"unchanged\" from \"a new array\", and motion\n// goes stepwise. The values are the only thing that actually changes.\nconst shapes = new Map<number, { names: string[]; sizes: number[] }>();\n\nfunction channel(entries: [string, number | readonly number[]][]) {\n const uniformValues: number[] = [];\n let shape = shapes.get(entries.length);\n let same = shape !== undefined;\n for (let i = 0; i < entries.length; i += 1) {\n const [name, value] = entries[i];\n const v = typeof value === 'number' ? [value] : value;\n if (same && (shape!.names[i] !== name || shape!.sizes[i] !== v.length)) same = false;\n for (const x of v) uniformValues.push(x);\n }\n if (!same) {\n shape = {\n names: entries.map((e) => e[0]),\n sizes: entries.map((e) => (typeof e[1] === 'number' ? 1 : e[1].length)),\n };\n shapes.set(entries.length, shape);\n }\n return { uniformNames: shape!.names, uniformSizes: shape!.sizes, uniformValues };\n}\n\n/** Props for the native view. Besides the uniform channel, only what the view uses itself lives\n * here: the shader source and the visible glass's size (the probe rectangle is taken from it). */\nexport function toLensProps(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n density: number,\n options: {\n debug?: VireGlassDebugMode;\n morph?: VireGlassMorph;\n /** Third shape of the fused body; a zero size turns it off. */\n morph2?: VireGlassMorph;\n groupProbe?: number[];\n touch?: VireGlassTouch;\n /** Progress fraction, 0…1: to the left of the boundary the element is active. `undefined` means no progress. */\n progress?: number;\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the lens builds up as the element appears — instead of a plain fade. */\n appear?: number;\n /** Tint for the primary action: the glass color and the fraction it lays over the content. */\n accent?: VireGlassAccent;\n } = {},\n) {\n const morph = options.morph ?? NO_MORPH;\n const morph2 = options.morph2 ?? NO_MORPH;\n const touch = options.touch ?? NO_TOUCH;\n // Backdrop estimate for the whole surface group. Travels through the same channel as the\n // material and applies AFTER the lens's own estimate — that is, it simply overrides it. It\n // can't travel as a separate prop: the lens view is wrapped in an animated component.\n const g = options.groupProbe;\n const group: [string, number | readonly number[]][] =\n g && g.length >= 9\n ? [\n ['u_probeLuma', g[0]],\n ['u_probeBusy', g[1]],\n ['u_probeRange', [g[2], g[3]]],\n ['u_probeSlope', [g[4], g[5]]],\n ['u_probe', [g[6], g[7], g[8]]],\n ]\n : [];\n const d = density;\n const halfW = (geometry.width * d) / 2;\n const halfH = (geometry.height * d) / 2;\n const halfMin = Math.min(halfW, halfH);\n\n return {\n shaderSource: LENS_SHADER,\n glassWidth: geometry.width,\n glassHeight: geometry.height,\n ...channel([\n ['u_halfSize', [halfW, halfH]],\n ['u_corner', Math.min(geometry.cornerRadius * d, halfMin)],\n ['u_bevel', Math.max(bevelDp(geometry, optics) * d, 1)],\n ['u_thick', thicknessDp(geometry, optics) * d],\n ['u_rim', rimDp(geometry, optics) * d],\n ['u_ior', optics.ior],\n ['u_iorSpread', optics.iorSpread],\n ['u_light', options.light ?? REST_LIGHT],\n ['u_appear', options.appear ?? 1],\n ['u_accent', options.accent ? [...options.accent.color, options.accent.amount ?? ACCENT_AMOUNT] : NO_ACCENT],\n // Haze from surface roughness. Lives in the same disc-gather pass as adaptive scattering,\n // and fades out toward the bevel: that's a different job there — bending the ray and\n // splitting it.\n ['u_frost', optics.blur * d],\n ['u_ink', optics.ink],\n ['u_legibility', optics.legibility],\n ['u_dim', optics.dimming],\n ['u_presence', optics.presence],\n ['u_adaptRadius', optics.adaptRadius * d],\n ['u_bodyDensity', optics.bodyDensity],\n ['u_edgeLight', optics.edgeLight],\n ['u_fresnel', optics.fresnel],\n ['u_specular', optics.specular],\n // The rim gathers light from the element's vicinity — this is a radius around the shape,\n // not its bevel.\n ['u_reflectReach', optics.gatherRadiusDp * d],\n ['u_film', optics.film],\n ['u_iridescence', optics.iridescence],\n ['u_diffraction', optics.diffraction],\n ['u_colorPickup', optics.colorPickup],\n ['u_morphOffset', [morph.offsetX * d, morph.offsetY * d]],\n ['u_morphHalf', [(morph.width * d) / 2, (morph.height * d) / 2]],\n ['u_morphCorner', morph.cornerRadius * d],\n ['u_morphK', morph.smoothing * d],\n ['u_morph2Offset', [morph2.offsetX * d, morph2.offsetY * d]],\n ['u_morph2Half', [(morph2.width * d) / 2, (morph2.height * d) / 2]],\n ['u_morph2Corner', morph2.cornerRadius * d],\n ['u_touch', [touch.x * d, touch.y * d]],\n ['u_pull', [touch.pullX * d, touch.pullY * d]],\n ['u_touchPress', touch.press],\n ['u_touchRadius', touch.radius * d],\n ['u_wave', [touch.waveAmp * d, touch.wavePhase]],\n ['u_progress', options.progress ?? NO_PROGRESS],\n ['u_debug', debugIndex(options.debug ?? 'normal')],\n ...group,\n ]),\n };\n}\n\n/** Static part of the surface uniforms. Dynamics (gesture, press, light) get mixed in inside the\n * component's worklet — the adapter must stay an ordinary function. */\nexport function toSurfaceUniforms(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n options: {\n debug?: VireGlassDebugMode;\n morph?: VireGlassMorph;\n /** Third shape of the fused body; a zero size turns it off. */\n morph2?: VireGlassMorph;\n dragLimit?: number;\n shadow?: number;\n /** Average ambient color around the element: light from it bleeds into the shadow (reference 219 @8:22). */\n ambient?: readonly [number, number, number];\n /** The lens draws the glass body — the surface is left with the highlight, shadow and icon. */\n bodyInLens?: boolean;\n touch?: VireGlassTouch;\n /** Progress fraction, 0…1: to the left of the boundary the element is active. `undefined` means no progress. */\n progress?: number;\n /** 0…1: the element is appearing — shadow and ink build up together with the lens. */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n } = {},\n) {\n const morph = options.morph ?? NO_MORPH;\n const morph2 = options.morph2 ?? NO_MORPH;\n const touch = options.touch ?? NO_TOUCH;\n const pad = surfacePadDp(geometry, options.dragLimit ?? 0, morph);\n return {\n u_center: [geometry.width / 2 + pad, geometry.height / 2 + pad],\n u_halfSize: [geometry.width / 2, geometry.height / 2],\n u_corner: Math.min(geometry.cornerRadius, halfMinDp(geometry)),\n u_bevel: bevelDp(geometry, optics),\n u_thickness: bevelFraction(geometry, optics),\n u_morphOffset: [morph.offsetX, morph.offsetY],\n u_morphHalf: [morph.width / 2, morph.height / 2],\n u_morphCorner: morph.cornerRadius,\n u_morphK: morph.smoothing,\n u_morph2Offset: [morph2.offsetX, morph2.offsetY],\n u_morph2Half: [morph2.width / 2, morph2.height / 2],\n u_morph2Corner: morph2.cornerRadius,\n u_edgeDensity: optics.edgeDensity,\n u_dispersion: optics.dispersion,\n u_refraction: optics.refraction,\n // Tint density is suppressed when the lens is drawing the body: painting it twice would\n // double the fill, and adaptation is impossible on the surface anyway — it can't see the\n // backdrop. The color itself stays: it drives absorption at the rim.\n u_tint: [\n optics.tint.r,\n optics.tint.g,\n optics.tint.b,\n options.bodyInLens ? 0 : optics.tintStrength,\n ],\n u_shadow: options.shadow ?? 1,\n // Neutral by default: without an ambient sample, the shadow stays exactly as it was.\n u_ambient: options.ambient ?? [0, 0, 0],\n u_shadowReach: shadowReachDp(geometry),\n u_touch: [touch.x, touch.y],\n u_pull: [touch.pullX, touch.pullY],\n u_touchPress: touch.press,\n u_touchRadius: touch.radius,\n u_wave: [touch.waveAmp, touch.wavePhase],\n u_presence: optics.presence,\n u_progress: options.progress ?? NO_PROGRESS,\n u_appear: options.appear ?? 1,\n // Zero by default: buttons sink in, the way every element behaved before this rule existed.\n u_lift: options.lift ?? 0,\n\n u_debug: debugIndex(options.debug ?? 'normal'),\n };\n}\n\n/**\n * Surface fields that are LENGTHS: the adapter's contract is specified in dp, and on the web each\n * one of them has to be multiplied by screen density. The list lives here rather than in the\n * renderer, where it used to be a dozen and a half manual multiplications in a row: a missed\n * field there was only caught by eye, and the miss isn't visible everywhere — at density 1,\n * multiplying is indistinguishable from not doing it.\n */\nexport type SurfaceUniforms = ReturnType<typeof toSurfaceUniforms>;\n\nexport const SURFACE_LENGTH_UNIFORMS = [\n 'u_halfSize',\n 'u_corner',\n 'u_bevel',\n 'u_morphOffset',\n 'u_morphHalf',\n 'u_morphCorner',\n 'u_morphK',\n 'u_morph2Offset',\n 'u_morph2Half',\n 'u_morph2Corner',\n 'u_shadowReach',\n 'u_touch',\n 'u_pull',\n 'u_touchRadius',\n // `satisfies`, not just `as const`: otherwise a typo in the name compiles silently and makes it\n // to runtime — the field with the garbage name gets NaN, and the real one is left un-multiplied.\n] as const satisfies readonly (keyof SurfaceUniforms)[];\n\n/**\n * Surface uniforms in device pixels. Android draws in dp and calls the adapter as-is; the web\n * needs this conversion. `u_center` isn't part of it: the renderer knows the element's center on\n * its own.\n */\nexport function toDeviceSurfaceUniforms(raw: SurfaceUniforms, density: number): SurfaceUniforms {\n const scaled: Record<string, unknown> = { ...raw };\n for (const key of SURFACE_LENGTH_UNIFORMS) {\n const value: unknown = scaled[key];\n scaled[key] = Array.isArray(value)\n ? (value as number[]).map((v) => v * density)\n : (value as number) * density;\n }\n // Of the wave, only the amplitude has a length; the phase is in turns and knows nothing about density.\n scaled.u_wave = [raw.u_wave[0] * density, raw.u_wave[1]];\n return scaled as SurfaceUniforms;\n}\n\n/** Key light direction in screen coordinates, for when the orientation response is off. */\nexport const REST_LIGHT: readonly [number, number] = [-0.577, -0.817];\n\n/** Uniforms the component mixes in inside the worklet (press, active, light direction) and via\n * the icon layer. Listed here so a test can check the shader contract's completeness without\n * importing the component itself (it pulls in Skia and doesn't come up in a node environment). */\nexport const DYNAMIC_UNIFORMS = ['u_press', 'u_active'] as const;\n\nexport const ICON_UNIFORMS = ['u_iconOn', 'u_iconScale', 'u_inkIdle', 'u_inkActive'] as const;\n\n/** App-colored overlay layer on the glass. The `u_overlay` sampler shares its contract with the\n * ink mask and is sampled at the SAME coordinate — otherwise deformation would carry them apart. */\nexport const OVERLAY_UNIFORMS = ['u_overlayOn'] as const;\n\n/**\n * Fusing two surfaces into one continuous medium.\n *\n * The second shape is described RELATIVE to the first one's center, because both live in the\n * same shader: the union has no \"two pieces of glass,\" just one body with two bulges — the mask,\n * the refraction and the rim are all computed from a single shared scene.\n *\n * `t` — how fused the shapes are: 0 turns the second shape off before any computation, 1 gives a\n * single shared medium. The seam's smoothing radius is a fraction of the smaller half-size: on\n * large elements the bridge has to be wider, otherwise the seam is left with a sharp corner,\n * which doesn't happen in a liquid.\n */\n\n\n/**\n * How wide the neck between two lobes has to be: enough to soften the seam on a large element, and\n * enough to actually SPAN whatever is between them. The second term is the one that was missing.\n */\nfunction neckFor(\n half: number,\n aw: number,\n ah: number,\n bw: number,\n bh: number,\n offsetX: number,\n offsetY: number,\n): number {\n // Surface-to-surface, measured between the bounding boxes. The rounded corners put the true\n // surfaces slightly further apart, so this errs toward a wider neck, which is the safe side.\n const gx = Math.abs(offsetX) - (aw + bw) / 2;\n const gy = Math.abs(offsetY) - (ah + bh) / 2;\n const gap = Math.hypot(Math.max(gx, 0), Math.max(gy, 0));\n // Capped at the narrowest of the two bodies. A neck wider than what it joins is not a neck, and\n // past that width the honest answer is that these are two things rather than one — a menu that\n // has finished leaving its button, two controls too far apart to be a segmented control. Being\n // separate is a legitimate state; being joined by a blob larger than either shape is not.\n const widest = Math.min(aw, ah, bw, bh);\n return Math.min(Math.max(half * MORPH.neck, neckToBridge(gap) * MORPH.fuse), widest);\n}\n\nexport function morphBetween(\n a: VireGlassGeometry,\n b: VireGlassGeometry,\n offsetX: number,\n offsetY: number,\n t: number,\n): VireGlassMorph | undefined {\n if (t <= 0) return undefined;\n const half = Math.min(halfMinDp(a), halfMinDp(b));\n return {\n offsetX,\n offsetY,\n width: b.width,\n height: b.height,\n cornerRadius: b.cornerRadius,\n smoothing: neckFor(half, a.width, a.height, b.width, b.height, offsetX, offsetY) * Math.min(t, 1),\n };\n}\n\n/**\n * MITOSIS: the second shape grows OUT OF the first and travels to its place, instead of appearing\n * beside it at full size. A menu coming out of its button, a control dividing into segments.\n *\n * `morphBetween` is the other half — two shapes that are both already where they belong, fusing\n * into one body — and run backwards it is meiosis, the neck thinning until it breaks. What neither\n * of them may do is pop: at any `t` above zero this returns one continuous body, because that is\n * the whole of what the reference says a material transition is.\n *\n * The choreography stays the host's: what the shapes MEAN is the app's business. How a silhouette\n * emerges from another silhouette is the material's, the same way the spring under a finger is.\n */\nexport function morphOutOf(\n source: VireGlassGeometry,\n target: VireGlassGeometry,\n offsetX: number,\n offsetY: number,\n t: number,\n): VireGlassMorph | undefined {\n if (t <= 0) return undefined;\n const k = Math.min(t, 1);\n // At t = 0 the lobe IS the parent, in the parent's place: the transition starts from one body and\n // never has a first frame in which a second one exists. The parent's own surface is what the neck\n // attaches to, so nothing has to be budded off to give it something to hold.\n const width = source.width + (target.width - source.width) * k;\n const height = source.height + (target.height - source.height) * k;\n const cornerRadius = source.cornerRadius + (target.cornerRadius - source.cornerRadius) * k;\n const half = Math.min(halfMinDp(source), Math.min(width, height) / 2);\n return {\n offsetX: offsetX * k,\n offsetY: offsetY * k,\n width,\n height,\n cornerRadius,\n // The lobe travels as it grows, so the span changes every frame and the neck is measured\n // against where the lobe actually is, not against where it will end up.\n smoothing: neckFor(half, source.width, source.height, width, height, offsetX * k, offsetY * k),\n };\n}\n","// The element's response to a finger — PART OF THE MATERIAL, not the app: the springs here\n// describe what the medium feels like, exactly the way ior describes what it looks like through.\n// Keeping them with the consumer would mean web and Android end up with two different glasses\n// under one name.\n//\n// It's the FIELD around the touch point that deforms (vgTouchWarp in sdf.ts), so four values are\n// computed here: where it was touched, how far it's being dragged, how deep the press is, and\n// what wave is currently running.\n//\n// The key point: drag is anchored to the touch BLOB. Pull the right edge and the right edge\n// moves, the left stays put; the finger has area, not a point — the plateau inside `vgTouchWarp`.\n// Scaling the shape's bounding box isn't an option: that would make a rightward pull also bulge\n// the left side, which liquid doesn't do.\n//\n// PRESS is viscous: it dents shallow and releases slowly.\n// DRAG is thick: the body noticeably lags the finger, travel is short, and on release it snaps\n// back quickly with almost no overshoot. A wide, springy overshoot would be liquid jelly, not\n// dense glass.\n// WAVE: touch and lift-off each throw a short ring that decays within a quarter second.\n\nimport { ACCESSIBILITY, SPRING } from './law';\n\nexport type DeformSample = {\n /** Touch point relative to the element's center, CSS pixels. */\n touchX: number;\n touchY: number;\n pullX: number;\n pullY: number;\n press: number;\n active: number;\n /** Wave amplitude in CSS pixels and its phase in turns. */\n waveAmp: number;\n wavePhase: number;\n};\n\n/**\n * `elastic: false` is reduced motion (§9): the spring and the ripple are the material's elastic\n * properties and stop, the press stays and is damped. An element that goes dead under the setting\n * would not be reduced motion — it would be no feedback at all, and the press is what lights the\n * element from within (§5), which is light rather than movement.\n */\nexport type DeformOptions = { elastic?: boolean };\n\nexport function createDeform(options: DeformOptions = {}) {\n let elastic = options.elastic !== false;\n let pressCeiling = elastic ? 1 : ACCESSIBILITY.stillPress;\n let touchX = 0;\n let touchY = 0;\n let targetTouchX = 0;\n let targetTouchY = 0;\n let pullX = 0;\n let pullY = 0;\n let vx = 0;\n let vy = 0;\n let targetX = 0;\n let targetY = 0;\n let held = false;\n let press = 0;\n let active = 0;\n let waveAmp = 0;\n let wavePhase = 0;\n\n /** `x`, `y` — touch point relative to the element's center, CSS pixels. */\n function grab(x: number, y: number, waveStart: number): void {\n // Rest is checked BEFORE the grab: idle() looks at !held, and after `held = true` it's\n // always false — the point would then jump even on a first touch of a resting element.\n const atRest = idle();\n held = true;\n targetTouchX = x;\n targetTouchY = y;\n // On a resting element the finger lands instantly; if it hasn't settled yet from the\n // previous touch, the point travels there over a couple of frames. An instant jump tears the\n // deformation, and on rapid taps that reads as jitter.\n if (atRest) {\n touchX = x;\n touchY = y;\n }\n targetX = 0;\n targetY = 0;\n // Impulses ADD UP rather than restart, and phase isn't reset: resetting it would cut off a\n // running wave mid-period, which is exactly what causes a jolt on rapid clicks.\n if (elastic) waveAmp = Math.min(waveAmp + waveStart, waveStart * SPRING.waveCapOnGrab);\n }\n\n function drag(dx: number, dy: number, limit: number): void {\n if (!held || !elastic) return;\n const len = Math.hypot(dx, dy);\n // Travel saturates rather than clips: near the limit the finger keeps moving while the field\n // barely does — that's how a thick liquid behaves once it hits its limit.\n const scale = len > 1e-3 ? (limit * Math.tanh(len / limit)) / len : 0;\n targetX = dx * scale;\n targetY = dy * scale;\n }\n\n /** Lifting the finger throws a second wave — weaker than the one from touching down. */\n function release(waveStart: number): void {\n held = false;\n targetX = 0;\n targetY = 0;\n if (elastic) waveAmp = Math.min(waveAmp + waveStart, waveStart * SPRING.waveCapOnRelease);\n }\n\n function integrate(dt: number): void {\n const k = held ? SPRING.holdStiffness : SPRING.releaseStiffness;\n const c = held ? SPRING.holdDamping : SPRING.releaseDamping;\n vx += (k * (targetX - pullX) - c * vx) * dt;\n vy += (k * (targetY - pullY) - c * vy) * dt;\n pullX += vx * dt;\n pullY += vy * dt;\n\n const pressTarget = held ? pressCeiling : 0;\n const tau = held ? SPRING.pressAttack : SPRING.pressRelease;\n press += (pressTarget - press) * (1 - Math.exp(-dt / tau));\n active += (pressTarget - active) * (1 - Math.exp(-dt / SPRING.activeFollow));\n\n // The touch point catches up to the finger fast, but not instantly — see grab().\n const follow = 1 - Math.exp(-dt / SPRING.pointFollow);\n touchX += (targetTouchX - touchX) * follow;\n touchY += (targetTouchY - touchY) * follow;\n\n wavePhase += dt * SPRING.waveTurnsPerSecond;\n waveAmp *= Math.exp(-dt / SPRING.waveDecay);\n if (waveAmp < 0.01) waveAmp = 0;\n }\n\n /**\n * The step is fixed, the frame isn't: on a software renderer there can be as few as ten frames\n * a second, and integrating \"however much time passed\" makes the response lag behind real time\n * (and at a large step the spring can even diverge). So time is caught up in sub-steps.\n */\n function step(dt: number): void {\n let rest = Math.min(Math.max(dt, 0), 0.25);\n const h = 1 / 120;\n while (rest > 1e-6) {\n const slice = Math.min(h, rest);\n integrate(slice);\n rest -= slice;\n }\n // Settled means exactly at rest. The `idle()` threshold stops rendering, but the values\n // themselves only approach zero asymptotically, and the element would stay forever very\n // slightly deformed: invisible to the eye, but a frame-vs-reference comparison would flag the\n // mismatch forever.\n if (idle()) {\n pullX = 0;\n pullY = 0;\n vx = 0;\n vy = 0;\n press = 0;\n active = 0;\n wavePhase = 0;\n }\n }\n\n /** Whether the element has settled — the bench uses this to decide whether to keep drawing frames. */\n function idle(): boolean {\n return (\n !held &&\n Math.abs(pullX) < 0.05 &&\n Math.abs(pullY) < 0.05 &&\n Math.hypot(vx, vy) < 0.5 &&\n press < 0.004 &&\n active < 0.004 &&\n waveAmp === 0\n );\n }\n\n /** The setting can be turned on while the page is open, and a deformation already in flight has\n * to stop rather than finish. */\n function setElastic(on: boolean): void {\n if (on === elastic) return;\n elastic = on;\n pressCeiling = on ? 1 : ACCESSIBILITY.stillPress;\n if (!on) {\n pullX = 0;\n pullY = 0;\n vx = 0;\n vy = 0;\n targetX = 0;\n targetY = 0;\n waveAmp = 0;\n wavePhase = 0;\n }\n }\n\n function sample(): DeformSample {\n return { touchX, touchY, pullX, pullY, press, active, waveAmp, wavePhase };\n }\n\n return { grab, drag, release, step, idle, sample, setElastic };\n}\n\n/**\n * RAISING INTO GLASS (reference §5, M 4:10–4:30). A control that isn't glass at rest — a switch\n * knob, a slider handle — stops being frosted under the finger and becomes a lens: whatever is\n * beneath it shows through.\n *\n * Glass comes in FASTER than frost leaves: the two fractions overlap, otherwise midway through\n * the transition the backdrop flashes through the knob for an instant — a hole where the control\n * should be.\n *\n * Lifting off the backdrop is NOT part of this. The shader's `u_lift` is a direction (\"this kind\n * of element sinks in or rises\"), not a magnitude — how far it has already risen is carried by\n * the press value that `u_lift` gets multiplied by. Returning a third fraction here would mean\n * multiplying press by itself — which is exactly what happened the first time the web bench wired\n * this up.\n */\nexport function raiseIntoGlass(press: number): { glass: number; solid: number } {\n const t = press < 0 ? 0 : press > 1 ? 1 : press;\n return { glass: Math.pow(t, 0.6), solid: 1 - Math.pow(t, 1.4) };\n}\n","// Scroll edge effect (reference 219 @8:52) — the SCREEN's job, not the material's: it sits over\n// the content beneath the panel, and the glass sees an already-dimmed backdrop. Only the general\n// rules live here.\nimport { SCROLL_EDGE } from './law';\n\n/**\n * 356 @11:48 names two styles across the system, \"soft and hard\", and says not to mix or stack\n * them. Soft is the default; hard is \"a stronger, more opaque boundary\", mostly macOS, for pinned\n * table headers and controls without backgrounds.\n *\n * Soft has two forms, and which one is in play is not a choice: 219 @9:16 dissolves the content\n * into the background, and @9:33, when darker content scrolls under and the glass itself turns to\n * its dark style, \"the effect intelligently switches to apply a subtle dimming instead\". Same\n * trigger as ink polarity, because it is the same problem — dark content under dark glass merges\n * with it unless the content is pushed down.\n */\nexport type ScrollEdgeStyle = 'dissolve' | 'dim' | 'hard';\n\nexport function scrollEdgeStyle(inkLight: boolean, pinned = false): ScrollEdgeStyle {\n if (pinned) return 'hard';\n return inkLight ? 'dim' : 'dissolve';\n}\n\n/** How far the content has to slide under the panel for the effect to fully engage, dp. */\nexport const SCROLL_EDGE_ENGAGE_DP = SCROLL_EDGE.engageDp;\n\n/**\n * How tall to make the edge, given the bar it sits under. The host positions the element; without\n * this it has to guess a height, and the reference has an answer — measured off the footage rather\n * than chosen (see `SCROLL_EDGE.reachOfBarHeight`).\n */\nexport function scrollEdgeReachDp(barHeightDp: number): number {\n return Math.max(barHeightDp, 0) * SCROLL_EDGE.reachOfBarHeight;\n}\n\n/**\n * Edge strength as a function of scroll. With no scroll, content near the top doesn't slide\n * under the panel yet — so there's no effect (a mail screen at the top: the header sits on a\n * clean background). At the bottom, content slides under it for as long as there's room left\n * to scroll.\n */\nexport function scrollEdgeStrength(side: 'top' | 'bottom', scroll: number, maxScroll: number): number {\n const room = side === 'top' ? scroll : maxScroll - scroll;\n return Math.min(Math.max(room / SCROLL_EDGE_ENGAGE_DP, 0), 1);\n}\n","// The scroll edge (docs/reference.md §10). Not the material's job but the SCREEN's: it sits over\n// the content beneath a panel, and the glass sees a backdrop that is already dimmed. The rules are\n// the core's (`../scroll-edge`); this attaches them to a real scroller and a real element.\nimport { SCROLL_EDGE } from '../law';\nimport { scrollEdgeStrength, scrollEdgeStyle, type ScrollEdgeStyle } from '../scroll-edge';\n\nexport type ScrollEdgeHandle = { update(): void; destroy(): void };\n\nexport type ScrollEdgeOptions = {\n /** Which edge of the scroller the panel sits at. */\n side?: 'top' | 'bottom';\n /** A view pinned under the panel — column headers — gets a flat band with no gradient (§10). */\n pinned?: boolean;\n /** Ink polarity of the nearest glass, 1 light and 0 dark. The edge style follows it: light ink\n * means dark glass and the content fades into a light dimming; dark ink means the opposite. */\n ink?: () => number;\n};\n\n/**\n * What the effect actually is. 356 @11:32: \"they don't block or darken like overlays.\"\n *\n * So the soft style is a BLUR with a mask, not a painted gradient: the content under the panel\n * goes out of focus into the background, which is what 219 @9:16 means by dissolving it, and\n * nothing is laid over it. The first version of this painted black at 22% down the ramp — an\n * overlay, doing the one thing the reference names as wrong.\n *\n * `dim` is the other soft form and it does carry a tone, because 219 @9:33 asks for one: over dark\n * content the glass turns dark and \"the effect intelligently switches to apply a subtle dimming\n * instead\". Dimming is a reduction in luminance. This painted white, which lightened the content\n * it was supposed to be pushing down.\n */\nexport type EdgePaint = { filter: string; mask: string; tone: string };\n\nexport function paintFor(style: ScrollEdgeStyle, side: 'top' | 'bottom'): EdgePaint {\n const direction = side === 'top' ? 'to top' : 'to bottom';\n if (style === 'hard') {\n // A flat band rather than a gradual fade (219 @9:41), and a stronger boundary (356 @12:12).\n return {\n filter: `blur(${SCROLL_EDGE.hardBlurDp}px)`,\n mask: '',\n tone: `linear-gradient(${direction}, rgba(0,0,0,${SCROLL_EDGE.hardAlpha}) 0 100%)`,\n };\n }\n const ramp = `linear-gradient(${direction}, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 100%)`;\n return {\n filter: `blur(${SCROLL_EDGE.dissolveBlurDp}px)`,\n mask: ramp,\n tone:\n style === 'dim'\n ? `linear-gradient(${direction}, rgba(0,0,0,${SCROLL_EDGE.dimAlpha}) 0%, rgba(0,0,0,0) 100%)`\n : 'none',\n };\n}\n\n/**\n * Paints the edge onto `edgeEl` — an element the host positions along the scroller's edge, under\n * the glass. It is the host's because §10 puts this on the screen, not on the material: the glass\n * must SEE the result, which means the effect has to be behind it in the stack.\n */\nexport function attachScrollEdge(\n scroller: HTMLElement,\n edgeEl: HTMLElement,\n opts: ScrollEdgeOptions = {},\n): ScrollEdgeHandle {\n const side = opts.side ?? 'top';\n let destroyed = false;\n\n function update(): void {\n if (destroyed) return;\n const maxScroll = Math.max(scroller.scrollHeight - scroller.clientHeight, 0);\n const strength = scrollEdgeStrength(side, scroller.scrollTop, maxScroll);\n const inkLight = (opts.ink?.() ?? 1) > 0.5;\n const style = scrollEdgeStyle(inkLight, opts.pinned);\n const paint = paintFor(style, side);\n // The blur is what dissolves the content; the mask is what makes it a ramp rather than a step.\n edgeEl.style.setProperty('backdrop-filter', paint.filter);\n edgeEl.style.setProperty('-webkit-backdrop-filter', paint.filter);\n if (paint.mask) {\n edgeEl.style.setProperty('mask-image', paint.mask);\n edgeEl.style.setProperty('-webkit-mask-image', paint.mask);\n } else {\n edgeEl.style.removeProperty('mask-image');\n edgeEl.style.removeProperty('-webkit-mask-image');\n }\n edgeEl.style.setProperty('background-image', paint.tone);\n edgeEl.style.setProperty('opacity', strength.toFixed(3));\n }\n\n const onScroll = () => update();\n scroller.addEventListener('scroll', onScroll, { passive: true });\n update();\n\n return {\n update,\n destroy() {\n destroyed = true;\n scroller.removeEventListener('scroll', onScroll);\n edgeEl.style.removeProperty('backdrop-filter');\n edgeEl.style.removeProperty('-webkit-backdrop-filter');\n edgeEl.style.removeProperty('mask-image');\n edgeEl.style.removeProperty('-webkit-mask-image');\n edgeEl.style.removeProperty('background-image');\n edgeEl.style.removeProperty('opacity');\n },\n };\n}\n","import { CONFIRMATIONS, FLIP_LUMA, RETURN_LUMA, type BackdropSample } from './adaptation';\n\n/**\n * GLASS GROUP ESTIMATE — the pure part of the surface group (`glass-group.tsx`).\n *\n * Everything that decides lives here: the lightness plane from members' samples, the group's\n * aggregates, the polarity requirement and its hysteresis. None of these rules need React or the\n * native layer, so they live apart from the component and are checked by a unit test.\n */\n\nexport type GroupMember = { x: number; y: number; sample: BackdropSample; legibility: number };\n\n/** Group estimate: center and average lightness, slope along x, the lightest spot, and the\n * measurement values shared by everyone — [variegation, lo, hi, r, g, b]. */\nexport type GroupPlane = {\n mx: number;\n ml: number;\n slope: number;\n base: number;\n rest: number[];\n};\n\n/** Input to the polarity decision: the lightness the group judges by, and the strictest of the requirements. */\nexport type GroupDecision = { decisive: number; legibility: number };\n\n/** Fraction of a new sample in the smoothed estimate. Samples come in from every member, so the\n * group collects roughly twenty a second — a quarter is enough for a response within ~200 ms. */\nexport const SMOOTH = 0.25;\n\n/** The remainder below which smoothing snaps the value to the sample. An exponential never\n * actually reaches its target, and the estimate kept \"changing\" by denormals for two more\n * minutes after the backdrop had settled. */\nexport const SETTLE = 1e-6;\n\n/**\n * Fraction of the slope that reaches the members.\n *\n * A plane through four points nearly interpolates them: right at a black/white border, buttons\n * were getting 0.0, 0.3, 0.7 and 1.0 — that is, exactly their own individual values, and the\n * group fell apart into independent elements again. Density is set by the group's LIGHTEST spot;\n * the slope only lets it off slightly at the dark end.\n */\nexport const GRADIENT = 0.35;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * Lightness plane from members' samples. The slope is a least-squares fit along x: the group's\n * members stand in a row, and one axis is enough — there's no vertical spread among them. The\n * coordinates are centered, so the normal equations decouple.\n */\nfunction fitLuma(members: readonly GroupMember[]): {\n mx: number;\n ml: number;\n slope: number;\n} {\n const n = members.length;\n let mx = 0;\n let ml = 0;\n for (const m of members) {\n mx += m.x;\n ml += m.sample.luma;\n }\n mx /= n;\n ml /= n;\n let sxx = 0;\n let sxl = 0;\n for (const m of members) {\n const dx = m.x - mx;\n sxx += dx * dx;\n sxl += dx * m.sample.luma;\n }\n return { mx, ml, slope: sxx > 1e-6 ? sxl / sxx : 0 };\n}\n\n/** Group estimate from its members. An empty group has nothing to estimate — that's `null`. */\nexport function aggregate(\n members: readonly GroupMember[],\n): { plane: GroupPlane; decision: GroupDecision } | null {\n if (members.length === 0) return null;\n\n const { mx, ml, slope } = fitLuma(members);\n let busy = 0;\n let lo = 1;\n let hi = 0;\n // The group's lightest SPOT: density for everyone is computed from it. Otherwise, right at a\n // black/white border the group would hold to the average, a light ink would never darken\n // against anything, and it would drown over the light half.\n let base = 0;\n let r = 0;\n let g = 0;\n let b = 0;\n // The legibility requirement is the group's strictest: polarity is one for all, and going by\n // the weakest requirement would leave a neighbor with pickier optics illegible.\n let legibility = 0;\n for (const m of members) {\n busy = Math.max(busy, m.sample.busy);\n lo = Math.min(lo, m.sample.lo);\n hi = Math.max(hi, m.sample.hi);\n base = Math.max(base, m.sample.luma);\n r += m.sample.r;\n g += m.sample.g;\n b += m.sample.b;\n legibility = Math.max(legibility, m.legibility);\n }\n const k = members.length;\n return {\n plane: { mx, ml, slope, base, rest: [busy, lo, hi, r / k, g / k, b / k] },\n // The polarity decision is one per group, by its AVERAGE lightness. Deciding on its own,\n // each button used to end up a different color over a busy backdrop.\n decision: { decisive: ml * 0.75 + hi * 0.25, legibility },\n };\n}\n\n/**\n * Smoothing runs over samples, not frames: the native lens smooths ITS OWN estimate, and the\n * group estimate overrides it with an already-finished value. Without this the group's tone\n * changed in steps — the probe's 180 ms cadence is too coarse for the adaptation to read as\n * unnoticeable.\n */\nexport function smoothPlane(prev: GroupPlane | null, next: GroupPlane): GroupPlane {\n if (!prev) return next;\n const e = (was: number, now: number) =>\n Math.abs(now - was) < SETTLE ? now : was + (now - was) * SMOOTH;\n const ml = e(prev.ml, next.ml);\n const slope = e(prev.slope, next.slope);\n const base = e(prev.base, next.base);\n const rest = next.rest.map((v, i) => e(prev.rest[i], v));\n // A converged estimate is handed back as the same object: otherwise `setPlane` would repaint\n // the group on every sample — twenty times a second, even on a still screen.\n const same =\n next.mx === prev.mx &&\n ml === prev.ml &&\n slope === prev.slope &&\n base === prev.base &&\n rest.every((v, i) => v === prev.rest[i]);\n return same ? prev : { mx: next.mx, ml, slope, base, rest };\n}\n\n/** The sample a member at position `x` hands its own lens — in the order of its prop. */\nexport function probeValuesAt(plane: GroupPlane, x: number): number[] {\n // Down from the group's lightest spot — by exactly as much as that spot is darker along the\n // plane, and even then only a GRADIENT fraction of it. This lets the dark end off on density,\n // without canceling it: the group stays a single material.\n const here = plane.ml + plane.slope * (x - plane.mx);\n const luma = clamp01(plane.base - (plane.base - here) * GRADIENT);\n // The slope doesn't carry over into the lens: the group's is measured in screen dp, while the\n // shader multiplies `u_probeSlope` by a normalized position within the element — different\n // units.\n return [luma, plane.rest[0], plane.rest[1], plane.rest[2], 0, 0, plane.rest[3], plane.rest[4], plane.rest[5]];\n}\n\n/** Whether the group needs to flip ink polarity given the current one (1 light, 0 dark). */\nfunction wantsPolarityChange(decision: GroupDecision, polarity: number): boolean {\n return polarity === 1 ? decision.decisive >= FLIP_LUMA : decision.decisive < RETURN_LUMA;\n}\n\nexport type GroupSink = {\n /** The group estimate has been recomputed: members take their values from it. */\n plane: (plane: GroupPlane | null) => void;\n /** The group flips ink polarity for everyone at once. */\n flip: (polarity: number) => void;\n};\n\nexport type GroupState = {\n report: (\n id: string,\n x: number,\n y: number,\n sample: BackdropSample,\n legibility: number,\n ) => void;\n release: (id: string) => void;\n plane: () => GroupPlane | null;\n polarity: () => number;\n confirmations: () => number;\n};\n\n/** Group state: members, the smoothed estimate, and polarity hysteresis. */\nexport function createGroupState(sink: GroupSink): GroupState {\n const members = new Map<string, GroupMember>();\n let plane: GroupPlane | null = null;\n let pending = 0;\n let polarity = 1;\n\n const measure = (): GroupDecision | null => {\n const next = aggregate([...members.values()]);\n if (!next) {\n pending = 0;\n plane = null;\n sink.plane(null);\n return null;\n }\n plane = smoothPlane(plane, next.plane);\n sink.plane(plane);\n return next.decision;\n };\n\n return {\n report(id, x, y, sample, legibility) {\n members.set(id, { x, y, sample, legibility });\n const decision = measure();\n if (!decision) return;\n if (!wantsPolarityChange(decision, polarity)) {\n pending = 0;\n return;\n }\n pending += 1;\n if (pending < CONFIRMATIONS) return;\n pending = 0;\n polarity = polarity === 1 ? 0 : 1;\n sink.flip(polarity);\n },\n // Only recomputes the estimate: losing a member isn't a backdrop sample and can't count as a\n // polarity confirmation — unmounting the group used to rack up CONFIRMATIONS instantly and\n // trigger a recolor nobody was left to cancel.\n release(id) {\n if (members.delete(id)) measure();\n },\n plane: () => plane,\n polarity: () => polarity,\n confirmations: () => pending,\n };\n}\n","// A row of glass that agrees with itself.\n//\n// Each element probing on its own is not merely wasteful — it is wrong. Neighbouring pieces of one\n// control sit over slightly different patches of backdrop, reach different polarities, and a tab\n// bar ends up with two light glyphs and two dark ones. §3 is explicit that small elements switch\n// WHOLESALE; a group is what \"wholesale\" means when the element is really four of them.\n//\n// Every decision is the core's (`../group-model`): the lightness plane, the smoothing, the polarity\n// requirement and its hysteresis. This binds them to real elements.\nimport { createGroupState, type GroupPlane } from '../group-model';\nimport { TOUCH } from '../law';\nimport { probeBackdrop } from './probe';\nimport type { BackdropSample } from '../adaptation';\nimport type { GlassHandle } from './index';\n\nexport type GroupEntry = {\n el: HTMLElement;\n handle: GlassHandle;\n /** Set by the group: pass it to this member's own `attachGlass` as `onGlow`. */\n onGlow?: (glow: { pageX: number; pageY: number; strength: number } | null) => void;\n /** How strongly this member needs its ink to stay legible. The strictest in the group wins. */\n legibility?: number;\n};\n\nexport type GlassGroupHandle = {\n /** Re-read every member and settle on one answer for all of them. */\n update(): void;\n /** The polarity the whole group agreed on, 1 light and 0 dark. */\n ink(): number;\n /** The group's current estimate, or null before the first reading. */\n plane(): GroupPlane | null;\n /** Spread a glow from one member to the rest. Members wired through `onGlow` call this for you. */\n carryGlow(from: number, glow: { pageX: number; pageY: number; strength: number } | null): void;\n destroy(): void;\n};\n\nexport type GlassGroupOptions = {\n /** Where a member reads its backdrop. Defaults to the DOM probe. */\n probe?: (el: HTMLElement) => BackdropSample;\n};\n\nexport function createGlassGroup(\n members: readonly GroupEntry[],\n opts: GlassGroupOptions = {},\n): GlassGroupHandle {\n let polarity = 1;\n let destroyed = false;\n\n const state = createGroupState({\n plane: () => {},\n flip: (next) => {\n polarity = next;\n // One flip, everyone at once — that is the whole point of the group.\n for (const { handle } of members) handle.update();\n },\n });\n\n /**\n * \"Starting right under your fingertips, the glow spreads throughout the element and onto any\n * Liquid Glass elements nearby\" (§5, 219 @12:11). The element being touched cannot know who is\n * nearby; the group does.\n */\n function carryGlow(from: number, glow: { pageX: number; pageY: number; strength: number } | null): void {\n members.forEach(({ el, handle }, index) => {\n if (index === from) return;\n if (!glow) {\n handle.setNeighbourGlow(null);\n return;\n }\n const rect = el.getBoundingClientRect();\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n const reach = (Math.min(rect.width, rect.height) / 2) * TOUCH.glowReach;\n const distance = Math.hypot(glow.pageX - cx, glow.pageY - cy);\n // Falls off with distance and stops: a glow that reached the whole screen would read as the\n // page flashing rather than as light travelling through neighbouring glass.\n const falloff = reach > 0 ? Math.max(0, 1 - distance / reach) : 0;\n handle.setNeighbourGlow(falloff <= 0 ? null : { ...glow, strength: glow.strength * falloff });\n });\n }\n\n /** Wire each member's own touch to the rest of the group. */\n function connect(): void {\n members.forEach((entry, index) => {\n entry.onGlow = (glow) => carryGlow(index, glow);\n });\n }\n\n function update(): void {\n if (destroyed) return;\n const probe = opts.probe ?? probeBackdrop;\n members.forEach(({ el, legibility }, index) => {\n const rect = el.getBoundingClientRect();\n // A member with no box has nothing behind it to read; reporting it anyway would drag the\n // group's estimate toward whatever sits at the page's origin.\n if (rect.width <= 0 || rect.height <= 0) {\n state.release(String(index));\n return;\n }\n state.report(\n String(index),\n rect.left + rect.width / 2,\n rect.top + rect.height / 2,\n probe(el),\n legibility ?? 0,\n );\n });\n }\n\n connect();\n update();\n\n return {\n update,\n ink: () => polarity,\n plane: () => state.plane(),\n carryGlow,\n destroy() {\n destroyed = true;\n carryGlow(-1, null);\n members.forEach((_, index) => state.release(String(index)));\n },\n };\n}\n","// The third VireGlass renderer: refracts LIVE DOM via `backdrop-filter: url(#svg-filter)` with an\n// `feDisplacementMap`, instead of drawing its own backdrop like the WebGL2 and AGSL renderers do.\n//\n// Everything is derived from the same model the shaders read, and where a law already exists in\n// the core or in the shader text, this mirrors it rather than restating it: the rim's two arcs are\n// the lens's own key-light lobe, the shadow is `shadowOpacityFrom`, dispersion is the shader's\n// per-channel index shift, and the finger response is `createDeform` driving the same `touchWarp`.\n//\n// Even the spectral edge, which looked impossible: a filter graph cannot evaluate a function per\n// pixel, but it can MULTIPLY by an image, so diffraction and interference are baked into one and\n// applied with an arithmetic composite.\n// See `docs/superpowers/specs/2026-09-19-vireglass-over-live-dom.md` for the technique and the\n// three findings that make it work (objectBoundingBox, prefiltering the source, the 8-bit step).\nimport { ambientFrom, INK_DARK, INK_LIGHT, shouldInkBeLight, type BackdropSample } from '../adaptation';\nimport { buildDisplacementMap } from './displacement';\nimport { buildSpectralMap, hasSpectralEdge, type SpectralMap } from './spectral-map';\nimport { cached } from './map-cache';\nimport { roundedRectGeometry, type VireGlassGeometry } from '../geometry';\nimport { resolveOptics, VIREGLASS_MATERIAL, type VireGlassMaterial, type VireGlassOptics } from '../material';\nimport { probeBackdrop } from './probe';\nimport { supportsSvgBackdropFilter } from './support';\nimport { boxShadowCss } from './shadow';\nimport { resolveBody, withPresence } from './body';\nimport { systemAccessibility, watchAccessibility } from './preferences';\nimport { applyAccessibility, contrastRimLuma, elasticAllowed, type VireGlassAccessibility } from '../accessibility';\nimport { applyGlassScale, GLASS_SCALE_DEFAULT } from '../glass-scale';\nimport { applyAppear } from '../appear';\nimport { accentAmount, accentTone } from '../accent';\nimport type { VireGlassAccent } from '../adapters';\nimport { concentricRadius } from '../concentric';\nimport { RIM_WIDTH_PX, contrastRimCss, rimGradientCss } from './rim';\nimport { GLASS_ATTR, warnIfNested } from './nesting';\nimport { REST_LIGHT } from '../adapters';\nimport { refractionStrength } from '../optics';\nimport { DISPERSION, TOUCH } from '../law';\nimport type { MorphShape } from '../sdf';\nimport { createDeform, raiseIntoGlass, type DeformSample } from '../touch-response';\nimport { halfMinDp, MAX_STRETCH } from '../geometry';\n\nexport * from './support';\nexport * from './probe';\nexport * from './displacement';\nexport * from './rim';\nexport * from './shadow';\nexport * from './body';\nexport * from './preferences';\nexport * from './scroll-edge';\nexport * from './group';\nexport * from './spectral-map';\nexport * from './map-cache';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst FILTER_HOST_ATTR = 'data-vireglass-filters';\n\nlet filterCounter = 0;\n\n/** Live instances keyed by element, so a second attach can retire the first rather than orphan\n * its filter. Weak: a detached element takes its entry with it. */\nconst attached = new WeakMap<HTMLElement, GlassHandle>();\n\nconst TOUCH_RADIUS_FRACTION = TOUCH.radiusOfHalfSize;\n\nconst WAVE_OF_TRAVEL = TOUCH.waveOfTravel;\nconst RELEASE_WAVE = TOUCH.releaseWave;\n\nfunction waveImpulse(g: VireGlassGeometry): number {\n return halfMinDp(g) * MAX_STRETCH * WAVE_OF_TRAVEL;\n}\n\nconst STYLE_ATTR = 'data-vireglass-styles';\n\n\n/**\n * The hairline rim (docs/reference.md §2) needs a layer of its own over the element. A stylesheet\n * rule on `::after` keeps it out of the host's markup — injecting a child node would fight any\n * framework that owns these children.\n *\n * The mask pair is what makes it a ring rather than a fill: the same box painted twice, once\n * clipped to the content box, composited so only the padding band survives.\n */\n/**\n * Where the filter and the rim styles go.\n *\n * `backdrop-filter: url(#id)` resolves the reference in the element's OWN tree. From inside a\n * shadow root, a filter parked on the page is not found — and the failure is silent, because the\n * reference is valid CSS: the element gets no backdrop at all, not even the blur fallback. A\n * widget in a shadow root (which is how you survive a page full of global `!important`) came out\n * with no material whatsoever.\n *\n * So the host is the element's own root node, which is the shadow root when there is one and the\n * document otherwise. Nothing to configure and nothing to get wrong.\n */\nfunction hostFor(el: Element): Document | ShadowRoot {\n const root = el.getRootNode();\n return root instanceof ShadowRoot ? root : el.ownerDocument ?? document;\n}\n\n/** A shadow root has no `<head>`; a style element goes straight into it. */\nfunction styleParent(host: Document | ShadowRoot): Node {\n return host instanceof ShadowRoot ? host : host.head;\n}\n\nfunction ensureRimStyles(host: Document | ShadowRoot): void {\n if (host.querySelector(`style[${STYLE_ATTR}]`)) return;\n const style = document.createElement('style');\n style.setAttribute(STYLE_ATTR, '');\n style.textContent =\n `[${GLASS_ATTR}]::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;padding:var(--vireglass-rim-width,1px);background:var(--vireglass-rim,none);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}` +\n // The touch glow (§5) lights the material from the point of contact. Below the content, above\n // the refraction — it is light inside the glass, not a film over the label.\n `[${GLASS_ATTR}]::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:var(--vireglass-glow,none);opacity:var(--vireglass-glow-opacity,0)}`;\n styleParent(host).appendChild(style);\n}\n\nfunction getFilterHost(host: Document | ShadowRoot): SVGSVGElement {\n const existing = host.querySelector<SVGSVGElement>(`svg[${FILTER_HOST_ATTR}]`);\n if (existing) return existing;\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute(FILTER_HOST_ATTR, '');\n svg.setAttribute('width', '0');\n svg.setAttribute('height', '0');\n svg.setAttribute('aria-hidden', 'true');\n svg.style.position = 'absolute';\n svg.style.pointerEvents = 'none';\n svg.appendChild(document.createElementNS(SVG_NS, 'defs'));\n // A shadow root takes the svg directly; a document takes it on the body.\n (host instanceof ShadowRoot ? host : host.body).appendChild(svg);\n return svg;\n}\n\n/**\n * Finding #1 (do not re-litigate): `objectBoundingBox` with an explicit unit box. `userSpaceOnUse`\n * measures from something other than the element's own box and the displacement smears across\n * the page instead of staying at the rim.\n */\nfunction buildFilterElement(\n id: string,\n mapUrl: string,\n optics: VireGlassOptics,\n scale: number,\n spectral: SpectralMap | null,\n): SVGFilterElement {\n const filter = document.createElementNS(SVG_NS, 'filter');\n filter.setAttribute('id', id);\n filter.setAttribute('filterUnits', 'objectBoundingBox');\n filter.setAttribute('x', '0');\n filter.setAttribute('y', '0');\n filter.setAttribute('width', '1');\n filter.setAttribute('height', '1');\n // Without this the spec's default is linearRGB: the browser gamma-linearises the map's bytes\n // before reading them, so 128 stops meaning \"no shift\" and the flat middle of the glass drifts\n // by several pixels. Measured at ~57px of spurious displacement at scale 200.\n filter.setAttribute('color-interpolation-filters', 'sRGB');\n\n const feImage = document.createElementNS(SVG_NS, 'feImage');\n feImage.setAttribute('href', mapUrl);\n feImage.setAttribute('preserveAspectRatio', 'none');\n feImage.setAttribute('result', 'map');\n\n // Finding #2: prefiltering the source before displacement. This is `roughness`, not a hack —\n // without it, fine texture (1px diagonals) resamples into chevrons under the displacement.\n const feBlur = document.createElementNS(SVG_NS, 'feGaussianBlur');\n feBlur.setAttribute('in', 'SourceGraphic');\n feBlur.setAttribute('stdDeviation', String(Math.max(optics.blur, 0)));\n feBlur.setAttribute('result', 'blurred');\n\n filter.append(feImage, feBlur);\n\n // DISPERSION (docs/reference.md §1, and `lens-shader.ts` lines 283–284 for the law): the channels\n // refract at different indices — red at `ior - 0.4 * iorSpread`, blue at `ior + 0.6 * iorSpread`,\n // green at the base. One displacement pass cannot do that, so each channel gets its own and they\n // are summed back. Three passes instead of one, so it only runs when the spread is worth paying\n // for.\n const spread = optics.iorSpread;\n if (spread > 1e-4) {\n const base = refractionStrength(optics.ior);\n const ratio = (shift: number) => (base > 0 ? refractionStrength(optics.ior + shift) / base : 1);\n const channels: Array<[string, number, string]> = [\n ['dR', scale * ratio(DISPERSION.redShift * spread), '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'],\n ['dG', scale, '0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0'],\n ['dB', scale * ratio(DISPERSION.blueShift * spread), '0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0'],\n ];\n for (const [name, chScale, matrix] of channels) {\n const pass = document.createElementNS(SVG_NS, 'feDisplacementMap');\n pass.setAttribute('in', 'blurred');\n pass.setAttribute('in2', 'map');\n pass.setAttribute('scale', String(chScale));\n pass.setAttribute('xChannelSelector', 'R');\n pass.setAttribute('yChannelSelector', 'G');\n pass.setAttribute('result', `${name}raw`);\n // Each channel displaces by its own share of the base scale. The share is stored on the\n // element itself: under a press the scale is recomputed every frame, with nowhere else to\n // recover the shares from.\n pass.setAttribute('data-vireglass-ratio', String(scale > 0 ? chScale / scale : 1));\n const only = document.createElementNS(SVG_NS, 'feColorMatrix');\n only.setAttribute('in', `${name}raw`);\n only.setAttribute('type', 'matrix');\n only.setAttribute('values', matrix);\n only.setAttribute('result', name);\n filter.append(pass, only);\n }\n // Arithmetic add, not a blend: every channel is isolated, so the sum is the recombined colour.\n // Alpha stays at 1 on all three and clamps, which is what an opaque backdrop wants.\n const rg = document.createElementNS(SVG_NS, 'feComposite');\n rg.setAttribute('in', 'dR');\n rg.setAttribute('in2', 'dG');\n rg.setAttribute('operator', 'arithmetic');\n rg.setAttribute('k1', '0');\n rg.setAttribute('k2', '1');\n rg.setAttribute('k3', '1');\n rg.setAttribute('k4', '0');\n rg.setAttribute('result', 'dRG');\n const rgb = document.createElementNS(SVG_NS, 'feComposite');\n rgb.setAttribute('in', 'dRG');\n rgb.setAttribute('in2', 'dB');\n rgb.setAttribute('operator', 'arithmetic');\n rgb.setAttribute('k1', '0');\n rgb.setAttribute('k2', '1');\n rgb.setAttribute('k3', '1');\n rgb.setAttribute('k4', '0');\n rgb.setAttribute('result', 'refracted');\n filter.append(rg, rgb);\n return withSpectral(filter, spectral);\n }\n\n const feDisplace = document.createElementNS(SVG_NS, 'feDisplacementMap');\n feDisplace.setAttribute('in', 'blurred');\n feDisplace.setAttribute('in2', 'map');\n feDisplace.setAttribute('scale', String(scale));\n feDisplace.setAttribute('xChannelSelector', 'R');\n feDisplace.setAttribute('yChannelSelector', 'G');\n feDisplace.setAttribute('result', 'refracted');\n filter.append(feDisplace);\n return withSpectral(filter, spectral);\n}\n\n/**\n * Multiplies the refracted frame by the baked hue (docs/reference.md §1). `feComposite` in\n * arithmetic mode with `k1` is a per-pixel product, which is the only way a filter graph can apply\n * a function of position. The headroom the bake divided by is multiplied back here.\n */\nfunction withSpectral(filter: SVGFilterElement, spectral: SpectralMap | null): SVGFilterElement {\n if (!spectral) return filter;\n const image = document.createElementNS(SVG_NS, 'feImage');\n image.setAttribute('href', spectral.url);\n image.setAttribute('preserveAspectRatio', 'none');\n image.setAttribute('result', 'hue');\n const product = document.createElementNS(SVG_NS, 'feComposite');\n product.setAttribute('in', 'refracted');\n product.setAttribute('in2', 'hue');\n product.setAttribute('operator', 'arithmetic');\n product.setAttribute('k1', String(spectral.headroom));\n product.setAttribute('k2', '0');\n product.setAttribute('k3', '0');\n product.setAttribute('k4', '0');\n filter.append(image, product);\n return filter;\n}\n\nfunction measureGeometry(el: HTMLElement): VireGlassGeometry {\n const rect = el.getBoundingClientRect();\n // Uniform corner radius only, matching `VireGlassGeometry` itself — a per-corner or elliptical\n // radius isn't modeled by any renderer in this package.\n const radius = parseFloat(getComputedStyle(el).borderTopLeftRadius) || 0;\n return roundedRectGeometry(rect.width, rect.height, radius);\n}\n\nfunction devicePixelRatio(): number {\n return typeof window !== 'undefined' && window.devicePixelRatio ? window.devicePixelRatio : 1;\n}\n\n/**\n * No SVG filter reference support (Firefox, older Safari): a real path, not a stub — the Android\n * renderer degrades to an affine magnifier below API 33 and that's documented as normal too. Blur\n * and saturation stand in for refraction's optical effect; the tint carries what refraction can't:\n * a body of glass, not just a smudge over whatever's behind it.\n */\nfunction fallbackFilterCss(optics: VireGlassOptics): string {\n const blurPx = Math.max(optics.blur, 1.5);\n const saturate = 1 + optics.colorPickup;\n return `blur(${blurPx}px) saturate(${saturate})`;\n}\n\nconst to255 = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * 255);\n\nfunction rgbCss(r: number, g: number, b: number): string {\n return `rgb(${to255(r)} ${to255(g)} ${to255(b)})`;\n}\n\n/**\n * The body, from the model's own law (`./body`, ported from the lens shader §3): density is what\n * legibility and presence demand over THIS backdrop, `tintLuma` is the lightness it tints toward,\n * and the hue is the surroundings' — glass has no colour of its own, only the colour of what lies\n * beneath it. A flat fill in place of a tint is what breaks the material.\n */\nfunction bodyCss(\n optics: VireGlassOptics,\n sample: BackdropSample,\n ink: number,\n accent?: VireGlassAccent,\n): string {\n const body = withPresence(resolveBody(optics, sample, ink), optics, sample);\n\n // A tinted element takes its colour from the accent rather than from its surroundings, but it is\n // still the MEDIUM that is coloured: the amount stays short of one so the content keeps coming\n // through. A fill at full opacity is the thing §7 says breaks the material.\n if (accent) {\n const [r, g, b] = accentTone(accent.color, sample.luma);\n const amount = Math.max(accentAmount(accent), body.density);\n return `rgba(${to255(r)}, ${to255(g)}, ${to255(b)}, ${amount.toFixed(3)})`;\n }\n\n const [r, g, b] = ambientFrom(sample);\n const hue = (c: number) => body.tintLuma + (c - body.tintLuma) * optics.colorPickup;\n return `rgba(${to255(hue(r))}, ${to255(hue(g))}, ${to255(hue(b))}, ${body.density.toFixed(3)})`;\n}\n\nexport type AttachGlassOptions = {\n material?: Partial<VireGlassMaterial>;\n /** Defaults to the element's measured box (size + `border-radius`). */\n geometry?: VireGlassGeometry;\n /** Key-light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** Whether `attachGlass` writes `box-shadow` itself. Turn it off if the host owns that property —\n * is always emitted either way. */\n shadow?: boolean;\n /**\n * The user's clear-to-tinted preference (§3). iOS 27 made it continuous and apps get it without\n * recompiling, so the material has to stay usable across the WHOLE range, not at one point.\n */\n scale?: number;\n /** System accessibility (§9). Read from the browser's own media queries unless supplied. */\n accessibility?: VireGlassAccessibility;\n /**\n * Tint for a primary action (§7). A colour that belongs to the medium, generating a range of\n * tones from the backdrop's brightness — not a fill. Use it on the one element that should stand\n * out: \"when every element is tinted, nothing stands out\" (219 @17:31).\n */\n accent?: VireGlassAccent;\n /** Initial presence, 0 to 1 (§1). Defaults to fully present. */\n appear?: number;\n /**\n * `'interactive'` is glass that is not there until it is touched (S 42:34, \"Building Tide Guide\"): \"this effect doesn't\n * change the appearance of a view until you interact with it... as you start sliding it, the\n * interactive effect adds a soft, subtle highlight\". The element carries no material at rest and\n * materialises under the finger — §1's materialising, driven by touch instead of by the host.\n *\n * It is what makes glass usable on a control that is not chrome: a slider thumb, a chart scrubber,\n * a card. Permanent glass there would be glass in the content layer, which §6 says to avoid.\n */\n variant?: 'present' | 'interactive';\n /** Called while this element is being touched, so a group can carry the glow to its neighbours\n * (§5). Wired for you by `createGlassGroup`. */\n onGlow?: (glow: { pageX: number; pageY: number; strength: number } | null) => void;\n /** Pointer response (§5). On by default. */\n interactive?: boolean;\n /** Overrides the probe entirely — images and video are invisible to it, and the host app\n * already knows its own cover-art accent. */\n sample?: BackdropSample;\n};\n\n/**\n * Shapes this element flows into (docs/reference.md §5): merging with a neighbour, or splitting\n * into parts across two bridges. Offsets and sizes are CSS px relative to this element's centre.\n *\n * `smoothing` is the width of the bridge — zero leaves the element alone. What each shape MEANS\n * (a menu growing out of its button, a control breaking into segments) is the host's choreography;\n * the material only knows how two silhouettes join.\n */\nexport type GlassMorph = {\n smoothing: number;\n shape?: MorphShape;\n shape2?: MorphShape;\n /**\n * Any number of shapes flowing into this one. Several independent elements becoming one whole is\n * the behaviour; how many of them there are is the host's business, and it used to be the\n * material's — the count lived in the field NAMES, so a fourth element had nowhere to go.\n *\n * `shape` and `shape2` still work and come first.\n */\n shapes?: readonly MorphShape[];\n};\n\nexport type GlassHandle = {\n update(): void;\n /**\n * How present the material is, 0 to 1 (docs/reference.md §1). Drive this to bring glass in and\n * out — NOT opacity. \"Instead of fading, Liquid Glass objects materialize in and out by\n * gradually modulating the light bending and lensing\" (219 @2:55). A faded element shows the\n * backdrop through a veil; one that is still arriving shows it undistorted.\n */\n setAppear(t: number): void;\n /** Tint the element, or clear it with null (§7). */\n setAccent(accent: VireGlassAccent | null): void;\n /** A glow that started on a neighbour, in page coordinates (§5). Null clears it. */\n setNeighbourGlow(glow: { pageX: number; pageY: number; strength: number } | null): void;\n setMorph(morph: GlassMorph | null): void;\n destroy(): void;\n};\n\nexport function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): GlassHandle {\n if (typeof document === 'undefined') {\n throw new Error('vireglass/dom: attachGlass requires a browser DOM');\n }\n\n // One live instance per element. Re-attaching without destroying the previous handle used to\n // leave its filter in the shared <defs> forever, unreferenced, while the element quietly moved\n // to the new id.\n attached.get(el)?.destroy();\n\n const id = `vireglass-filter-${(filterCounter += 1)}`;\n const svgSupported = supportsSvgBackdropFilter();\n let wasLight = (opts.material?.ink ?? VIREGLASS_MATERIAL.ink) > 0.5;\n let filterEl: SVGFilterElement | null = null;\n let destroyed = false;\n let mapKey = '';\n let morph: GlassMorph | null = null;\n const onlyWhenTouched = opts.variant === 'interactive';\n let appear = onlyWhenTouched ? 0 : (opts.appear ?? 1);\n let accent = opts.accent;\n // Read once at attach, then followed: a setting turned on while the page is open has to reach\n // the material, not wait for a reload.\n let a11y = systemAccessibility();\n const stopWatchingA11y = watchAccessibility((next) => {\n a11y = next;\n mapKey = '';\n deform.setElastic(elasticAllowed(opts.accessibility ?? a11y));\n apply();\n });\n\n warnIfNested(el);\n\n // The element's own tree: a shadow root when it is in one, the document otherwise.\n const host = hostFor(el);\n ensureRimStyles(host);\n el.setAttribute(GLASS_ATTR, '');\n // `inset: 0` on the rim needs a positioned ancestor. Only taken over when the host left it at\n // the initial value, and put back on destroy.\n const positionWasStatic = getComputedStyle(el).position === 'static';\n if (positionWasStatic) el.style.setProperty('position', 'relative');\n\n /**\n * Causes to effects, then the user's scale, then accessibility — in that order. §9 is explicit\n * that a system setting outranks the material preset: even a transparent preset moves to the\n * edge of the scale under increased contrast, because the user needs contrast more than they\n * need the aesthetic.\n */\n function optics(patch?: Partial<VireGlassMaterial>): VireGlassOptics {\n const base = resolveOptics(patch ?? opts.material);\n const scaled = applyGlassScale(base, opts.scale ?? GLASS_SCALE_DEFAULT);\n const settled = applyAccessibility(scaled, opts.accessibility ?? a11y);\n // Appearance last, and by modulating the lens rather than by fading the element: §1 is\n // explicit that opacity is the wrong instrument for this.\n return applyAppear(settled, appear);\n }\n\n function morphState() {\n if (!morph) return {};\n return { smoothing: morph.smoothing, morph: morph.shape, morph2: morph.shape2, morphs: morph.shapes };\n }\n\n function morphKey(): string {\n if (!morph) return '0';\n const part = (s?: MorphShape) =>\n s ? `${s.offsetX},${s.offsetY},${s.width},${s.height},${s.cornerRadius}` : '-';\n return `${morph.smoothing}/${part(morph.shape)}/${part(morph.shape2)}`;\n }\n\n function apply(): void {\n if (destroyed) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n const opticsNow = optics();\n const sample = opts.sample ?? probeBackdrop(el);\n\n if (svgSupported) {\n // The map depends only on geometry, optics and density — never on the backdrop. Rebuilding\n // it on every scroll would re-run a per-pixel loop and a PNG encode for a picture that did\n // not change; the refraction itself updates in the compositor with no JS at all.\n const key = `a${appear.toFixed(3)}|m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}:${opticsNow.blur}`;\n if (key !== mapKey || !filterEl) {\n // Keyed by exactly what the maps are functions of, which is exactly the cache key above.\n const map = cached(`d|${key}`, () => buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState()));\n const defs = getFilterHost(host).querySelector('defs') as SVGDefsElement;\n const hue = hasSpectralEdge(opticsNow)\n ? cached(`h|${key}`, () => buildSpectralMap(opticsNow, geometry, devicePixelRatio()))\n : null;\n const next = buildFilterElement(id, map.url, opticsNow, map.scale, hue);\n if (filterEl?.parentNode) defs.replaceChild(next, filterEl);\n else defs.appendChild(next);\n filterEl = next;\n mapKey = key;\n }\n el.style.setProperty('backdrop-filter', `url(#${id})`);\n el.style.setProperty('-webkit-backdrop-filter', `url(#${id})`);\n } else {\n el.style.setProperty('backdrop-filter', fallbackFilterCss(opticsNow));\n el.style.setProperty('-webkit-backdrop-filter', fallbackFilterCss(opticsNow));\n el.style.backgroundColor = bodyCss(opticsNow, sample, wasLight ? 1 : 0, accent);\n }\n\n const light = shouldInkBeLight(sample, wasLight);\n wasLight = light;\n const [tr, tg, tb] = ambientFrom(sample);\n el.style.setProperty('--vireglass-ink', light ? '1' : '0');\n el.style.setProperty('--vireglass-tint', `${tr} ${tg} ${tb}`);\n el.style.setProperty('--vireglass-body-density', String(opticsNow.bodyDensity));\n\n // The raw numbers above are the model's own values; these are the same thing in a form CSS\n // can actually consume. Without them a host has to convert in script, which is the work this\n // renderer exists to do.\n const inkLevel = Math.round((light ? INK_LIGHT : INK_DARK) * 255);\n el.style.setProperty('--vireglass-ink-color', `rgb(${inkLevel} ${inkLevel} ${inkLevel})`);\n el.style.setProperty('--vireglass-tint-color', rgbCss(tr, tg, tb));\n el.style.setProperty('--vireglass-body-color', bodyCss(opticsNow, sample, light ? 1 : 0, accent));\n\n // Rim and shadow follow the SAMPLE, not just the geometry, so they sit outside the map's\n // cache key: the environment they take their colour and density from moves under a scroll\n // while the silhouette does not.\n // §9: under increased contrast the hairline stops reporting where the light is and starts\n // separating the element from what is behind it, so it is measured from the body, not the\n // environment.\n const pole = withPresence(resolveBody(opticsNow, sample, light ? 1 : 0), opticsNow, sample).tintLuma;\n el.style.setProperty(\n '--vireglass-rim',\n (opts.accessibility ?? a11y).increaseContrast\n ? contrastRimCss(pole, contrastRimLuma(pole))\n : rimGradientCss(opticsNow, [tr, tg, tb], opts.light ?? REST_LIGHT, appear),\n );\n el.style.setProperty('--vireglass-rim-width', `${RIM_WIDTH_PX}px`);\n\n // §11: a rounded child inside glass has to be concentric with it, or the two curves fight.\n // Emitted rather than applied — the inset is the host's, and CSS can do the arithmetic.\n el.style.setProperty('--vireglass-radius', `${geometry.cornerRadius}px`);\n el.style.setProperty('--vireglass-radius-min', `${concentricRadius(geometry.cornerRadius, geometry.cornerRadius, 0)}px`);\n\n const shadow = boxShadowCss(geometry, sample, appear);\n el.style.setProperty('--vireglass-shadow', shadow);\n if (opts.shadow !== false) el.style.setProperty('box-shadow', shadow);\n }\n\n apply();\n\n // INTERACTION (docs/reference.md §5). The physics is the core's — `createDeform` carries the\n // spring, the press attack and the wave, at its own fixed step. What lives here is only the\n // plumbing: pointer in, map and glow out.\n const deform = createDeform({ elastic: elasticAllowed(opts.accessibility ?? a11y) });\n let frame: number | null = null;\n let lastFrameAt = 0;\n let interacting = false;\n\n function localPoint(e: PointerEvent): [number, number] {\n const rect = el.getBoundingClientRect();\n return [e.clientX - rect.left - rect.width / 2, e.clientY - rect.top - rect.height / 2];\n }\n\n function paintInteraction(sampleOut: DeformSample): void {\n const geometry = opts.geometry ?? measureGeometry(el);\n const base = optics();\n // Under the finger a matte control stops being frosted and becomes a lens (§5, M 4:10–4:30).\n const rise = raiseIntoGlass(sampleOut.press);\n // The same chain as at rest — the user's scale and the system's settings do not stop\n // applying because a finger is down.\n const risen = optics({ ...opts.material, roughness: (opts.material?.roughness ?? VIREGLASS_MATERIAL.roughness) * rise.solid });\n\n // A reduced-resolution map while the finger is down: `feImage` stretches it over the element\n // regardless, the displacement is smooth, and a full device-pixel rebuild plus a PNG encode\n // every frame does not hold a frame budget.\n const map = buildDisplacementMap(risen, geometry, interacting ? 1 : devicePixelRatio(), {\n ...morphState(),\n touch: {\n x: sampleOut.touchX,\n y: sampleOut.touchY,\n pullX: sampleOut.pullX,\n pullY: sampleOut.pullY,\n press: sampleOut.press,\n radius: halfMinDp(geometry) * TOUCH_RADIUS_FRACTION,\n waveAmp: sampleOut.waveAmp,\n wavePhase: sampleOut.wavePhase,\n },\n });\n if (filterEl) {\n const feImage = filterEl.querySelector('feImage');\n feImage?.setAttribute('href', map.url);\n // EVERY pass, not the first. With dispersion there are three at different scales, and\n // querySelector returned only red: under a finger it got the undispersed scale while green\n // and blue kept their attach-time values, and the coloured rim stopped following the finger.\n for (const pass of filterEl.querySelectorAll('feDisplacementMap')) {\n const ratio = Number(pass.getAttribute('data-vireglass-ratio') ?? 1);\n pass.setAttribute('scale', String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));\n }\n }\n mapKey = '';\n\n paintGlow(sampleOut.touchX, sampleOut.touchY, sampleOut.active * base.edgeLight, geometry);\n\n // \"the glow spreads throughout the element and onto any Liquid Glass elements NEARBY\" (§5,\n // 219 @12:11). This element cannot know who is nearby; the group does, so it is told.\n const rect = el.getBoundingClientRect();\n opts.onGlow?.({\n pageX: rect.left + rect.width / 2 + sampleOut.touchX,\n pageY: rect.top + rect.height / 2 + sampleOut.touchY,\n strength: sampleOut.active,\n });\n }\n\n /**\n * The glow is a CONCENTRATION of the surroundings, not the glass's own whiteness: over a dark\n * backdrop the element lightens but never turns white, and ink over it stays legible.\n *\n * `x` and `y` are relative to the element's centre and may fall outside it — a glow that started\n * next door still has a direction, and dropping it to the centre would make a neighbour brighten\n * uniformly rather than from the side the finger is on.\n */\n function paintGlow(x: number, y: number, strength: number, geometry: VireGlassGeometry): void {\n if (strength <= 0.001) {\n el.style.setProperty('--vireglass-glow-opacity', '0');\n return;\n }\n const [gr, gg, gb] = ambientFrom(opts.sample ?? probeBackdrop(el));\n const cx = ((x + geometry.width / 2) / geometry.width) * 100;\n const cy = ((y + geometry.height / 2) / geometry.height) * 100;\n const reach = halfMinDp(geometry) * TOUCH_RADIUS_FRACTION;\n el.style.setProperty(\n '--vireglass-glow',\n `radial-gradient(circle ${reach.toFixed(0)}px at ${cx.toFixed(1)}% ${cy.toFixed(1)}%, rgba(${to255(gr)},${to255(gg)},${to255(gb)},1) 0%, rgba(${to255(gr)},${to255(gg)},${to255(gb)},0) 100%)`,\n );\n el.style.setProperty('--vireglass-glow-opacity', strength.toFixed(3));\n }\n\n function tick(now: number): void {\n if (destroyed) return;\n const dt = lastFrameAt ? (now - lastFrameAt) / 1000 : 1 / 60;\n lastFrameAt = now;\n deform.step(dt);\n const s = deform.sample();\n // The interactive variant materialises with the touch rather than being held present. `active`\n // rather than `press`: press is the depth of the dent, active is simply whether a finger is\n // there, and the material arriving has to track the second.\n if (onlyWhenTouched) appear = s.active;\n paintInteraction(s);\n if (deform.idle()) {\n interacting = false;\n frame = null;\n lastFrameAt = 0;\n // Settled: put the full-resolution map back and drop the glow.\n el.style.setProperty('--vireglass-glow-opacity', '0');\n opts.onGlow?.(null);\n apply();\n return;\n }\n frame = requestAnimationFrame(tick);\n }\n\n function run(): void {\n if (frame === null && !destroyed) frame = requestAnimationFrame(tick);\n }\n\n let grabX = 0;\n let grabY = 0;\n\n function onDown(e: PointerEvent): void {\n const [x, y] = localPoint(e);\n const geometry = opts.geometry ?? measureGeometry(el);\n interacting = true;\n grabX = x;\n grabY = y;\n // Pointer capture, or a drag that leaves the element stops reporting and the deformation\n // freezes mid-pull with the finger still down.\n el.setPointerCapture?.(e.pointerId);\n deform.grab(x, y, waveImpulse(geometry));\n run();\n }\n function onMove(e: PointerEvent): void {\n if (!interacting) return;\n const [x, y] = localPoint(e);\n const geometry = opts.geometry ?? measureGeometry(el);\n // `drag` takes the travel FROM the grab point, and saturates it against the limit itself.\n deform.drag(x - grabX, y - grabY, halfMinDp(geometry) * MAX_STRETCH);\n run();\n }\n function onUp(e?: PointerEvent): void {\n if (!interacting) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n if (e) el.releasePointerCapture?.(e.pointerId);\n // Lifting throws a second, weaker ring (§5) — the core caps the sum, so this only has to be\n // the smaller impulse.\n deform.release(waveImpulse(geometry) * RELEASE_WAVE);\n run();\n }\n\n if (opts.interactive !== false) {\n el.addEventListener('pointerdown', onDown);\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onUp);\n el.addEventListener('pointercancel', onUp);\n el.addEventListener('pointerleave', onUp);\n }\n\n // The \"listener\" `destroy()` has to remove: geometry defaults to the measured box, so a resize\n // of the element itself has to rebuild the map, or the displacement drifts from the element's\n // actual silhouette as soon as its layout changes.\n let resizeObserver: ResizeObserver | null = null;\n if (!opts.geometry && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => apply());\n resizeObserver.observe(el);\n }\n\n function destroy(): void {\n destroyed = true;\n stopWatchingA11y();\n if (attached.get(el) === handle) attached.delete(el);\n if (frame !== null) cancelAnimationFrame(frame);\n frame = null;\n el.removeEventListener('pointerdown', onDown);\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onUp);\n el.removeEventListener('pointercancel', onUp);\n el.removeEventListener('pointerleave', onUp);\n el.style.removeProperty('--vireglass-glow');\n el.style.removeProperty('--vireglass-glow-opacity');\n resizeObserver?.disconnect();\n resizeObserver = null;\n if (filterEl?.parentNode) filterEl.parentNode.removeChild(filterEl);\n filterEl = null;\n mapKey = '';\n el.style.removeProperty('backdrop-filter');\n el.style.removeProperty('-webkit-backdrop-filter');\n el.style.removeProperty('background-color');\n el.style.removeProperty('--vireglass-ink');\n el.style.removeProperty('--vireglass-tint');\n el.style.removeProperty('--vireglass-body-density');\n el.style.removeProperty('--vireglass-ink-color');\n el.style.removeProperty('--vireglass-tint-color');\n el.style.removeProperty('--vireglass-body-color');\n el.style.removeProperty('--vireglass-rim');\n el.style.removeProperty('--vireglass-rim-width');\n el.style.removeProperty('--vireglass-shadow');\n el.style.removeProperty('--vireglass-radius');\n el.style.removeProperty('--vireglass-radius-min');\n el.style.removeProperty('box-shadow');\n el.removeAttribute(GLASS_ATTR);\n if (positionWasStatic) el.style.removeProperty('position');\n }\n\n const handle: GlassHandle = {\n update: apply,\n setAppear(t) {\n const next = t < 0 ? 0 : t > 1 ? 1 : t;\n if (next === appear) return;\n appear = next;\n apply();\n },\n setAccent(next) {\n accent = next ?? undefined;\n apply();\n },\n setNeighbourGlow(glow) {\n if (destroyed || interacting) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n if (!glow) {\n paintGlow(0, 0, 0, geometry);\n return;\n }\n const rect = el.getBoundingClientRect();\n paintGlow(\n glow.pageX - (rect.left + rect.width / 2),\n glow.pageY - (rect.top + rect.height / 2),\n glow.strength,\n geometry,\n );\n },\n setMorph(next) {\n morph = next && next.smoothing > 0 ? next : null;\n mapKey = '';\n apply();\n },\n destroy,\n };\n attached.set(el, handle);\n return handle;\n}\n"]}
1
+ {"version":3,"sources":["../src/adaptation.ts","../src/law.ts","../src/geometry.ts","../src/sdf.ts","../src/dom/displacement.ts","../src/spectral.ts","../src/dom/spectral-map.ts","../src/dom/map-cache.ts","../src/optics.ts","../src/material.ts","../src/dom/probe.ts","../src/dom/support.ts","../src/shadow-tint.ts","../src/dom/shadow.ts","../src/dom/body.ts","../src/accessibility.ts","../src/dom/preferences.ts","../src/glass-scale.ts","../src/appear.ts","../src/accent.ts","../src/concentric.ts","../src/dom/rim.ts","../src/dom/nesting.ts","../src/dom/style-hold.ts","../src/adapters.ts","../src/touch-response.ts","../src/scroll-edge.ts","../src/dom/scroll-edge.ts","../src/group-model.ts","../src/dom/group.ts","../src/dom/index.ts"],"names":["BEVEL_SAMPLES","mapDensity","clamp01","thicknessDp","bevelDp","diffraction","clamp","luma","smoothstep","k","to255"],"mappings":"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","file":"dom.cjs","sourcesContent":["\n/**\n * Automatic content polarity above the glass.\n *\n * The glass adjusts its own body to the backdrop — but that has a limit. When the backdrop is\n * light AND the ink over it is light, no amount of body density can separate them by contrast\n * anymore: the body hits its own ceiling, and the letters drown. Past that point the decision is\n * no longer the glass's to make but the app's — it recolors the ink to the opposite side, and all\n * of the glass's own automation reflows behind it, because it depends on that same polarity.\n *\n * The app has nowhere to get the lightness of the backdrop UNDER the glass from — only the native\n * capture can see it. That's where it comes from: the `onBackdropSample` event (a probe in\n * `GlassBackdropView`).\n *\n * The decision is made BY LIGHTNESS with hysteresis: computing body density here with the\n * shader's formula would mean keeping a second implementation of the model that silently drifts\n * from the first. Whether the body and the ink actually separate by contrast is checked by\n * `check:optics` — against a real render, not a copy of the formula.\n */\n\nexport type BackdropSample = {\n /** Average lightness of the backdrop under the glass, 0..1, on the same (sRGB-encoded) scale\n * as the screen. */\n luma: number;\n /** Variegation: twice the mean deviation of lightness, 0 on a flat fill, 1 at the limit.\n * Exactly the same quantity the probe computes on the web — otherwise the platforms would\n * drift apart silently. */\n busy: number;\n /** The darkest and lightest spots under the glass. The legibility decision is made from these,\n * not the average: right over a black/white border the average reads as \"everything's fine\". */\n lo: number;\n hi: number;\n r: number;\n g: number;\n b: number;\n};\n\n/** Quantization step for the ambient color — for platforms where the measurement flows through\n * state: every probe sample would otherwise trigger a surface repaint. The shadow is tinted\n * coarsely, it doesn't need precision either. The web draws uniforms imperatively every frame\n * and takes the color as is. */\nconst AMBIENT_STEP = 32;\n\n/** The element's ambient color from a probe sample — the one that bleeds into its shadow\n * (docs/reference.md §7). */\nexport function ambientFrom(sample: { r: number; g: number; b: number }): [number, number, number] {\n const step = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * AMBIENT_STEP) / AMBIENT_STEP;\n return [step(sample.r), step(sample.g), step(sample.b)];\n}\n\n/** Ink lightness at the ends of the scale. The kit keeps light text nearly white and dark text\n * nearly black; there's no in-between polarity state by construction. */\nexport const INK_LIGHT = 0.95;\nexport const INK_DARK = 0.08;\n\n/**\n * Ink polarity from a backdrop sample — ONE place for every platform. A small element and its\n * glyphs switch between light and dark so that contrast is maximized (docs/reference.md §3): over\n * a yellow flower the reference already has black glyphs on light glass. Holding a light ink with\n * body density over a light backdrop just turns the element into a painted plaque.\n *\n * The decision is by lightness with a bias toward the light side — not by average (a white screen\n * with a dark stripe would otherwise never flip) and not by maximum (one light cover peeking under\n * the edge would recolor the whole panel). Hysteresis lives inside; the caller decides how many\n * confirmations it takes.\n */\nexport function shouldInkBeLight(sample: { luma: number; hi?: number }, wasLight: boolean): boolean {\n return decisiveLuma(sample) < (wasLight ? FLIP_LUMA : RETURN_LUMA);\n}\n\nexport const decisiveLuma = (sample: { luma: number; hi?: number }) =>\n sample.luma * 0.75 + (sample.hi ?? sample.luma) * 0.25;\n\n/** Lighter than this, a light ink flips to dark. */\nexport const FLIP_LUMA = 0.62;\n/** The way back triggers noticeably earlier than the way forward: without the gap the ink would\n * flicker on every light cover sliding under the glass edge. */\nexport const RETURN_LUMA = 0.5;\n/** How many consecutive samples have to demand a change. The probe samples ~5 times a second, so\n * three samples is roughly half a second of a stable backdrop, not a random cover flashing by\n * under the edge. */\nexport const CONFIRMATIONS = 3;\n/** Duration of the recolor. Slow enough not to read as an event, fast enough that the illegible\n * in-between state doesn't linger noticeably. */\nexport const FADE_MS = 420;\n","/**\n * THE LAW: every calibrated number the material obeys, in one place.\n *\n * A value here is written ONCE and read by everything that needs it — the shader text interpolates\n * it, the JS twins import it. The alternative is what this file replaces: the same number typed\n * into a GLSL string and again into a TypeScript function, drifting apart the first time one side\n * is tuned. `VG_FALLOFF` already worked this way; the rest now does too.\n *\n * Each entry carries where it came from. `§N` is a section of `docs/reference.md`, which is itself\n * drawn from Apple's public sessions; `M 2:32` and the like are the timestamps those sections cite.\n * A number with no provenance is marked as such, and that marking is a debt, not a decoration.\n *\n * Structural constants — 0, 1, 0.5, 2, π — are not laws and do not belong here.\n */\n\n/** Rim optics: the silhouette's light (§2). */\nexport const RIM = {\n /**\n * The key-light lobe's exponent. Two opposing arcs come out of one expression, which is why\n * they are opposed rather than placed: `pow(max(facing, 0), n) + 0.45 * pow(max(-facing, 0), n)`.\n *\n * MEASURED off two close-ups of real end caps, frames/crops/cap158-left and cap158-right. The\n * bright arc's full width at half its peak is 53 degrees in the first and 30 in the second; this\n * exponent's own width is `2·acos(0.5^(1/n))`, so they imply 6 and 20. It was 3, whose arc is 75\n * degrees wide — broader than either measurement, and the error is in the same direction in both.\n *\n * 6 is the conservative end: it reproduces the wider crop exactly, and a broader arc is the more\n * forgiving error. One exponent cannot serve both, and that is not noise — a specular lobe's\n * width depends on the light's angular size as well as the surface, and those are two different\n * scenes. The model has no term for the light's size.\n */\n lobeExponent: 6,\n /** The far arc, weaker than the one facing the light (§2). */\n opposingArc: 0.45,\n /**\n * The dark edge along the whole silhouette, as a multiplicative darkening. iOS 27 made it a\n * layer of its own, and it does not rule out the highlight sitting on top of it (§2).\n */\n darkEdge: 0.22,\n /** Width of the hairline, CSS px. \"About a point, not a band and not a bevel\" (§2). */\n widthPx: 1,\n /**\n * How strongly the line is drawn, by the lightness around the element. The rim is a reflection\n * of the surroundings, so it is faint over a dark one and plain over a bright one, not white at\n * full strength everywhere (§2, §6).\n *\n * MEASURED off the controls of A 2:17 (over dark video), M 2:52 (over sky) and A 2:18 (over\n * grass), as the brightest rim bin's OKLab lightness over the surround's: 0.24 to 0.27 over dark,\n * 0.25 over sky, 0.37 over grass. Through the DOM path onto the same backdrops these land within\n * 0.08 of the smooth rows (docs/dom.md); a line white at full strength reads 0.70 to 0.80 over the\n * dark frames.\n */\n strengthDark: 0.37,\n strengthLight: 0.95,\n /**\n * The surround lightness between which the strength moves from one to the other. UNMEASURED: the\n * two ends are, and the controls in between were not looked for.\n */\n ambientFrom: 0.15,\n ambientTo: 0.45,\n /**\n * The share of the line's width, from the silhouette inward, that the light line leaves to the\n * dark edge. UNMEASURED: without it the line covers the dark edge and an element over a bright\n * flat backdrop loses the one mark that holds it there.\n */\n lineInset: 0.3,\n /**\n * The share of the peak that the line keeps along the whole contour, away from the key light.\n * MEASURED: the reference line goes all the way round. Its dimmest bin sits 0.06 to 0.12 of\n * lightness over the surround on the dark frames, against a peak of 0.24 to 0.27 (A 2:17).\n */\n contour: 0.3,\n /** How far the line's colour is lifted from the surroundings' toward white. UNMEASURED: the\n * lens always had 0.75 here, and this is that figure with a name. */\n whiteShare: 0.75,\n /**\n * The reflectance (`fresnelStrength`) at which the line is drawn at the strengths above: that\n * of ordinary glass, index 1.5. A denser medium does not draw it brighter than they say; a\n * thinner one draws it fainter. UNMEASURED.\n */\n reflectanceRef: 0.7,\n} as const;\n\n/** How the medium stands between the backdrop and the eye (§3). */\nexport const BODY = {\n /** Lightness ceiling for the body when legibility is loose. */\n capLoose: 0.62,\n /** …and when it is strict. The model is calibrated at these two, not in between (E-43). */\n capTight: 0.38,\n /** The two ends the body tints toward. Glass has no colour of its own (HIG \"Color\"). */\n tintDark: 0.07,\n tintLight: 0.94,\n /** How far the backdrop's spread reaches past its mean when deciding what the ink needs. */\n busyEdge: 0.75,\n /** Fine texture the body has to stop being a window for. */\n groundSpan: 0.06,\n /**\n * The spread under the element at which the ink's legibility requirement starts to bind, and the\n * spread where it binds fully. Over a flat backdrop polarity flips before the ink drowns, so\n * the body does not darken under a light glyph there; over texture it does. UNMEASURED: the\n * reference shows a lighter body under a white glyph over sky, nothing about texture.\n */\n inkBusyFrom: 0.02,\n inkBusyTo: 0.12,\n /** Ceiling on any single demand, so one requirement cannot make the glass opaque on its own. */\n maxDemand: 0.92,\n /**\n * And a tighter one for presence specifically. It is a FLOOR on visibility, not a licence to go\n * opaque: wherever the body's tint sits close to the backdrop, the density that would deliver the\n * separation is the ceiling, and glass at `maxDemand` has stopped being a window. Better to\n * separate as far as transparency allows and no further. UNMEASURED.\n */\n presenceDemand: 0.5,\n /**\n * The density at which the body is wholly the ink's own pole. Between `presenceDemand` and this\n * the body moves from the light a thin body carries to the pole: a density no presence floor\n * reaches is one the ink's legibility, or a system setting, has asked for. UNMEASURED.\n */\n inkPoleTo: 0.8,\n} as const;\n\n/** Shadow (§4). The density law lives in `geometry.ts`; these are its measured ends. */\nexport const SHADOW = {\n /**\n * Measured off reference frames 711–723: 4.0% over a flat light backdrop, 19.9% over text.\n *\n * REPRODUCED independently off frames/verify/m-707 and m-711 — the same capsule in the same scene\n * at the same scale, once below the text over plain background and once scrolled up over it.\n * Comparing the rows under the capsule against the same rows far to either side, so the\n * background's own gradient cancels: 3.5% and 19.2%, peaking about 140 px below the capsule.\n * Two passes, different frames and a different method, agreeing to within 0.7 of a point.\n */\n alphaFlat: 0.04,\n alphaBusy: 0.199,\n} as const;\n\n/** Dispersion: the channels refract at different indices (§1, Cauchy). */\nexport const DISPERSION = {\n /** Red bends less than the base index, blue more — and not symmetrically. */\n redShift: -0.4,\n blueShift: 0.6,\n} as const;\n\n/** Response to a finger (§5). The springs and decay live in `touch-response.ts`; these shape the\n * field the finger deforms. */\nexport const TOUCH = {\n /**\n * The element grows under pressure (M 3:51; HIG: interactive \"expands\").\n *\n * CHECKED, not measured: across frames/knob/switch-press, a 4x5 sheet of one switch being\n * pressed, the control's extent runs 764 px in the three settled frames and 787 to 822 under the\n * finger — 3 to 8 per cent. This value sits inside that, which is a consistency check and not a\n * derivation: the measurement cannot separate the knob stretching from the track growing, and the\n * settled frames agreeing to the pixel is the only part of it that is tight.\n */\n pressGrow: 0.06,\n /** The ridge around the contact blob: material displaced from under the finger ends up\n * somewhere. Without it the shape balloons, and a dense medium does not do that. */\n ridge: 0.42,\n /** How far press pulls the field toward the finger. */\n pressPull: 0.16,\n /** Wavelength and decay of the ripple, as fractions of its span. Short and quick: in a dense\n * medium ripples are frequent and small; long shallow swells are water. */\n waveLength: 0.17,\n waveDecay: 0.7,\n /** The ripple's span, as a multiple of the contact radius. It has to reach the far edge, or it\n * reads as jitter under the finger rather than a wave across the surface. */\n waveSpan: 2,\n /**\n * Contact radius as a fraction of the element's half-size. UNMEASURED: §5 says the response has\n * to be visible UNDER the finger, which is why the blob is wide, but gives no figure.\n */\n radiusOfHalfSize: 1.1,\n /**\n * Wave impulse as a fraction of the travel limit. UNMEASURED: the core carries the ripple's\n * decay and frequency, but nothing says how hard a finger strikes it.\n */\n waveOfTravel: 0.18,\n /** The lift-off ring is weaker than the one from touching down (§5). UNMEASURED ratio. */\n releaseWave: 0.6,\n /**\n * How far a glow reaches past the element it started on, as a multiple of that element's\n * half-size. UNMEASURED: §5 says the glow spreads \"onto any Liquid Glass elements nearby\" and\n * names no distance. This is the reach at which a neighbour in a tab bar still lights and one\n * across the screen does not.\n */\n glowReach: 3,\n /**\n * How much of an element's \"active\" state a touch alone raises — the fraction the glow and the\n * ink lift ride on when nothing else is driving them. UNMEASURED.\n *\n * It was a private constant on the Android surface whose comment said it matched the web's, and\n * nothing enforced that: the web renderer takes `active` from the host as a field and has no\n * constant to match. Two renderers agreeing by a comment is exactly what this file is for.\n */\n activeOnTouch: 0.3,\n} as const;\n\n/** The bevel's profile — spherical, like a cap: `t / sqrt(1 - t² · k)`, clamped. A plain `t²` kept\n * the slope near zero through most of the bevel and then shot up at the edge, so the optics\n * bunched into a ring and the element read as a puck. */\nexport const BEVEL = {\n sphere: 0.94,\n floor: 0.02,\n slopeMax: 3.2,\n} as const;\n\n/** Where two shapes meet head-on their normals cancel exactly and the blend lands on zero. */\nexport const EPSILON = 1e-5;\n\n/** What the medium does to light passing through it (§3). */\nexport const MEDIUM = {\n /** The lightness content under the glass is pulled toward, and how hard. The medium both removes\n * light and mixes scattered light back in: over a light backdrop the body darkens, over a dark\n * one it lightens. A layer that only ADDED light pushed the body the wrong way over light\n * backdrops (M 2:35). */\n luma: 0.4,\n pull: 0.07,\n /** Ambient light reaching the body on top of that pull. */\n ambientSpill: 0.01,\n /** Glass concentrates light: the body is a touch lighter than what lies beneath it (M 2:29). */\n concentrate: 0.01,\n /** Scattered light on a frosted element is an ADDITION over the backdrop, not a fraction of the\n * way to the tint — a fraction goes to zero once the backdrop reaches the tint's lightness and\n * darkens past it (docs/benchmarks.md). */\n matteLift: 0.1,\n /** How far scattering reaches, as a fraction of the gather radius, over a busy backdrop under\n * ink. Set against the reference: structure under the capsule fades by a factor of nine or ten\n * there, not thirty (M 11:47). */\n scatterMax: 0.2,\n scatterBase: 0.1,\n /** The response to structure saturates early: what competes with the ink is not the AREA of\n * foreign text but the fact of it — a line under a tile measures about 0.12 of busy. */\n structureGain: 20,\n /** Tint density in the flat middle; the bevel multiplies it by the edge density. */\n bodyDensityFlat: 0.19,\n} as const;\n\n/** The lens itself (§1). */\nexport const LENS = {\n /** Backdrop compression at the rim goes to infinity at the silhouette, so the radius correction\n * is capped. */\n footprintMax: 1.8,\n /** Same reason, for the profile's slope. */\n slopeMax: 40,\n /** Every thin film on glass sits around this index. */\n filmIor: 1.35,\n /** Reference channel wavelengths in nm — red, green, blue — for diffraction and interference. */\n lambdaR: 610,\n lambdaG: 550,\n lambdaB: 460,\n} as const;\n\n/** The shadow's shape in the gap under the element (§4). */\nexport const SHADOW_GAP = {\n /** How much weaker the shadow is right at the outline than under the middle of the gap, and what\n * fraction of the offset it takes to reach full depth. In the reference the shadow's minimum\n * sits BELOW the rim, not at it. */\n light: 0.76,\n reach: 0.2,\n /** Fraction of the ambient hue the shadow carries. It has to stay a shadow, not a coloured blob. */\n tint: 1,\n} as const;\n\n/** Ink drawn inside the material (§5). */\nexport const INK = {\n /** Depth beneath the surface, dp. The normal displaces it by exactly this much at the rim. */\n depth: 4,\n /** Defocus under a finger, as a FRACTION of the touch blob rather than a length: the blob\n * already arrives in device units, so this follows both screen density and element size. At\n * rest it is zero and the sample stays a single one. */\n defocus: 0.08,\n} as const;\n\n/** The spectral edge (§1): dispersion, diffraction and interference are one cause — a dependence\n * on wavelength — and one hue multiplier, normalised to its own mean. They colour the reflection\n * without brightening it. */\nexport const SPECTRAL = {\n /** How far into the bevel the fringes reach, as a fraction of it measured from the silhouette.\n * Diffraction is an EDGE effect; past this the bevel is plain glass. */\n diffractionOnset: 0.45,\n /**\n * The same window for interference, which had none. §2 puts the iridescence on the opposing ARC —\n * \"the opposing arc carries an iridescent fringe\" — and a fringe is a thing at an edge.\n *\n * Without it the term applies wherever the surface angle puts it, and across the inner bevel the\n * angle barely changes, so a film that should read as a fringe reads as a flat colour filter.\n * Measured on a 680x64 bar with the default preset: a multiplier of 1.68, 1.26, 0.05 held CONSTANT\n * from a third of the way through the bevel to its inner edge — red boosted by two thirds and blue\n * removed outright. UNMEASURED window; wider than diffraction's because interference reaches\n * further in than the fringes do.\n */\n iridescenceOnset: 0.25,\n /** Fringes across the bevel. Denser as the bevel sharpens, which is what the phase term does. */\n diffractionFringes: 4,\n /** The channel the hue is measured against, nm. Green is the eye's own reference. */\n referenceLambda: 550,\n} as const;\n\n/** Tinting (§7): a colour that is a property of the medium, not a fill over it. */\nexport const ACCENT = {\n /** The tone the colour takes over a dark backdrop and over a light one. \"A range of tones mapped\n * to content brightness underneath\", rather than one flat colour. */\n deep: 0.88,\n light: 1.08,\n /** How much of the medium the colour occupies by default. Short of one, because the content has\n * to keep coming through: a fill \"breaks the visual character of Liquid Glass\" (@17:03). */\n amount: 0.8,\n} as const;\n\n/**\n * The system accessibility settings (§9). They are modifiers on the material's layers, so their\n * calibration belongs in the law next to the layers they move — not as private constants in the\n * module that happens to apply them.\n */\nexport const ACCESSIBILITY = {\n /** Frost floor under reduced transparency: the glass gets \"frostier\" (§9). */\n frostMinDp: 14,\n /**\n * Body floor under reduced transparency. B @10:07 is the stricter statement of the two — a bar\n * \"gets a background when reduce transparency is enabled\" — so this is a background, not a\n * thicker haze. UNMEASURED: neither source gives a figure.\n */\n obscureMin: 0.82,\n /** Under increased contrast the element is \"predominantly black or white\" (§9): the body goes to\n * whichever pole its ink already points at, at a density that leaves it reading as that pole. */\n contrastDensity: 0.94,\n /** …and separates from the backdrop on its own, whatever is behind it. */\n contrastPresence: 0.5,\n /**\n * The contrasting border §9 asks for, in units of lightness away from the body's own pole. The\n * rim stops taking its colour from the environment and takes it from the element instead — an\n * ambient hairline is not a contrasting border. UNMEASURED.\n */\n contrastRim: 0.85,\n /**\n * Press that survives reduced motion. §9 \"decreases the intensity of some effects and disables\n * any elastic properties\": the spring and the ripple are elastic and go to zero, the press is an\n * ease that carries the element's light, so it is damped rather than removed — an element that\n * stops answering a finger altogether is not reduced motion, it is no feedback. UNMEASURED.\n */\n stillPress: 0.6,\n} as const;\n\n/**\n * Morphing (§5). Apple's design leads name their own model for it out loud (S 1:25:30, fireside\n * chat with the Apple design team): \"we also had a refresher from biology class. It's called\n * mitosis and meiosis. When these things are coming together or materialization and\n * dematerialization and morphing.\"\n *\n * Which is the right physics and not a metaphor: a dividing cell is one body throughout. It never\n * has a moment of being two bodies that happen to touch, and it never pops a second body into\n * existence beside the first. The neck is continuous from start to finish, and it is the neck that\n * carries the whole transition.\n */\nexport const MORPH = {\n /**\n * Width of the neck between two lobes, as a fraction of the smaller one's half-size. On a large\n * element the bridge has to be wider or the seam keeps a sharp corner, which a liquid does not\n * have. UNMEASURED: the reference names the behaviour and no figure.\n */\n neck: 0.35,\n /**\n * How far past merely touching a completed fusion goes, as a multiple of the bridge width that\n * just closes the gap. At exactly the bridge width the two surfaces meet at a point, which is two\n * shapes kissing rather than one body.\n *\n * MEASURED, frames/morph/s03, the one panel where the necks are still attached. Apple's\n * silhouette there: lobes 72 and 82 px with their centres 92 px apart — 15 px of space between\n * their surfaces — joined by a neck 28 px tall. Rendering the same geometry through this model\n * gives 29.0. The measurement discriminates: 1.2 gives 23.5, 1.4 gives 33.5, and at 1.0 the neck\n * closes to nothing.\n */\n fuse: 1.3,\n} as const;\n\n/**\n * CAUSE TO EFFECT. The normalisations that turn what the medium IS — index, thickness, bevel,\n * roughness, film — into what a renderer needs. They lived as literals inside `optics.ts`, half of\n * them not even named, which meant the heart of the model was the one part of it the law could not\n * see.\n *\n * Almost all of them are stylisations and say so. Literal physical values put every effect at the\n * threshold of visibility: real glass reflects four per cent at normal incidence, and a rim drawn\n * at four per cent is not a rim. Each is monotonic in its own cause, so \"denser medium, brighter\n * rim\" holds whatever the constant is; what no one has measured is where on the scale Apple's\n * material sits. Hence UNMEASURED on nearly all of it — that is the honest state of this file, and\n * the gate now says so out loud instead of the number hiding in a module.\n */\nexport const DERIVE = {\n /** Physical 4% reflectance into the render's working range. UNMEASURED. */\n fresnelGain: 17.5,\n /** Schlick's exponent. A constant of the approximation, not a knob. */\n fresnelExponent: 5,\n /** The index at which ray bending is at full strength, measured from air. UNMEASURED. */\n iorFullBend: 0.6,\n /** Magnification behind a plane-parallel plate, per dp of thickness. UNMEASURED. */\n magnifyPerDp: 0.006,\n /** In ordinary glasses the Abbe number falls as the index rises, so dispersion grows with it.\n * UNMEASURED slope. */\n dispersionPerIor: 1.1,\n /** Index spread between the red and blue channels. The physical value (~0.01 at an Abbe number\n * of 55) is at the threshold of visibility. UNMEASURED. */\n iorSpreadPerDispersion: 0.045,\n /** Beer–Lambert absorption per dp of path. UNMEASURED. */\n absorbPerDp: 0.017,\n /** Ceiling on how much denser the bevel may read than the body. The rim's ray travels further\n * through the medium; past this the rim is milk rather than glass. UNMEASURED. */\n edgeDensityMax: 4,\n /**\n * Frost ceiling, dp. Deliberately low: blur is a SUPPORTING device here, and past about a dozen\n * dp letters under the glass stop being letters. Separating content from ink is the body's job.\n *\n * UNMEASURED, and an attempt is recorded here so the next one does not repeat it.\n * frames/verify/m-711 has the same paragraph sharp beside the capsule and behind it, which looks\n * like the measurement: match the blur that takes the sharp patch's detail down to the glassed\n * one's. It gives 2 to 3 px at that frame's scale, and the figure is not trustworthy. Detail is\n * lost to three things at once there — the frost, the magnification (`refractionScale` lowers the\n * text's spatial frequency without blurring anything), and the body veiling its contrast — and\n * the method cannot separate them. What it does bound is the total: the text behind the glass\n * keeps 68% of the detail it has beside it.\n *\n * A clean measurement needs a frame where the glass does not magnify, or a feature of known size\n * behind it to normalise the magnification out.\n */\n blurMaxDp: 12,\n /** Highlight width from a smooth surface and from a fully rough one, as a specular exponent.\n * UNMEASURED. */\n specularPowerSmooth: 160,\n specularPowerRough: 8,\n /** How much roughness damps the highlight's brightness. UNMEASURED. */\n specularRoughDamping: 0.6,\n /**\n * The medium's own hue by density. Water absorbs red and skews cool, ordinary glass is nearly\n * neutral with a faint green, dense high-index media skew warm. Glass has no colour of its own\n * (HIG \"Color\"), so this is never set by hand — it is tied to the index.\n */\n hueCool: [0.86, 1.0, 1.08],\n hueNeutral: [1.0, 1.02, 0.99],\n hueWarm: [1.08, 1.0, 0.88],\n /** The index range the hue sweeps across, and where it starts. UNMEASURED. */\n hueFromIor: 1.2,\n hueSpan: 0.55,\n /** Body lightness follows reflectance: the denser the medium, the more of its surroundings it\n * returns. UNMEASURED base and slope. */\n bodyLiftBase: 0.34,\n bodyLiftPerF0: 2.4,\n /**\n * How far past the bevel the rim gathers its surroundings, as a multiple of the bevel. At a\n * grazing angle the eye receives the vicinity rather than what is under the glass, and without\n * this, glass on an empty black background has no source at all. UNMEASURED.\n */\n gatherPerBevel: 4,\n /** Floor and ceiling on that radius, dp. Unbounded, a wide bevel gathers from fifty dp away and\n * a READABLE copy of the neighbourhood appears inside the glass — eight samples cannot blur a\n * disc that large (E-33, E-37). */\n gatherMinDp: 4,\n gatherMaxDp: 28,\n /** The body's own density from absorption through its thickness. Small: the body only moves\n * toward the tint under the legibility requirement, otherwise it dims the content. UNMEASURED. */\n bodyDensity: 0.05,\n /**\n * Rim light on the physical scale rather than the rim highlight's. `fresnelGain` saturates at one\n * for dense media, and applying it here too would raise body lightness harder than the glass had\n * just separated it from the ink — eating its own legibility work. UNMEASURED.\n */\n edgeLightGain: 6,\n /**\n * Iridescence rides the REFLECTED ray, so it is tied to Fresnel and has no knob of its own.\n *\n * MEASURED against how coloured a real rim is. In frames/crops the brightest rim pixels have a\n * channel spread — (max − min) / max — of 13% in cap158-left and 20% in cap158-right, against\n * their own backdrops' 14.6% and 14.3%. So the rim is no more coloured than the scene it stands\n * in: §2's \"iridescent fringe\" adds a few points at most, and in one of the two crops it adds\n * nothing measurable.\n *\n * At 1.6 this put ordinary glass at 0.945 iridescence and the spectral multiplier reached a 97%\n * channel spread — red boosted by two thirds and blue removed. Rendered over a coloured page that\n * is a neon tube around every control, which is what sent me to measure it.\n */\n iridescencePerFresnel: 0.042,\n /** Edge diffraction shares dispersion's λ-dependence, at the stylised amplitude: at the physical\n * one the fringes are not visible at all. MEASURED with the same crops and the same target as\n * iridescence — on its own it was reaching a 93% channel spread. */\n diffractionPerDispersion: 0.05,\n /** Multiple internal reflection — the denser the medium, the more light it circulates and the\n * more it is tinted by its surroundings. UNMEASURED slope. */\n colorPickupPerFresnel: 0.9,\n /**\n * The ceiling, which keeps it a medium rather than a fill.\n *\n * MEASURED, frames/concentric/shadow-zoom: the same sidebar twice, over a yellow cover and over a\n * pink one, so the difference between the panels is the pickup with the sidebar's own colour\n * subtracted out. Sampling a band of rows clear of the text, the bar's hue offset against the\n * cover's own reaches 0.31 of it at the edge nearest the content in the yellow panel and 0.28 in\n * the pink one. It was 0.42, which nothing measured.\n *\n * Reality is not uniform: the bleed falls to nothing about ninety pixels in, and both panels show\n * the same falloff. The DOM path has one backdrop sample per element and cannot reproduce that,\n * so it applies the ceiling across the whole body — right at the edge, too strong in the middle.\n * That limit is in docs/dom.md rather than papered over with a lower number.\n */\n colorPickupMax: 0.3,\n} as const;\n\n/**\n * SIZE AND SHADOW. What changes when an element gets bigger, and how dense its shadow reads over\n * what is behind it. 219 @6:36: as glass \"flexes and morphs to larger sizes, it simulates a\n * thicker material with deeper shadows and more pronounced lensing and refraction\".\n */\nexport const SIZE = {\n /** Half-size at which bevel and thickness are specified as given; they grow as its square root\n * from there. UNMEASURED reference size. */\n referenceDp: 24,\n /** Floor and ceiling on that growth. UNMEASURED. */\n gainMin: 0.8,\n gainMax: 2.4,\n /** A bevel wider than this fraction of the half-size breaks the SDF — the roundings converge in\n * the middle. A property of the geometry, not a taste. */\n maxBevelFraction: 0.65,\n} as const;\n\n/**\n * Shadow density by what is behind the element. 219 @11:47, verbatim: it \"increases the opacity of\n * its shadow when it is over text… lowers the opacity of its shadow when it is over a solid light\n * background.\" About content BEHIND the element, so one value per element rather than a field over\n * the shadow's area. Endpoints checked against the reference by the depth of the dip under the\n * element (docs/benchmarks.md).\n */\nexport const SHADOW_DENSITY = {\n /** Over a flat background. */\n flat: 0.8,\n /** How fast it rises with structure behind the element, and how far it may rise. */\n busyGain: 6,\n busyRise: 1.2,\n /** Quantisation of the emitted value: a shadow that changes on every pixel of scroll re-lays-out\n * the native view every frame. */\n step: 0.05,\n} as const;\n\n/**\n * THE MEDIUM'S RESPONSE TO A FINGER (§5). Part of the material, exactly as `ior` is: keeping these\n * with the consumer would mean web and Android ended up with two different glasses under one name.\n *\n * Press is viscous — it dents shallow and releases slowly. Drag is thick: the body noticeably lags\n * the finger, travel is short, and on release it snaps back fast with almost no overshoot, because\n * a wide springy overshoot would be liquid jelly rather than dense glass.\n */\nexport const SPRING = {\n /** Stiffness and damping while the finger is down. UNMEASURED. */\n holdStiffness: 260,\n holdDamping: 46,\n /** …and after it lifts. Stiffer, and damped hard: a dense medium snaps back without ringing. */\n releaseStiffness: 420,\n releaseDamping: 34,\n /** Time constants for the press dent, in and out, seconds. UNMEASURED. */\n pressAttack: 0.07,\n pressRelease: 0.16,\n /** How fast the touch point catches up to the finger. Not instant: an instant jump tears the\n * deformation, and on rapid taps that reads as jitter. */\n pointFollow: 0.045,\n /** …and how fast the element registers as being touched at all, which is what the glow rides. */\n activeFollow: 0.09,\n /** The ripple decays within a quarter second rather than oscillating: in a viscous medium ripples\n * are short and weak. UNMEASURED. */\n waveDecay: 0.22,\n waveTurnsPerSecond: 3,\n /** Ceilings on the accumulated ripple, as multiples of a single impulse. Impulses add up rather\n * than restart — restarting cuts a running wave mid-period, which is what jolts on rapid taps. */\n waveCapOnGrab: 1.6,\n waveCapOnRelease: 2,\n} as const;\n\n/** The user's clear-to-tinted preference (§3). */\nexport const SCALE = {\n /** Where on the scale the material stays exactly as it is by default. */\n default: 0.35,\n /** Body density at the fully tinted end: content under the glass has to be hidden. UNMEASURED. */\n tintedDensity: 0.9,\n} as const;\n\n/**\n * The scroll edge (§10). 219 @9:16: as content scrolls under a glass element \"the effect gently\n * DISSOLVES the content into the background, lifting the glass visually above the moving content,\n * and allowing floating elements like titles to always remain clear.\"\n *\n * 356 @11:32 says what it is not, and the first implementation here did exactly that: \"they don't\n * block or darken like overlays. They simply clarify where UI and content meet.\"\n */\nexport const SCROLL_EDGE = {\n /** How far the content has to slide under the panel for the effect to fully engage, dp. */\n engageDp: 24,\n /**\n * How far the blur reaches BELOW the bar's lower lip, as a multiple of the bar's own height.\n *\n * MEASURED, frames/scroll-edge/z576 at 320x413. High-frequency energy (mean |laplacian| per row,\n * which a brightness gradient in the content cannot fake) reads 1.4 through the zone under the\n * bar and 14 in the sharp content below — a factor of ten. The bar's lip is at y≈45 and the zone\n * runs to y≈130, so the reach is about 1.9 times the bar's own height.\n *\n * The same frame confirms 219 @9:22 in passing: the floating title sits inside that zone at 32,\n * twenty times its surroundings. Titles stay crisp while everything behind them dissolves, which\n * is why the effect belongs behind the glass in the stack rather than over the content.\n */\n reachOfBarHeight: 1.9,\n /** The blur the content dissolves into at the edge, dp. This is the effect itself — the content\n * goes out of focus into the background rather than being covered by anything. UNMEASURED. */\n dissolveBlurDp: 10,\n /**\n * Over dark content the glass turns dark and 219 @9:33 switches the effect \"to apply a subtle\n * dimming instead\". Dimming is a reduction in luminance: dark content under dark glass merges\n * with it, and pushing the content down is what lets the glass sit above it. UNMEASURED.\n */\n dimAlpha: 0.1,\n /** A pinned view under the panel (column headers) gets a flat band instead of a gradual fade\n * (219 @9:41) — \"a stronger, more opaque boundary\" (356 @12:12). UNMEASURED. */\n hardBlurDp: 14,\n hardAlpha: 0.18,\n} as const;\n","import type { VireGlassOptics } from './material';\nimport { SHADOW_DENSITY, SIZE } from './law';\n\n/** Glass shape in dp. Circle and capsule are special cases of a rounded rectangle. */\nexport type VireGlassGeometry = {\n width: number;\n height: number;\n cornerRadius: number;\n};\n\nexport const circleGeometry = (size: number): VireGlassGeometry => ({\n width: size,\n height: size,\n cornerRadius: size / 2,\n});\n\nexport const capsuleGeometry = (width: number, height: number): VireGlassGeometry => ({\n width,\n height,\n cornerRadius: Math.min(width, height) / 2,\n});\n\nexport const roundedRectGeometry = (\n width: number,\n height: number,\n cornerRadius: number,\n): VireGlassGeometry => ({ width, height, cornerRadius });\n\nexport const halfMinDp = (g: VireGlassGeometry) => Math.max(Math.min(g.width, g.height) / 2, 1);\n\n/** Viewport margin for a drop that overshoots past the finger: a fraction of the element's half\n * size beyond the drag travel itself. The drop overshoots the body by no more than `dragLimit`,\n * and stitching adds smoothing on top of that — this term covers it too. */\nexport const MAX_STRETCH = 0.34;\n\n/**\n * How big this element reads, for the purpose of how thick its glass is.\n *\n * Not `halfMinDp`, which is half the narrower side and is the right measure for a bevel limit or a\n * contact radius but not for this: a 390x420 sheet and a 390x780 one have the same narrow side and\n * are not the same surface. Not the area either: a 900x8 rule has more area than a toolbar button\n * and is the thinnest glass in the interface.\n *\n * The geometric mean of the two respects both facts — the narrow side caps how much glass there\n * can be, and among shapes that share it, more surface reads as more glass. Derived, not\n * calibrated: it introduces no constant.\n */\nexport const sizeDp = (g: VireGlassGeometry) =>\n Math.sqrt(halfMinDp(g) * Math.max(Math.sqrt(g.width * g.height) / 2, 1));\n\n/**\n * Bigger element, thicker glass: a stronger lens, a deeper shadow (219 @6:36 — as glass \"flexes and\n * morphs to larger sizes, it simulates a thicker material with deeper shadows and more pronounced\n * lensing and refraction effects\"). Bevel and material thickness are specified for an element at a\n * reference size and grow as the square root of it.\n *\n * The ceiling is approached, never reached. A hard clip made every surface above it the same glass,\n * and above it was where the interface lives: a half-open sheet, a full-screen sheet, an iPad\n * sidebar and a 900px Mac panel all sat at exactly 2.4. The reference names sidebars as the LARGE\n * end of the range, so a model that stops responding before them has stopped obeying it.\n *\n * The curve below is the same square root; the join at `gainMin` is continuous in value and in\n * slope, and the asymptote is `gainMax` exactly as before. Both constants keep their values —\n * what changed is that saturation is smooth instead of a clip.\n */\nexport const sizeGain = (g: VireGlassGeometry) => {\n const raw = Math.sqrt(sizeDp(g) / SIZE.referenceDp);\n if (raw <= SIZE.gainMin) return SIZE.gainMin;\n const span = SIZE.gainMax - SIZE.gainMin;\n return SIZE.gainMin + span * (1 - Math.exp(-(raw - SIZE.gainMin) / span));\n};\n\n/** A bevel wider than this fraction of the half-size breaks the SDF: the roundings converge in\n * the middle. */\nexport const MAX_BEVEL_FRACTION = SIZE.maxBevelFraction;\n\nexport const bevelFraction = (g: VireGlassGeometry, o: VireGlassOptics) =>\n Math.min(MAX_BEVEL_FRACTION, (o.bevelDp * sizeGain(g)) / halfMinDp(g));\n\nexport const bevelDp = (g: VireGlassGeometry, o: VireGlassOptics) =>\n Math.max(bevelFraction(g, o) * halfMinDp(g), 1);\n\nexport const thicknessDp = (g: VireGlassGeometry, o: VireGlassOptics) =>\n o.thicknessDp * sizeGain(g);\n\n/** Glass height right at the silhouette, a fraction of thickness: without it there's nothing at\n * the edge to bend the ray. */\nexport const RIM_FRACTION = 0.85;\n\nexport const rimDp = (g: VireGlassGeometry, o: VireGlassOptics) => thicknessDp(g, o) * RIM_FRACTION;\n\n/** Bigger element, deeper and wider shadow (M 7:14). */\nexport const shadowReachDp = (g: VireGlassGeometry) =>\n Math.min(Math.max(halfMinDp(g) * 0.65, 6), 36);\n\n/** How far the second morph shape reaches past the first one's bounds. Without this margin the\n * fused shape gets clipped by the canvas edge and the experiment shows the wrong thing. */\nexport function morphReachDp(\n g: VireGlassGeometry,\n morph?: { offsetX: number; offsetY: number; width: number; height: number; smoothing: number },\n): number {\n if (!morph || morph.smoothing <= 0) return 0;\n return Math.max(\n 0,\n Math.abs(morph.offsetX) + morph.width / 2 - g.width / 2,\n Math.abs(morph.offsetY) + morph.height / 2 - g.height / 2,\n );\n}\n\n/**\n * Quantization step for the margin. The margin only needs to cover the sampling — its exact value\n * doesn't matter, but changing it every frame is expensive: the native lens view gets re-laid-out\n * and re-sets its `RenderEffect`. While dragging a panel or morphing, the margin used to drift\n * continuously, and that produced visible stutter. Round up to the step — size changes rarely.\n */\nconst PAD_STEP = 8;\nconst quantise = (v: number) => Math.ceil(v / PAD_STEP) * PAD_STEP;\n\n/**\n * Margin around the lens view on each side: beyond it, the shader has nothing to sample.\n *\n * FOUR things have to fit in here. The refraction sample with aberrations. The blur radius —\n * it also samples around the point. The gather radius — the rim picks it up from outside the\n * shape, and without the margin it goes black exactly where it should be catching the\n * surroundings. And drag travel: the lens view moves with the finger, but its bounds don't, and\n * the sample falls off the edge, which is how layers from under the glass leak through.\n */\nexport function lensPadDp(\n g: VireGlassGeometry,\n o: VireGlassOptics,\n morph?: Parameters<typeof morphReachDp>[1],\n dragLimit = 0,\n): number {\n const sampling = Math.max(o.blur, o.gatherRadiusDp);\n const stretch = halfMinDp(g) * MAX_STRETCH;\n return quantise(sampling + dragLimit + stretch + morphReachDp(g, morph) + 2);\n}\n\n/**\n * Margin around the surface canvas: the shadow reaches outside the shape, and dragging shifts it\n * further still.\n *\n * The multiplier is smaller than the shadow's full reach: under the finger, the shader for a\n * rising element multiplies the radius by 1.55, and the very end of that tail falls outside the\n * margin. Left that way on purpose — at the margin's edge it's at 1.2% alpha (2.5% before the\n * shadow was softened), and raising the multiplier means growing every surface view's area. If\n * that tail ever shows up on a device, fix it here.\n */\nexport function surfacePadDp(\n g: VireGlassGeometry,\n dragLimit = 0,\n morph?: Parameters<typeof morphReachDp>[1],\n): number {\n return quantise(shadowReachDp(g) * 1.2 + dragLimit + morphReachDp(g, morph) + 2);\n}\n\n/**\n * SHADOW DENSITY BY WHAT'S UNDER THE ELEMENT. Reference 219 @11:47, verbatim: \"increases the\n * opacity of its shadow when it is over text… lowers the opacity of its shadow when it is over a\n * solid light background.\" This is about content BEHIND THE ELEMENT, so it's a single value per\n * element, not a field over the shadow's area.\n *\n * The law lives here, not at the bench: while it was baked into the web renderer, shadows on\n * Android never adapted at all. The endpoints were checked against the reference by the depth of\n * the dip under the element — docs/benchmarks.md.\n */\nexport function shadowOpacity(busy: number): number {\n return (\n SHADOW_DENSITY.flat +\n Math.min(Math.max(busy, 0) * SHADOW_DENSITY.busyGain, SHADOW_DENSITY.busyRise)\n );\n}\n\n/** Same thing for platforms where the measurement flows through state: quantized coarsely, like\n * the ambient color, otherwise every probe sample would trigger a surface repaint. */\nexport function shadowOpacityFrom(sample: { busy: number }): number {\n return Math.round(shadowOpacity(sample.busy) / SHADOW_DENSITY.step) * SHADOW_DENSITY.step;\n}\n","// The single description of VireGlass geometry. Both shaders draw it from here: the SKSL surface\n// (`surface-shader.ts`) and the AGSL lens (`lens-shader.ts`, shipped as a string into the native\n// view). AGSL and SKSL are the same language, so the SDF no longer needs duplicating in Kotlin:\n// before, the surface's circle and the lens's rounded rectangle described different pieces of\n// glass, and the bevel constant had to be kept in sync by hand (docs/adr-001-rendering.md §3).\nimport { BEVEL, EPSILON, TOUCH } from './law';\n\n/** 2π. Structural, not a law — but the shader has no built-in for it. */\nconst VG_TAU = 6.28318530718;\n\nexport const VG_SDF = `\nfloat vgRoundRect(float2 p, float2 halfSize, float corner) {\n float2 q = abs(p) - halfSize + corner;\n return min(max(q.x, q.y), 0.0) + length(max(q, float2(0.0))) - corner;\n}\n\nfloat vgSmin(float a, float b, float k) {\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n return mix(b, a, h) - k * h * (1.0 - h);\n}\n\n// A scene is a single shape, and when k > 0 a smooth union with one or two neighbors. A third\n// shape exists to break the control into pieces (docs/reference.md §5): there are two bridges\n// there. It's turned off with a zero size, not its own k: the fused body shares one bridge.\nfloat vgScene(float2 p, float2 halfSize, float corner,\n float2 offsetB, float2 halfB, float cornerB, float k,\n float2 offsetC, float2 halfC, float cornerC) {\n float a = vgRoundRect(p, halfSize, corner);\n if (k <= 0.0) { return a; }\n float ab = vgSmin(a, vgRoundRect(p - offsetB, halfB, cornerB), k);\n if (halfC.x <= 0.0) { return ab; }\n return vgSmin(ab, vgRoundRect(p - offsetC, halfC, cornerC), k);\n}\n\n// Response to a finger. It's the FIELD around the touch point that deforms, not the shape's\n// bounding box: scaling width to pull the right edge would also pull the left one — liquid\n// doesn't behave that way. Here the displacement falls off with distance from the finger, so the\n// far edge stays put.\n//\n// The order of the terms matters: drag shifts the field, press pulls it toward the finger, the\n// wave rides on top of the already-shifted field — otherwise the ripple decouples from the\n// deformation and lives a life of its own.\nfloat2 vgTouchWarp(float2 p, float2 touch, float2 pull, float press, float radius,\n float waveAmp, float wavePhase) {\n if (radius <= 0.0) { return p; }\n // Under the finger the whole element grows (M 3:51; HIG: interactive \"expands\").\n p /= 1.0 + ${TOUCH.pressGrow} * press;\n float2 d = p - touch;\n float r = length(d);\n\n // The finger is a BLOB, not a point, but not a hard stamp either: a wide peak, soft edges. A\n // flat plateau with a sharp cutoff at the edge shifts the region as a block, and a straight\n // line under the glass breaks into a step — the deformation reads as rectangular even though\n // the finger is round. A double smoothstep gives the same contact width without that step.\n //\n // The influence cuts off at the radius rather than fading into an infinite tail like a\n // Gaussian: with a tail the deformation spreads into a \"rubber mattress\" bulge.\n float k = clamp((radius - r) / radius, 0.0, 1.0);\n float s = k * k * (3.0 - 2.0 * k);\n float core = s * s * (3.0 - 2.0 * s);\n // A ring around the blob: material displaced from under the finger has to end up somewhere.\n // Without this ridge the shape just balloons, and a dense medium doesn't behave that way.\n float rim = k * k * (1.0 - k) * 4.0;\n\n float2 q = p - pull * (core - ${TOUCH.ridge} * rim);\n q -= d * (press * ${TOUCH.pressPull} * core);\n\n // The wave has its own scale, twice the drag radius: the ripple has to reach the far edge,\n // otherwise it reads as jitter under the finger rather than a wave across the surface. The\n // wavelength is short: in a dense medium ripples are frequent and small, long shallow swells\n // are water.\n if (waveAmp > 0.0 && r > 0.0001) {\n float span = radius * ${TOUCH.waveSpan}.0;\n float ring = sin(r / (span * ${TOUCH.waveLength}) - wavePhase * ${VG_TAU}) * exp(-r / (span * ${TOUCH.waveDecay}));\n q -= (d / r) * ring * waveAmp;\n }\n return q;\n}\n\n// Analytical normal of a single shape: radial on the rounded part, axis-aligned on the straight\n// segments.\nfloat2 vgRoundRectNormal(float2 p, float2 halfSize, float corner) {\n float2 q = abs(p) - halfSize + corner;\n float2 g = (q.x > 0.0 && q.y > 0.0)\n ? normalize(max(q, float2(0.0001)))\n : (q.x > q.y ? float2(1.0, 0.0) : float2(0.0, 1.0));\n return g * sign(p);\n}\n\n// Normal of the union — ANALYTICAL, no more finite differences here.\n//\n// Derivation: smin has two terms, mix(b,a,h) and −k·h·(1−h). Their derivatives with respect to h\n// contain a factor of (1−2h) with opposite signs and cancel exactly, because h is linear in\n// (b−a)/k. What's left is mix(∇b, ∇a, h) — that is, the two shapes' normals, blended with the\n// same weight that blends the distances themselves.\n//\n// The previous version took four ADDITIONAL scene evaluations per pixel (each one — two shapes\n// plus smin) and was still an approximation. Here there are two shapes, exactly.\nfloat2 vgSceneNormal(float2 p, float2 halfSize, float corner,\n float2 offsetB, float2 halfB, float cornerB, float k,\n float2 offsetC, float2 halfC, float cornerC) {\n float2 na = vgRoundRectNormal(p, halfSize, corner);\n if (k <= 0.0) { return na; }\n float2 q = p - offsetB;\n float a = vgRoundRect(p, halfSize, corner);\n float b = vgRoundRect(q, halfB, cornerB);\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n float2 nab = normalize(mix(vgRoundRectNormal(q, halfB, cornerB), na, h) + float2(${EPSILON}, ${EPSILON}));\n if (halfC.x <= 0.0) { return nab; }\n // Same derivation as for the pair: normals blend with the same weight as the distances.\n float2 qc = p - offsetC;\n float ab = vgSmin(a, b, k);\n float c = vgRoundRect(qc, halfC, cornerC);\n float hc = clamp(0.5 + 0.5 * (c - ab) / k, 0.0, 1.0);\n return normalize(mix(vgRoundRectNormal(qc, halfC, cornerC), nab, hc) + float2(${EPSILON}, ${EPSILON}));\n}\n\n// Position within the bevel: 0 is the flat middle, 1 is the very edge. This one value feeds the\n// mask, thickness, refraction, aberrations and the width of the light rim.\nfloat vgBevelT(float sd, float bevel) {\n return clamp((sd + bevel) / bevel, 0.0, 1.0);\n}\n\n// Slope of the bevel profile — spherical: t / sqrt(1 - t²), like a spherical cap. The previous t²\n// kept the slope near zero through almost the whole bevel and then shot up right at the edge, so\n// all the optics bunched into a narrow ring and the element read as a PUCK — a flat top and a\n// wall around the rim. Here curvature is spread across the bevel, and the rim stops being a line.\n//\n// This still doesn't control the field of view: only the bevel bends, the middle stays flat,\n// otherwise the surface reads as a soap bubble.\nfloat vgBevelSlope(float t) {\n return min(t * inversesqrt(max(1.0 - t * t * ${BEVEL.sphere}, ${BEVEL.floor})), ${BEVEL.slopeMax});\n}\n\n// PROGRESS FRACTION. Progress is an active state turned into a FIELD: to the left of the boundary\n// the element is active, to the right it stays regular glass, and the boundary moves. A negative\n// value turns the field off entirely — zero is taken by the start of the track and can't also\n// mean off.\n//\n// The boundary is SOFT. A hard seam reads as two different materials glued together rather than\n// two states of one; the transition width is a fraction of the half-width, so it doesn't read as\n// a thread on a large element and doesn't swallow a small one whole.\nfloat vgProgress(float2 p, float2 halfSize, float progress) {\n if (progress < 0.0) { return 0.0; }\n float edge = mix(-halfSize.x, halfSize.x, clamp(progress, 0.0, 1.0));\n float soft = max(halfSize.x * 0.05, 1.0);\n return 1.0 - smoothstep(edge - soft, edge + soft, p.x);\n}\n`;\n\n/** Rate at which the offset builds toward the rim. Shared between the lens (actual sampling\n * offset) and the surface (visualizing the displacement field in debug mode) — otherwise they'd\n * drift apart. */\nexport const VG_FALLOFF = 2.6;\n\n// JS twin of `vgRoundRect`/`vgRoundRectNormal` above, for targets with no GPU to run the shader on\n// (the DOM displacement map). Term-for-term against the GLSL text: a second geometry that behaves\n// differently is exactly the class of bug `check:optics` exists to catch on the shader side, and\n// there is no such gate for this one.\n\n/** Signed distance from `(x, y)` to a rounded rect of size `w`×`h` centered on the origin. */\nexport function sdfRoundedRect(x: number, y: number, w: number, h: number, r: number): number {\n const qx = Math.abs(x) - w / 2 + r;\n const qy = Math.abs(y) - h / 2 + r;\n return Math.min(Math.max(qx, qy), 0) + Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) - r;\n}\n\n/**\n * Closed-form gradient of `sdfRoundedRect`, unit length everywhere except the exact center (where\n * it's genuinely undefined — the medial axis of the shape). NOT finite differences: differencing\n * quantizes the gradient to the sampling step, and the displacement map needs sub-pixel accuracy\n * right at the rim.\n */\nexport function sdfRoundedRectGradient(x: number, y: number, w: number, h: number, r: number): [number, number] {\n const qx = Math.abs(x) - w / 2 + r;\n const qy = Math.abs(y) - h / 2 + r;\n let gx: number;\n let gy: number;\n if (qx > 0 && qy > 0) {\n const cx = Math.max(qx, 0.0001);\n const cy = Math.max(qy, 0.0001);\n const len = Math.hypot(cx, cy);\n gx = cx / len;\n gy = cy / len;\n } else if (qx > qy) {\n gx = 1;\n gy = 0;\n } else {\n gx = 0;\n gy = 1;\n }\n return [gx * Math.sign(x), gy * Math.sign(y)];\n}\n\n// ---------------------------------------------------------------------------\n// JS twins of the shader functions above. The DOM renderer needs this geometry\n// as numbers, not as a string it hands to a compiler. Each mirrors its `vg*`\n// counterpart term for term — a second geometry that drifts is the failure the\n// platform-parity gate exists to catch.\n// ---------------------------------------------------------------------------\n\n/** Mirrors `vgSmin`. */\nexport function smin(a: number, b: number, k: number): number {\n const h = Math.min(Math.max(0.5 + (0.5 * (b - a)) / k, 0), 1);\n return b + (a - b) * h - k * h * (1 - h);\n}\n\n/**\n * The smallest `k` at which `smin` joins two surfaces `gap` apart into one body. Exact for this\n * smin rather than fitted: at the midpoint the two distances are both gap/2, so h = 0.5 and the\n * result is gap/2 − k/4, which reaches zero at k = 2·gap.\n *\n * It is the number `morphBetween` was missing. A neck sized only as a fraction of the element's\n * own half-size has nothing to do with the distance it has to span, so two controls a hundred\n * pixels apart stayed two controls at every t — including t = 1, where the contract says they are\n * one shared medium.\n */\nexport function neckToBridge(gap: number): number {\n return gap > 0 ? gap * 2 : 0;\n}\n\nexport type MorphShape = {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n cornerRadius: number;\n};\n\n/**\n * Mirrors the scene distance: one shape, smoothly unioned with any number of neighbours when\n * `smoothing` is positive. §5's merging and splitting are this union opening and closing.\n *\n * A fold, not a pair. The count used to be in the ARGUMENT NAMES — `b` and `c`, and a fourth\n * shape would have been `d` — which is not a limit the material has. Several independent elements\n * flowing into one whole is the behaviour; how many of them there happen to be is the host's.\n */\nexport function sceneDistance(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n smoothing = 0,\n ...shapes: (MorphShape | undefined)[]\n): number {\n let d = sdfRoundedRect(x, y, w, h, r);\n if (smoothing <= 0) return d;\n for (const s of shapes) {\n if (!s || s.width <= 0) continue;\n d = smin(d, sdfRoundedRect(x - s.offsetX, y - s.offsetY, s.width, s.height, s.cornerRadius), smoothing);\n }\n return d;\n}\n\n/**\n * Mirrors `vgSceneNormal`: normals blend with the same weight that blends the distances, which the\n * shader derives rather than approximates. The same fold as `sceneDistance`, carrying the running\n * distance alongside the running normal because each step's weight is measured against it.\n */\nexport function sceneGradient(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n smoothing = 0,\n ...shapes: (MorphShape | undefined)[]\n): [number, number] {\n let d = sdfRoundedRect(x, y, w, h, r);\n let [gx, gy] = sdfRoundedRectGradient(x, y, w, h, r);\n let blended = false;\n if (smoothing > 0) {\n for (const s of shapes) {\n if (!s || s.width <= 0) continue;\n const sx = x - s.offsetX;\n const sy = y - s.offsetY;\n const ds = sdfRoundedRect(sx, sy, s.width, s.height, s.cornerRadius);\n const weight = Math.min(Math.max(0.5 + (0.5 * (ds - d)) / smoothing, 0), 1);\n const [nx, ny] = sdfRoundedRectGradient(sx, sy, s.width, s.height, s.cornerRadius);\n gx = nx + (gx - nx) * weight;\n gy = ny + (gy - ny) * weight;\n d = smin(d, ds, smoothing);\n blended = true;\n }\n }\n // With nothing blended in, the base gradient is already a unit vector and is returned untouched —\n // the shader takes the same early exit (`if (k <= 0.0) return na;`), and nudging it here instead\n // would put the two renderers a rounding step apart on every flat edge in the material.\n if (!blended) return [gx, gy];\n // The shader's `+ float2(${EPSILON}, ${EPSILON})` before normalising, and it is not decoration:\n // where two shapes meet head-on their normals cancel exactly and the blend lands on zero.\n gx += EPSILON;\n gy += EPSILON;\n const len = Math.hypot(gx, gy) || 1;\n return [gx / len, gy / len];\n}\n\nexport type TouchWarp = {\n x: number;\n y: number;\n pullX: number;\n pullY: number;\n press: number;\n radius: number;\n waveAmp: number;\n wavePhase: number;\n};\n\n/**\n * Mirrors `vgTouchWarp`. The FIELD around the finger deforms, not the bounding box: scaling the\n * width to pull the right edge would pull the left one too, and liquid does not do that.\n *\n * Term order is load-bearing — drag shifts the field, press pulls it toward the finger, the wave\n * rides on the already-shifted field. Reordered, the ripple decouples and lives its own life.\n */\nexport function touchWarp(x: number, y: number, t: TouchWarp): [number, number] {\n if (t.radius <= 0) return [x, y];\n const grow = 1 + TOUCH.pressGrow * t.press;\n let px = x / grow;\n let py = y / grow;\n const dx = px - t.x;\n const dy = py - t.y;\n const r = Math.hypot(dx, dy);\n\n const k = Math.min(Math.max((t.radius - r) / t.radius, 0), 1);\n const s = k * k * (3 - 2 * k);\n const core = s * s * (3 - 2 * s);\n // The ridge around the blob: material pushed out from under the finger has to go somewhere.\n const rim = k * k * (1 - k) * 4;\n\n px -= t.pullX * (core - TOUCH.ridge * rim);\n py -= t.pullY * (core - TOUCH.ridge * rim);\n px -= dx * (t.press * TOUCH.pressPull * core);\n py -= dy * (t.press * TOUCH.pressPull * core);\n\n if (t.waveAmp > 0 && r > 0.0001) {\n const span = t.radius * TOUCH.waveSpan;\n const ring = Math.sin(r / (span * TOUCH.waveLength) - t.wavePhase * VG_TAU) * Math.exp(-r / (span * TOUCH.waveDecay));\n px -= (dx / r) * ring * t.waveAmp;\n py -= (dy / r) * ring * t.waveAmp;\n }\n return [px, py];\n}\n","// The DOM renderer's own optics: an `feDisplacementMap` source built from the same causes as the\n// GL/AGSL shaders, so a page refracting live content still reads as the same material. See\n// `docs/superpowers/specs/2026-09-19-vireglass-over-live-dom.md` for the technique this encodes.\nimport { bevelDp, thicknessDp, type VireGlassGeometry } from '../geometry';\nimport { BEVEL } from '../law';\nimport type { VireGlassOptics } from '../material';\nimport {\n sceneDistance,\n sceneGradient,\n touchWarp,\n type MorphShape,\n type TouchWarp,\n} from '../sdf';\n\nexport type DisplacementMap = { url: string; width: number; height: number; scale: number };\n\n/** dp of rim displacement per dp of size-adjusted thickness, at full refraction strength (ior →\n * 1.6). Tuned so the product default (V5: ior 1.5, thickness 28dp) lands well under `MAX_SCALE`\n * before it's ever clamped — the ceiling below is what actually limits denser glass. */\nconst SCALE_GAIN = 0.75;\n\n/**\n * `feDisplacementMap` displaces by `scale * (channel / 255 - 0.5)`: a full channel swing spans\n * ±scale/2, and one 8-bit step is `scale/255` px — not `scale/127`, which an earlier version of\n * this file assumed and which rendered every material at half its derived refraction.\n *\n * Measured in Chromium on 2026-09-19: at scale 40 (0.157 px/step) a high-contrast edge visibly\n * terraces; at scale 12 (0.047 px/step) it does not. The ceiling sits between them and nearer\n * the clean end — thick, high-index glass is flattened to it instead of its derived scale,\n * trading rim depth for an edge without stairs.\n */\nconst MAX_STEP_PX = 0.09;\nconst MAX_SCALE = 255 * MAX_STEP_PX;\n\n/**\n * Samples across the bevel band, which is the only place the map carries anything. Everything\n * inside it is a constant, and `feImage` stretches whatever it is given over the element anyway,\n * so resolving the element is wasted work: a sheet at device resolution is 197 000 pixels of\n * per-pixel maths and a PNG encode, 120 ms on attach and far past a frame during interaction.\n *\n * Eight samples describe a profile that is smooth by construction. The measured cost falls with\n * the square of the reduction, and `check:dom` measures the displacement afterwards to say\n * whether anything was lost.\n */\nconst BEVEL_SAMPLES = 8;\n\n/** Resolution the map is built at: enough to resolve the bevel, never more than the element. */\nfunction mapDensity(geometry: VireGlassGeometry, bevel: number, dpr: number): number {\n if (bevel <= 0) return dpr;\n return Math.min(dpr, BEVEL_SAMPLES / bevel);\n}\n\n/** True neutral is the unrepresentable 127.5; 128 is the nearest byte and leaves a residual\n * 0.002 of the scale, far below one step and below a pixel at any usable scale. */\nfunction encode(displacement: number, scale: number): number {\n const channel = Math.round(255 * (displacement / scale + 0.5));\n return channel < 0 ? 0 : channel > 255 ? 255 : channel;\n}\n\n/** Mirrors the shader's `vgBevelSlope`, renormalized into 0..1: curvature concentrated at the\n * rim, the middle left flat. A plain linear ramp from `vgBevelT` alone reads as a chamfer, not a\n * lens — the same reason the shader doesn't use it raw either. */\nfunction bevelProfile(t: number): number {\n const raw = Math.min(t / Math.sqrt(Math.max(1 - t * t * BEVEL.sphere, BEVEL.floor)), BEVEL.slopeMax);\n return raw / BEVEL.slopeMax;\n}\n\nexport type DisplacementState = {\n /** Finger response (docs/reference.md §5): the field around the touch deforms, so the silhouette\n * the backdrop bends along deforms with it. */\n touch?: TouchWarp;\n /** Smooth-union neighbours (§5): shapes merging into one and splitting apart. */\n smoothing?: number;\n morph?: MorphShape;\n morph2?: MorphShape;\n /** Any number of shapes flowing into this one. `morph`/`morph2` are the first two, kept so a\n * caller that only ever had two does not have to change. */\n morphs?: readonly MorphShape[];\n};\n\n/**\n * The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.\n * `buildDisplacementMap` below is a thin DOM wrapper around this.\n *\n * Encoding: R = x offset, G = y offset, 128 = no shift, one step = `scale/255` px; B = 128\n * (unused), A = 255 (opaque, `feImage` would otherwise composite the map against page black).\n * The offset points INWARD — the rim samples the backdrop from inside the shape, a convex thick\n * lens. Displacement lives only in the bevel band (`bevelDp`); the flat middle is exactly 128/128.\n */\nexport function renderDisplacementPixels(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n state: DisplacementState = {},\n): { data: Uint8ClampedArray; width: number; height: number; scale: number } {\n const bevel = bevelDp(geometry, optics);\n const density = mapDensity(geometry, bevel, dpr);\n const width = Math.max(1, Math.round(geometry.width * density));\n const height = Math.max(1, Math.round(geometry.height * density));\n const rawScale = optics.refraction * thicknessDp(geometry, optics) * SCALE_GAIN;\n const scale = Math.min(rawScale, MAX_SCALE);\n const smoothing = state.smoothing ?? 0;\n // One list, whichever way the caller expressed it.\n const shapes: (MorphShape | undefined)[] = [state.morph, state.morph2, ...(state.morphs ?? [])];\n\n const data = new Uint8ClampedArray(width * height * 4);\n const halfW = geometry.width / 2;\n const halfH = geometry.height / 2;\n\n for (let py = 0; py < height; py += 1) {\n const y = (py + 0.5) / density - halfH;\n for (let px = 0; px < width; px += 1) {\n const x = (px + 0.5) / density - halfW;\n const i = (py * width + px) * 4;\n // Warp the FIELD first, then read the scene at the warped point — the shader's own order.\n const [wx, wy] = state.touch ? touchWarp(x, y, state.touch) : [x, y];\n const sd = sceneDistance(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);\n const t = Math.min(Math.max((sd + bevel) / bevel, 0), 1);\n if (t <= 0 || scale <= 0) {\n data[i] = 128;\n data[i + 1] = 128;\n data[i + 2] = 128;\n data[i + 3] = 255;\n continue;\n }\n const [gx, gy] = sceneGradient(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);\n // The rim reaches half the scale: the encoding can only span ±scale/2, so the derived\n // displacement is expressed as a fraction of that half-range.\n const magnitude = bevelProfile(t) * (scale / 2);\n const dx = -gx * magnitude;\n const dy = -gy * magnitude;\n // Inverse of the spec's own formula: channel = 255 * (displacement / scale + 0.5).\n data[i] = encode(dx, scale);\n data[i + 1] = encode(dy, scale);\n data[i + 2] = 128;\n data[i + 3] = 255;\n }\n }\n\n return { data, width, height, scale };\n}\n\nfunction hasCanvasSupport(): boolean {\n return typeof document !== 'undefined' && typeof document.createElement === 'function';\n}\n\n/** Builds the map at device-pixel resolution so it stays sharp once the browser stretches it back\n * over the element's CSS-px box (`feImage` fills the filter region regardless of source size). */\nexport function buildDisplacementMap(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n state: DisplacementState = {},\n): DisplacementMap {\n if (!hasCanvasSupport()) {\n throw new Error('vireglass/dom: buildDisplacementMap requires a DOM (canvas)');\n }\n const { data, width, height, scale } = renderDisplacementPixels(optics, geometry, dpr, state);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('vireglass/dom: 2D canvas context unavailable');\n const imageData = ctx.createImageData(width, height);\n imageData.data.set(data);\n ctx.putImageData(imageData, 0, 0);\n return { url: canvas.toDataURL('image/png'), width, height, scale };\n}\n","// The spectral edge (docs/reference.md §1). Dispersion, diffraction and interference are ONE\n// cause — a dependence on wavelength — and one hue multiplier, normalised to its own mean, so they\n// colour what passes through without brightening it.\n//\n// JS twins of the lens shader's `vgInterference`, `vgDiffraction` and the rim profile they read\n// from. Same reason as the SDF's twins: the DOM path needs this geometry as numbers, and a second\n// version that drifts is the defect the parity gate exists for.\nimport { LENS, SPECTRAL } from './law';\n\nconst TAU = 6.28318530718;\nconst LAMBDA: readonly [number, number, number] = [LENS.lambdaR, LENS.lambdaG, LENS.lambdaB];\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/** Normalises a triple to its own mean — the step that makes these hues rather than gains. */\nfunction toHue(v: [number, number, number]): [number, number, number] {\n const mean = Math.max((v[0] + v[1] + v[2]) / 3, 0.001);\n return [v[0] / mean, v[1] / mean, v[2] / mean];\n}\n\n/** Mirrors `vgRimQd`: the derivative of the rim's height profile. */\nexport function rimSlopeCurve(x: number): number {\n const k = 1 - clamp01(x);\n return (k * k * k) / Math.pow(Math.max(1 - k * k * k * k, 1e-5), 0.75);\n}\n\n/** Mirrors `vgSlope`: the top face's slope at distance `e` inside the silhouette. */\nexport function surfaceSlope(e: number, bevel: number, rim: number, thick: number): number {\n if (e >= bevel || bevel <= 0) return 0;\n return Math.min(((thick - rim) / bevel) * rimSlopeCurve(e / bevel), LENS.slopeMax);\n}\n\n/** The normal's z, which is what both spectral terms are measured against. `N = normalize([n·s, 1])`\n * in the shader, so its z is simply the slope resolved back to unit length. */\nexport function surfaceCosine(slope: number): number {\n return 1 / Math.sqrt(1 + slope * slope);\n}\n\n/** Thin-film interference: optical path difference 2·n·d·cosθt, each channel with its own λ. */\nexport function interference(cosI: number, filmNm: number): [number, number, number] {\n const sinT2 = (1 - cosI * cosI) / (LENS.filmIor * LENS.filmIor);\n const cosT = Math.sqrt(Math.max(1 - sinT2, 0));\n const opd = 2 * LENS.filmIor * filmNm * cosT;\n return toHue([\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[0] + Math.PI),\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[1] + Math.PI),\n 0.5 + 0.5 * Math.cos((TAU * opd) / LAMBDA[2] + Math.PI),\n ]);\n}\n\n/** Edge diffraction: fringes get denser as the bevel sharpens. A hue, not a brightness. */\nexport function diffraction(distFromEdge: number, bevel: number): [number, number, number] {\n const phase = (TAU * SPECTRAL.diffractionFringes * distFromEdge) / Math.max(bevel, 1);\n const f = (lambda: number) => 0.5 + 0.5 * Math.cos((phase * SPECTRAL.referenceLambda) / lambda);\n return toHue([f(LAMBDA[0]), f(LAMBDA[1]), f(LAMBDA[2])]);\n}\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n const t = clamp01((x - edge0) / (edge1 - edge0));\n return t * t * (3 - 2 * t);\n}\n\n/**\n * Both terms at one point, weighted as the lens weights them: interference by `iridescence` across\n * the bevel, diffraction by its own strength but only within `diffractionOnset` of the silhouette.\n *\n * `e` is the distance inside the edge; everything else comes from the resolved optics.\n */\nexport function spectralHue(\n e: number,\n bevel: number,\n rim: number,\n thick: number,\n optics: { film: number; iridescence: number; diffraction: number },\n): [number, number, number] {\n let r = 1;\n let g = 1;\n let b = 1;\n\n // `t` is 1 at the silhouette and 0 at the inner edge of the bevel, as below.\n const t = 1 - clamp01(bevel > 0 ? e / bevel : 1);\n\n if (optics.iridescence > 0.001) {\n // Windowed to the edge, for the same reason diffraction is: §2 puts the iridescence on the\n // opposing arc, and an arc is at the silhouette. Unwindowed, the surface angle stops changing a\n // third of the way in and the film paints the rest of the bevel one flat colour.\n const w = optics.iridescence * smoothstep(SPECTRAL.iridescenceOnset, 1, t);\n if (w > 0) {\n const cosI = clamp01(surfaceCosine(surfaceSlope(e, bevel, rim, thick)));\n const i = interference(cosI, optics.film);\n r += (i[0] - 1) * w;\n g += (i[1] - 1) * w;\n b += (i[2] - 1) * w;\n }\n }\n\n if (optics.diffraction > 0.001) {\n // The fringes live at the outer end of the bevel, which is what makes this an EDGE effect\n // rather than a sheen over it.\n const w = optics.diffraction * smoothstep(SPECTRAL.diffractionOnset, 1, t);\n if (w > 0) {\n const d = diffraction(e, bevel);\n r += (d[0] - 1) * w;\n g += (d[1] - 1) * w;\n b += (d[2] - 1) * w;\n }\n }\n\n return [r, g, b];\n}\n","// The spectral edge, baked into an image (docs/reference.md §1).\n//\n// Diffraction and interference are hue multipliers that vary per pixel across the bevel, and an\n// SVG filter has no way to evaluate a function per pixel. But it can MULTIPLY by an image:\n// `feComposite operator=\"arithmetic\"` with k1 set is a product, so the hue can be baked and\n// applied in one pass.\n//\n// The multiplier exceeds 1 wherever a channel is boosted, and eight bits cannot carry that, so the\n// map stores the hue divided by a headroom the filter multiplies back. Without the headroom every\n// boosted channel would clip to white and the fringes would read as a bright rim rather than a\n// coloured one.\nimport { bevelDp, rimDp, thicknessDp, type VireGlassGeometry } from '../geometry';\nimport type { VireGlassOptics } from '../material';\nimport { sdfRoundedRect } from '../sdf';\nimport { spectralHue } from '../spectral';\n\nexport type SpectralMap = { url: string; width: number; height: number; headroom: number };\n\n/** A hue normalised to its own mean cannot exceed the number of channels; in practice it stays\n * well under two. Two is the smallest headroom that never clips. */\nconst HEADROOM = 2;\n\n/**\n * The hue map is sampled like the displacement map — across the bevel, not across the element. It\n * needs MORE samples than the displacement does, because fringes oscillate where the displacement\n * is monotonic, and undersampling a fringe pattern aliases it into a different one.\n */\nconst BEVEL_SAMPLES = 24;\n\nfunction mapDensity(bevel: number, dpr: number): number {\n if (bevel <= 0) return dpr;\n return Math.min(dpr, BEVEL_SAMPLES / bevel);\n}\n\nexport function renderSpectralPixels(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n): { data: Uint8ClampedArray; width: number; height: number; headroom: number } {\n const bevel = bevelDp(geometry, optics);\n const density = mapDensity(bevel, dpr);\n const width = Math.max(1, Math.round(geometry.width * density));\n const height = Math.max(1, Math.round(geometry.height * density));\n const rim = rimDp(geometry, optics);\n const thick = thicknessDp(geometry, optics);\n\n const data = new Uint8ClampedArray(width * height * 4);\n const halfW = geometry.width / 2;\n const halfH = geometry.height / 2;\n const neutral = Math.round((1 / HEADROOM) * 255);\n\n for (let py = 0; py < height; py += 1) {\n const y = (py + 0.5) / density - halfH;\n for (let px = 0; px < width; px += 1) {\n const x = (px + 0.5) / density - halfW;\n const i = (py * width + px) * 4;\n const sd = sdfRoundedRect(x, y, geometry.width, geometry.height, geometry.cornerRadius);\n const e = Math.max(-sd, 0);\n if (e >= bevel) {\n // Past the bevel the glass is plain: a neutral multiplier, not a missing one.\n data[i] = neutral;\n data[i + 1] = neutral;\n data[i + 2] = neutral;\n data[i + 3] = 255;\n continue;\n }\n const [r, g, b] = spectralHue(e, bevel, rim, thick, optics);\n data[i] = Math.round((r / HEADROOM) * 255);\n data[i + 1] = Math.round((g / HEADROOM) * 255);\n data[i + 2] = Math.round((b / HEADROOM) * 255);\n data[i + 3] = 255;\n }\n }\n\n return { data, width, height, headroom: HEADROOM };\n}\n\n/** Whether this material has a spectral edge at all. Three extra filter primitives and a per-pixel\n * bake are not worth paying for a multiplier that is flat 1. */\nexport function hasSpectralEdge(optics: VireGlassOptics): boolean {\n return optics.iridescence > 0.001 || optics.diffraction > 0.001;\n}\n\nexport function buildSpectralMap(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n dpr: number,\n): SpectralMap {\n if (typeof document === 'undefined' || typeof document.createElement !== 'function') {\n throw new Error('vireglass/dom: buildSpectralMap requires a DOM (canvas)');\n }\n const { data, width, height, headroom } = renderSpectralPixels(optics, geometry, dpr);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('vireglass/dom: 2D canvas context unavailable');\n const image = ctx.createImageData(width, height);\n image.data.set(data);\n ctx.putImageData(image, 0, 0);\n return { url: canvas.toDataURL('image/png'), width, height, headroom };\n}\n","// Maps are pure functions of geometry, optics and density — the same element twice, or four\n// identical buttons in a tab bar, produce byte-identical PNGs. Building each one again is the\n// single largest avoidable cost in this renderer: a sheet's hue map is tens of milliseconds, and\n// it happens on every attach, every remount and every re-attach after a theme change.\n//\n// Small and strict on purpose. A page has a handful of distinct glass shapes, not hundreds; a\n// cache that grew without bound would hold megabytes of data URIs alive for a screen nobody is\n// looking at any more.\nconst LIMIT = 24;\n\nconst store = new Map<string, unknown>();\n\nexport function cached<T>(key: string, build: () => T): T {\n const hit = store.get(key);\n if (hit !== undefined) {\n // Re-inserting moves it to the end: the oldest key is the one evicted, not the most used one.\n store.delete(key);\n store.set(key, hit);\n return hit as T;\n }\n const value = build();\n store.set(key, value);\n if (store.size > LIMIT) {\n const oldest = store.keys().next();\n if (!oldest.done) store.delete(oldest.value);\n }\n return value;\n}\n\n/** Test-only: the cache is process-wide, and a suite that measures build cost needs it cold. */\nexport function clearMapCache(): void {\n store.clear();\n}\n\nexport function mapCacheSize(): number {\n return store.size;\n}\n","// Deriving optics from the medium's properties. The material describes CAUSES (index of\n// refraction, thickness, bevel, roughness); the shaders need EFFECTS — this file translates one\n// into the other. Pure functions: the physics is checked by tests, not on a device.\n//\n// The normalisations themselves are in `law.ts` under DERIVE, with the rest of the calibration.\n// They are honestly labelled there: the rendering is stylised, and literal physical values (glass\n// reflects 4% at normal incidence) produce effects right at the threshold of visibility. Each is\n// monotonic in its own cause, so \"denser medium → more visible rim\" always holds, and no\n// impossible combination can arise.\nimport { DERIVE } from './law';\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\nconst clamp01 = (v: number) => clamp(v, 0, 1);\n\n/** Reflectance at normal incidence: ((n−1)/(n+1))². For glass, n=1.5 gives 0.04. */\nexport const fresnelF0 = (ior: number) => ((ior - 1) / (ior + 1)) ** 2;\n\nexport const fresnelStrength = (ior: number) => clamp01(fresnelF0(ior) * DERIVE.fresnelGain);\n\n/** Exponent in the Schlick approximation — a constant of the model, not a knob. */\nexport const FRESNEL_EXPONENT = DERIVE.fresnelExponent;\n\n/** Strength of ray bending. As n→1 the medium is indistinguishable from air; n=1.6 is taken as\n * full strength. */\nexport const refractionStrength = (ior: number) => clamp01((ior - 1) / DERIVE.iorFullBend);\n\nexport const refractionScale = (ior: number, thicknessDp: number) =>\n 1 + DERIVE.magnifyPerDp * thicknessDp * (1 - 1 / Math.max(ior, 1));\n\nexport const dispersion = (ior: number) => clamp01((ior - 1) * DERIVE.dispersionPerIor);\n\nexport const iorSpread = (ior: number) => dispersion(ior) * DERIVE.iorSpreadPerDispersion;\n\nexport const absorption = (pathDp: number) =>\n 1 - Math.exp(-DERIVE.absorbPerDp * Math.max(pathDp, 0));\n\n/**\n * Density at the bevel relative to the body. Not a separate quantity: at the rim the ray travels\n * LONGER through the medium by the bevel's width, and absorption over that path is greater. This\n * used to be a separate `edgeDensity` slider, which is how a thin bevel with a milky rim got\n * built — a state that doesn't occur in real glass.\n */\nexport const edgeDensity = (thicknessDp: number, bevelDp: number) => {\n const body = absorption(thicknessDp);\n if (body <= 0) return 1;\n return clamp(absorption(thicknessDp + bevelDp) / body, 1, DERIVE.edgeDensityMax);\n};\n\n/**\n * Backdrop haziness — surface roughness, not a separate blur setting.\n *\n * The ceiling is deliberately low. Blur in this model is a SUPPORTING device: it helps ink sit\n * over glass, but doesn't improve the picture on its own. Past roughly a dozen dp, letters under\n * the glass stop being letters and turn into a mush of pixels — no amount of legibility justifies\n * that. Separating content from the ink is body density's job, not blur's.\n */\nexport const blur = (roughness: number) => clamp01(roughness) * DERIVE.blurMaxDp;\n\n/** A smooth surface gives a narrow highlight, a rough one a spread-out one. */\nexport const specularPower = (roughness: number) =>\n DERIVE.specularPowerSmooth -\n clamp01(roughness) * (DERIVE.specularPowerSmooth - DERIVE.specularPowerRough);\n\n/** Highlight brightness — the same reflectance as Fresnel, damped by roughness. */\nexport const specularStrength = (ior: number, roughness: number) =>\n clamp01(fresnelStrength(ior) * (1 - clamp01(roughness) * DERIVE.specularRoughDamping));\n\n/**\n * Color of the medium. Never set by hand: in transparent media, hue is tied to density. Water\n * absorbs red and skews cool, ordinary glass is nearly neutral with a faint green, dense\n * high-index media skew warm. Lightness follows reflectance: the denser the medium, the more of\n * its surroundings it returns, and the lighter its body reads.\n */\ntype Hue = readonly [number, number, number];\nconst mixHue = (a: Hue, b: Hue, t: number): Hue => [\n a[0] + (b[0] - a[0]) * t,\n a[1] + (b[1] - a[1]) * t,\n a[2] + (b[2] - a[2]) * t,\n];\n\nexport function mediumTint(ior: number): { r: number; g: number; b: number } {\n const t = clamp01((ior - DERIVE.hueFromIor) / DERIVE.hueSpan);\n const hue =\n t < 0.5\n ? mixHue(DERIVE.hueCool, DERIVE.hueNeutral, t * 2)\n : mixHue(DERIVE.hueNeutral, DERIVE.hueWarm, (t - 0.5) * 2);\n const lift = DERIVE.bodyLiftBase + fresnelF0(ior) * DERIVE.bodyLiftPerF0;\n return { r: clamp01(hue[0] * lift), g: clamp01(hue[1] * lift), b: clamp01(hue[2] * lift) };\n}\n\n/**\n * How far the rim gathers light AROUND the element.\n *\n * On real glass, at a grazing angle the eye receives not what's under the glass but the\n * surroundings: an object on a black table next to a lamp catches the lamp. So the radius is\n * noticeably larger than the bevel — it's the element's vicinity, not its rim. Without this,\n * glass on an empty black background has no source at all and honestly disappears.\n */\n/**\n * Ceiling on the radius. Without it, a wide bevel would gather its surroundings from fifty-odd dp\n * away, and a READABLE copy of whatever sits nearby would appear inside the glass: eight samples\n * aren't enough to blur a disc that large (E-33, E-37). Real rims also gather light mostly from\n * nearby — an unbounded radius was a modeling mistake.\n */\nexport const gatherRadius = (bevelDp: number) =>\n clamp(Math.max(bevelDp, 1) * DERIVE.gatherPerBevel, DERIVE.gatherMinDp, DERIVE.gatherMaxDp);\n\n/**\n * The body's own density from absorption through its thickness. Small: glass has no color of its\n * own, the body only moves toward the tint under the legibility requirement (HIG \"Color\"),\n * otherwise it dims the content.\n */\nexport const bodyDensity = (thicknessDp: number) =>\n DERIVE.bodyDensity * absorption(thicknessDp);\n\n/**\n * Highlight normalization. `fresnelStrength`'s ×17.5 factor is tuned for the rim highlight's\n * visibility and saturates at one for dense media; applying it to the highlight too would raise\n * body lightness harder than the glass had just separated it from the ink — eating its own\n * legibility work. This uses the physical scale instead.\n */\n/** How much the rim picks up the light and color of its surroundings. The same reflectance as\n * Fresnel: no separate knob — a dense medium returns more of its surroundings by construction. */\n\nexport const edgeLight = (ior: number) => clamp01(fresnelF0(ior) * DERIVE.edgeLightGain);\n\n/**\n * THE SPECTRAL PART. Three phenomena — dispersion, diffraction and interference — share one\n * cause: index of refraction and phase both depend on wavelength. So there are no separate\n * \"rainbow strength\" knobs here: everything is derived from the medium's density and film\n * thickness.\n */\n\n/**\n * Rim iridescence is visible exactly as much as the REFLECTION is bright: interference lives in\n * the reflected ray, not the transmitted one. Hence the tie to Fresnel — there's no strength knob\n * of its own.\n */\nexport const iridescence = (ior: number, filmNm: number) =>\n filmNm <= 0 ? 0 : clamp01(fresnelStrength(ior) * DERIVE.iridescencePerFresnel);\n\n/**\n * Edge diffraction. Same λ-dependence as dispersion, so it shares its strength; the bevel sets\n * the fringe frequency — wide bevels give sparse fringes, sharp ones frequent (in the shader this\n * is divided by bevel width). The 0.5 normalization reflects the stylized render: at the physical\n * amplitude the fringes aren't visible at all.\n */\nexport const diffraction = (ior: number) =>\n clamp01(dispersion(ior) * DERIVE.diffractionPerDispersion);\n\n/**\n * How much the body picks up the COLOR of its surroundings. This is multiple internal reflection:\n * the denser the medium, the more light it circulates inside itself, and the more strongly it's\n * tinted by what's around it. The ceiling is deliberately low — the tint has to stay a medium, not\n * become a flat color fill.\n */\nexport const colorPickup = (ior: number) =>\n clamp(fresnelStrength(ior) * DERIVE.colorPickupPerFresnel, 0, DERIVE.colorPickupMax);\n","// VireGlass material model.\n//\n// Two distinct objects, and they must not be confused:\n//\n// VireGlassMaterial — CAUSES. What a piece of glass is described by: index of refraction,\n// thickness, bevel width, roughness, absorption color. This is what gets\n// configured.\n// VireGlassOptics — EFFECTS. Eighteen values the shaders need. Not configured: they're\n// derived (`resolveOptics`, physics in `optics.ts`).\n//\n// Before v4, what was exposed were the effects themselves — eighteen independent sliders. Half of\n// them are physically dependent, so combining them produced states that don't occur in real\n// glass: a thin bevel with a dense white rim, rim optics as a fraction of the element's own size.\n// Every such case was patched by adding yet another slider (`edgeDensity`, a size compensation) —\n// that is, compensating for physics that wasn't there. Here there's one cause, and the effects\n// are derived.\n\nimport {\n absorption,\n blur as blurFrom,\n dispersion as dispersionFrom,\n edgeDensity as edgeDensityFrom,\n gatherRadius as gatherRadiusFrom,\n fresnelStrength,\n FRESNEL_EXPONENT,\n mediumTint,\n refractionScale as refractionScaleFrom,\n refractionStrength,\n specularPower as specularPowerFrom,\n bodyDensity as bodyDensityFrom,\n edgeLight as edgeLightFrom,\n iridescence as iridescenceFrom,\n diffraction as diffractionFrom,\n colorPickup as colorPickupFrom,\n specularStrength,\n iorSpread as iorSpreadFrom,\n} from './optics';\n\nexport type VireGlassTint = { r: number; g: number; b: number };\n\nexport type VireGlassMaterial = {\n /** Index of refraction of the medium. Water 1.33, glass 1.5, sapphire 1.77. */\n ior: number;\n /** Glass thickness, dp. Drives center magnification and absorption. */\n thickness: number;\n /** Bevel width, dp. Absolute: on real glass the rim doesn't depend on the piece's size. */\n bevel: number;\n /** Surface roughness: backdrop haziness and highlight blur. */\n roughness: number;\n /** Response to device orientation, 0 means the light is locked to the screen. */\n environment: number;\n /** Not physics but a legibility requirement: how strongly the glass has to separate its own\n * lightness from the ink drawn over it. 0 means the glass is simply transparent. */\n legibility: number;\n /** Dimming layer UNDER the glass, 0..1. For the transparent (Clear) variant this is what\n * provides legibility: that glass has no adaptation, and without dimming the ink drowns over\n * bright content.\n *\n * Not to be confused with the mobile surface's `dim` prop: that one compensates for a platform\n * capture quirk (BlurView can't see a scrim drawn over the content), while this is a property\n * of the material itself. */\n dimming: number;\n /** Lightness of what the app draws OVER the glass: 1 is light icons and text, 0 is dark. A\n * cause, not a knob: the calling screen knows it. */\n ink: number;\n /** Minimum PRESENCE of the element itself: a floor on its body density, tinted toward light and\n * fading as the backdrop nears the light pole. Not the same as `legibility` — that's about the ink OVER the glass,\n * this is about the element itself. Over a uniform backdrop the glass has nothing to refract,\n * and the element disappears; for a control that's unacceptable. 0 means no presence is\n * required.\n *\n * The direction is always toward light, whatever the ink: the reference body is lighter than\n * its surroundings from dark video to sky, under a white glyph as much as a dark one, and only\n * as far as the range allows. It never darkens the element on its own account. What can send\n * the body to the ink's pole is the ink's legibility over texture, a system setting (reduced\n * transparency, increased contrast) or a density past `BODY.inkPoleTo`. */\n presence: number;\n /** Surface film thickness, nm. This is where interference comes from: the optical path\n * difference in the film becomes comparable to the wavelength, and the reflection picks up\n * iridescence. 0 means no film. */\n film: number;\n};\n\nexport const MATERIAL_RANGES = {\n ior: [1, 2],\n thickness: [0, 60],\n bevel: [0, 40],\n roughness: [0, 1],\n environment: [0, 1],\n legibility: [0, 1],\n dimming: [0, 0.5],\n ink: [0, 1],\n presence: [0, 0.6],\n film: [0, 900],\n} as const satisfies Record<string, readonly [number, number]>;\n\nexport type VireGlassNumericKey = keyof typeof MATERIAL_RANGES;\n\n/** Radius over which the LOCAL backdrop lightness is taken, dp. Not per-pixel: otherwise the\n * glass chases individual strokes and a halo appears around letters beneath it. */\nexport const ADAPT_RADIUS = 22;\n\n/** Lens dimming on product surfaces — a flat fill over the backdrop. */\nexport const PRODUCT_DIM = 0.2;\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\n\n/** The values the shaders need. Assembled from the material, never set by hand. */\nexport type VireGlassOptics = {\n blur: number;\n refraction: number;\n refractionScale: number;\n /** Bevel width in dp — an absolute property of the medium. */\n bevelDp: number;\n /** Radius over which the rim gathers light around the element. */\n gatherRadiusDp: number;\n fresnel: number;\n fresnelPower: number;\n specular: number;\n specularPower: number;\n dispersion: number;\n tint: VireGlassTint;\n tintStrength: number;\n edgeDensity: number;\n environment: number;\n legibility: number;\n /** Dimming of the content under the glass — the very layer of the Clear variant. */\n dimming: number;\n ink: number;\n /** Minimum presence of the element against the backdrop — in units of lightness. */\n presence: number;\n adaptRadius: number;\n bodyDensity: number;\n edgeLight: number;\n /** Film thickness, nm — passed straight to the shader: the path difference is computed in the\n * same units. */\n film: number;\n /** Strength of reflection iridescence. */\n iridescence: number;\n /** Strength of the edge diffraction fringes. */\n diffraction: number;\n /** How much the body is tinted by the color of its surroundings. */\n colorPickup: number;\n /** Index of refraction: the shader computes ray bending from it via Snell's law. */\n ior: number;\n /** Plate thickness, dp — before the correction for element size. */\n thicknessDp: number;\n /** Spread of the index between the red and blue channels — dispersion. */\n iorSpread: number;\n};\n\n// The product default — \"water\": lower index of refraction, thinner medium and bevel, an almost\n// smooth surface. Chosen on-device at the bench.\nexport const VIREGLASS_MATERIAL_V4: VireGlassMaterial = {\n ior: 1.33,\n thickness: 14,\n bevel: 5,\n roughness: 0.05,\n environment: 0.27,\n legibility: 0.26,\n dimming: 0,\n ink: 1,\n presence: 0.05,\n film: 340,\n};\n\n\n/**\n * Glass, not water. v4's index of refraction, 1.33, is water: almost no reflection at the rim,\n * almost no dispersion, 2% magnification. On screen that surface honestly reads as \"nothing much\",\n * and it was being mistaken for glass that wasn't rendering at all.\n *\n * 1.5 is ordinary glass. The effects follow from it on their own: reflection at the rim twice as\n * strong, dispersion one and a half times, ambient color pickup at its ceiling. Thickness is\n * raised a little too: it drives magnification, but absorption comes along with it, and\n * absorption is blackness.\n */\nexport const VIREGLASS_MATERIAL_V5: VireGlassMaterial = {\n ior: 1.5,\n thickness: 28,\n bevel: 6,\n roughness: 0.06,\n environment: 0.27,\n legibility: 0.26,\n dimming: 0,\n ink: 1,\n presence: 0.05,\n film: 340,\n};\n\n/**\n * Frosted sheet glass. The sheet sits over a LIVE screen, and it can't be transparent: transport\n * buttons and progress used to read right through it — the layout looked broken. Dimming doesn't\n * fix this (a flat scrim over a sharp picture doesn't hide it), so roughness is raised instead: it\n * drives `u_frost`, a floor on backdrop blur that the adaptive-blur ceiling doesn't reach.\n */\nexport const VIREGLASS_SHEET_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n roughness: 0.85,\n};\n/** The product's material. Consumers use this, not a specific version by name. */\n/**\n * Glass under large text (the lyrics panel in the player).\n *\n * The product material with NO change to optics — only `legibility` is raised. That's exactly its\n * reason to exist: \"text on me must stay readable.\" It adds density locally — denser over light\n * and busy backdrops, more transparent over an even dark one.\n *\n * A dedicated thick material (thickness 52, ior 1.58) used to sit here and was removed: medium\n * absorption grows with thickness, and the panel picked up a black fringe around its perimeter —\n * a sooty plate instead of glass. Don't turn thickness into a legibility knob; that's what\n * `legibility` is for.\n */\nexport const VIREGLASS_LYRICS_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n legibility: 0.95,\n};\n\n/**\n * Glass for controls — buttons, tiles, anything that gets pressed.\n *\n * THICK AND CLEAR, not the baseline: wider bevel, thickness up by half, higher index of\n * refraction and almost no roughness. Baseline glass is a lens over a calm backdrop; a control has\n * to read as an object you can pick up, and that's not done by a fill but by volume: a wide bevel\n * gives the rim something to catch, and thickness gives it depth.\n *\n * Thickness is set by BUILDUP AT THE RIM: on the reference control the stripe image under the\n * element bulges there by a factor of 1.85; ours came out at 1.36 at 30. Saturation sets in around\n * 44, and any extra thickness past that only adds absorption — hence 44, not more.\n *\n * It also drags `tintStrength` (= `absorption(thickness)`) along with it, and on the path WITHOUT\n * a native lens that sets body density: there the element is denser by 2.4 percentage points. On\n * the web the surface has no body at all; the effect only shows on Android below 13.\n *\n * `presence` is left at none: the medium's own lift already separates the body from a uniform\n * backdrop as far as the reference does (docs/dom.md), and the rim carries the silhouette.\n *\n * IMPORTANT about size. The bevel is specified by the medium in dp and doesn't depend on the\n * element's size, but the geometry clamps it to half the smaller half-size (`MAX_BEVEL_FRACTION`).\n * On a 52 dp button that's 13 instead of 16 — a small element made of this glass ends up being\n * bevel all the way through. That's by design: a small piece of thick glass is supposed to look\n * like a lens, not a slab.\n */\nexport const VIREGLASS_CONTROL_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL_V5,\n ior: 1.69,\n thickness: 44,\n bevel: 8,\n roughness: 0.035,\n presence: 0,\n};\n\nexport const VIREGLASS_MATERIAL = VIREGLASS_MATERIAL_V5;\n\n/**\n * An element that CARRIES app ink (an icon, a line of text, cover art) has to keep it legible —\n * that's the reason `legibility` exists. An element with no ink has nothing to separate lightness\n * from, so the requirement is turned off for it: the model just promises it plain transparent\n * glass.\n *\n * The rule lives here, not with the consumer: otherwise the same icon button would get different\n * legibility on the web and on Android.\n */\nexport function materialForInk(material: VireGlassMaterial, carriesInk: boolean): VireGlassMaterial {\n // For the transparent variant, legibility is held by the dimming layer, not the body. Raising\n // its requirement would just turn it into ordinary glass, and the variants don't mix (219 §Clear).\n if (material.dimming > 0) return material;\n return { ...material, legibility: carriesInk ? VIREGLASS_LYRICS_MATERIAL.legibility : 0 };\n}\n\n/**\n * The transparent material variant (Clear). It has no adaptation — the glass stays consistently\n * more transparent, content beneath it shows through almost as-is, and legibility of the ink is\n * held by the dimming layer instead. Fit only where the reference's three conditions hold: the\n * element sits over media, the content can tolerate dimming, and the ink over it is large and\n * bright.\n */\nexport const VIREGLASS_CLEAR_MATERIAL: VireGlassMaterial = {\n ...VIREGLASS_MATERIAL,\n legibility: 0,\n presence: 0,\n // Apple's own numbers: 0.35 in the HIG Materials text, 0.3 in its own sample code. We take the\n // lower one — it comes from working code, not from prose, and Clear has to stay a window.\n dimming: 0.3,\n};\n\n/**\n * ACTIVE STATE as a state of the MEDIUM, not a highlight drawn over it.\n *\n * An active element is denser, clearer glass: higher index of refraction, thicker body, wider\n * bevel, less roughness. A bright rim, a strong highlight and greater presence all follow from\n * these causes on their own — assembling them separately would produce a state that doesn't occur\n * in real glass.\n *\n * `environment` is deliberately left untouched here. It sets how much the body is tinted by\n * what's beneath it, and at full strength an active button over cover art turned into a colored\n * blob: the state read as \"smudged\" rather than \"selected.\" A state indicator must not depend on\n * the backdrop — otherwise any image sliding underneath the element would fake it.\n */\nexport function activeMaterial(material: VireGlassMaterial, on: number): VireGlassMaterial {\n const k = Math.min(Math.max(on, 0), 1);\n return {\n ...material,\n ior: material.ior + 0.35 * k,\n thickness: material.thickness * (1 + 0.9 * k),\n bevel: material.bevel * (1 + 1.8 * k),\n roughness: material.roughness * (1 - 0.75 * k),\n presence: material.presence + 0.12 * k,\n };\n}\n\nexport function resolveMaterial(patch: Partial<VireGlassMaterial> = {}): VireGlassMaterial {\n const m = { ...VIREGLASS_MATERIAL, ...patch };\n const out = { ...m };\n for (const key of Object.keys(MATERIAL_RANGES) as VireGlassNumericKey[]) {\n const [lo, hi] = MATERIAL_RANGES[key];\n out[key] = clamp(out[key], lo, hi);\n }\n return out;\n}\n\n/** Causes → effects. All of the transition's physics lives in `optics.ts`. */\nexport function resolveOptics(patch: Partial<VireGlassMaterial> = {}): VireGlassOptics {\n const m = resolveMaterial(patch);\n return {\n blur: blurFrom(m.roughness),\n refraction: refractionStrength(m.ior),\n refractionScale: refractionScaleFrom(m.ior, m.thickness),\n bevelDp: m.bevel,\n gatherRadiusDp: gatherRadiusFrom(m.bevel),\n fresnel: fresnelStrength(m.ior),\n fresnelPower: FRESNEL_EXPONENT,\n specular: specularStrength(m.ior, m.roughness),\n specularPower: specularPowerFrom(m.roughness),\n dispersion: dispersionFrom(m.ior),\n tint: mediumTint(m.ior),\n tintStrength: absorption(m.thickness),\n edgeDensity: edgeDensityFrom(m.thickness, m.bevel),\n environment: m.environment,\n legibility: m.legibility,\n dimming: m.dimming,\n ink: m.ink,\n presence: m.presence,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: bodyDensityFrom(m.thickness),\n edgeLight: edgeLightFrom(m.ior),\n film: m.film,\n iridescence: iridescenceFrom(m.ior, m.film),\n diffraction: diffractionFrom(m.ior),\n colorPickup: colorPickupFrom(m.ior),\n ior: m.ior,\n thicknessDp: m.thickness,\n iorSpread: iorSpreadFrom(m.ior),\n };\n}\n\n/**\n * Frozen snapshots of the EFFECTS from the previous model. Kept as reference points until v4\n * settles: they can't be converted to causes — some of the values are internally inconsistent\n * (exactly why the move was made in the first place), and any \"equivalent\" material would be a\n * lie.\n */\nexport const LEGACY_OPTICS = {\n 'v3-manual': {\n blur: 4.32,\n refraction: 0.49,\n refractionScale: 1.05,\n bevelDp: 12.6,\n gatherRadiusDp: 40,\n fresnel: 0.77,\n fresnelPower: 2.86,\n specular: 0.3,\n specularPower: 74.58,\n dispersion: 0.54,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.35,\n edgeDensity: 1.5,\n environment: 0.27,\n legibility: 0.55,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n 'v2': {\n blur: 5,\n refraction: 0.95,\n refractionScale: 1.34,\n bevelDp: 14,\n gatherRadiusDp: 40,\n fresnel: 0.72,\n fresnelPower: 2.4,\n specular: 0.38,\n specularPower: 46,\n dispersion: 0.3,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.1,\n edgeDensity: 3.63,\n environment: 0,\n legibility: 0,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n 'v1': {\n blur: 12,\n refraction: 0.55,\n refractionScale: 1.14,\n bevelDp: 10,\n gatherRadiusDp: 40,\n fresnel: 0.5,\n fresnelPower: 3.2,\n specular: 0.42,\n specularPower: 58,\n dispersion: 0.22,\n tint: { r: 0.4, g: 0.4, b: 0.44 },\n tintStrength: 0.16,\n edgeDensity: 3.63,\n environment: 0,\n legibility: 0,\n dimming: 0,\n ink: 1,\n presence: 0,\n adaptRadius: ADAPT_RADIUS,\n bodyDensity: 0.14,\n edgeLight: 0.35,\n film: 0,\n iridescence: 0,\n diffraction: 0,\n colorPickup: 0,\n ior: 1.5,\n thicknessDp: 16,\n iorSpread: 0,\n },\n} as const satisfies Record<string, VireGlassOptics>;\n\nexport type LegacyOpticsName = keyof typeof LEGACY_OPTICS;\nexport const LEGACY_NAMES = Object.keys(LEGACY_OPTICS) as LegacyOpticsName[];\n\n/** Material presets: points in the space of CAUSES, not a set of ready-made effects. */\nexport const MATERIAL_PRESETS = {\n water: VIREGLASS_MATERIAL_V4,\n glass: { ...VIREGLASS_MATERIAL_V4, ior: 1.45, thickness: 25, bevel: 12.6, roughness: 0.17 },\n crystal: { ...VIREGLASS_MATERIAL_V4, ior: 1.7, thickness: 30, bevel: 16, roughness: 0.02 },\n frosted: { ...VIREGLASS_MATERIAL_V4, roughness: 0.55 },\n thick: { ...VIREGLASS_MATERIAL_V4, thickness: 48, bevel: 22 },\n thin: { ...VIREGLASS_MATERIAL_V4, thickness: 4, bevel: 3 },\n iridescent: { ...VIREGLASS_MATERIAL_V4, ior: 1.5, thickness: 8, bevel: 6, film: 620 },\n} as const satisfies Record<string, VireGlassMaterial>;\n\nexport type MaterialPresetName = keyof typeof MATERIAL_PRESETS;\nexport const PRESET_NAMES = Object.keys(MATERIAL_PRESETS) as MaterialPresetName[];\n\nexport const EFFECTS = [\n 'backdrop',\n 'blur',\n 'refraction',\n 'fresnel',\n 'bevel',\n 'specular',\n 'dispersion',\n 'tint',\n 'environment',\n 'legibility',\n 'interference',\n 'diffraction',\n] as const;\n\nexport type VireGlassEffect = (typeof EFFECTS)[number];\nexport type VireGlassToggles = Record<VireGlassEffect, boolean>;\n\nexport const ALL_EFFECTS_ON: VireGlassToggles = EFFECTS.reduce(\n (acc, e) => ({ ...acc, [e]: true }),\n {} as VireGlassToggles,\n);\n\n/**\n * A toggle zeroes out an EFFECT, it isn't a branch in the shader: the ON/OFF comparison runs on\n * one shader variant, otherwise two different programs would be getting compared. It operates on\n * optics, not on the material: a cause can't be zeroed out — it drags half a dozen effects along\n * with it. `backdrop` isn't handled by a toggle here: it decides whether to mount the BlurView at\n * all.\n */\nexport function applyToggles(\n optics: VireGlassOptics,\n toggles: Partial<VireGlassToggles> = {},\n): VireGlassOptics {\n const on = { ...ALL_EFFECTS_ON, ...toggles };\n const o = { ...optics, tint: { ...optics.tint } };\n if (!on.blur) o.blur = 0;\n if (!on.refraction) {\n o.refraction = 0;\n o.refractionScale = 1;\n o.ior = 1;\n }\n if (!on.fresnel) o.fresnel = 0;\n if (!on.bevel) o.bevelDp = 1;\n if (!on.specular) o.specular = 0;\n if (!on.dispersion) {\n o.dispersion = 0;\n o.iorSpread = 0;\n }\n if (!on.tint) o.tintStrength = 0;\n if (!on.environment) o.environment = 0;\n if (!on.legibility) {\n o.legibility = 0;\n // The dimming layer is the same answer to the legibility requirement, just for the\n // transparent variant.\n o.dimming = 0;\n }\n if (!on.interference) o.iridescence = 0;\n if (!on.diffraction) o.diffraction = 0;\n return o;\n}\n\n/** Order = the `u_debug` value in both shaders. Bench-only. */\nexport const DEBUG_MODES = [\n 'normal',\n 'sdf',\n 'mask',\n 'edge',\n 'fresnel',\n 'refraction',\n 'backdrop',\n 'specular',\n 'dispersion',\n 'normals',\n 'spectral',\n 'adapt',\n 'probe',\n] as const;\n\nexport type VireGlassDebugMode = (typeof DEBUG_MODES)[number];\n\nexport function debugIndex(mode: VireGlassDebugMode): number {\n return DEBUG_MODES.indexOf(mode);\n}\n","// Backdrop sample for the DOM renderer — the web-DOM counterpart to the WebGL downsample probe\n// (`web/probe.ts`) and the native capture on Android. The web canvas can read the pixels it just\n// drew; a page CANNOT read what's actually rendered behind an arbitrary element — that boundary\n// is the whole reason `backdrop-filter` exists as a browser primitive rather than a pixel API. So\n// this probes DECLARED STYLES instead: walk the stacking order under a grid of sample points and\n// read `background-color` (falling back to `color`) rather than any real pixel.\nimport type { BackdropSample } from '../adaptation';\n\n/** A modest grid: this runs on scroll, not per frame. `elementsFromPoint` walks the whole\n * stacking context at every sample point — a fine grid shows up in a profiler, a coarse one is\n * still plenty to tell \"flat\" from \"busy\" for the adaptation decision. */\nconst GRID_COLS = 5;\nconst GRID_ROWS = 5;\n\nexport type RgbColor = { r: number; g: number; b: number; a: number };\n\n/**\n * Parses `rgb()`/`rgba()` exactly as `getComputedStyle` emits them — every engine normalizes a\n * resolved color to one of these two forms, so there's nothing here worth a dependency for.\n * Returns `null` for anything else (a keyword that didn't resolve, a malformed value).\n */\nexport function parseColor(value: string): RgbColor | null {\n const match = /rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/i.exec(value);\n if (!match) return null;\n const r = Number(match[1]);\n const g = Number(match[2]);\n const b = Number(match[3]);\n const a = match[4] === undefined ? 1 : Number(match[4]);\n if (!Number.isFinite(r) || !Number.isFinite(g) || !Number.isFinite(b) || !Number.isFinite(a)) return null;\n return { r, g, b, a };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Same statistic the WebGL probe computes on its downsample grid (`web/probe.ts`, `rectStats`):\n * mean luma, twice the mean deviation for `busy`, 10th/90th percentile for `lo`/`hi`. A different\n * formula here would mean the ink-polarity decision quietly drifts between renderers on the same\n * page. `samples` are 0..255 per channel, matching what `parseColor` returns.\n */\nexport function statsFromSamples(samples: readonly (Omit<RgbColor, 'a'> & { a?: number })[]): BackdropSample {\n const n = samples.length;\n if (n === 0) return { luma: 0.5, busy: 0, lo: 0.5, hi: 0.5, r: 0.5, g: 0.5, b: 0.5 };\n\n const lumas: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n for (const s of samples) {\n const r = s.r / 255;\n const g = s.g / 255;\n const b = s.b / 255;\n lumas.push(luma(r, g, b));\n sr += r;\n sg += g;\n sb += b;\n }\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = Math.min((busy / n) * 2, 1);\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n return {\n luma: mean,\n busy,\n lo: percentile(0.1),\n hi: percentile(0.9),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\n/**\n * Composites a stack of backgrounds front to back, the way the compositor does.\n *\n * Taking the first layer with any alpha at all instead is wrong by a lot, not a little: a list row\n * tinted `rgba(255,255,255,0.028)` over a near-black page reads as pure WHITE, and the glass then\n * adapts to a backdrop that does not exist. That is most real interfaces.\n */\nexport function compositeLayers(layers: readonly RgbColor[]): RgbColor | null {\n let r = 0;\n let g = 0;\n let b = 0;\n let a = 0;\n for (const layer of layers) {\n const share = layer.a * (1 - a);\n if (share <= 0) continue;\n r += layer.r * share;\n g += layer.g * share;\n b += layer.b * share;\n a += share;\n if (a >= 0.999) break;\n }\n if (a <= 0.001) return null;\n // Normalised by coverage: what reached the eye, as an opaque colour. A stack that never became\n // opaque sits over the page's own background, which is the caller's floor layer.\n return { r: r / a, g: g / a, b: b / a, a };\n}\n\n/** Walks the stack at one point, skipping the glass element itself (it would otherwise probe its\n * own background) and its descendants. */\nfunction sampleColorAt(el: HTMLElement, x: number, y: number): RgbColor | null {\n const stack = document.elementsFromPoint(x, y);\n const behind = stack.filter((node) => node !== el && !el.contains(node));\n const layers: RgbColor[] = [];\n for (const node of behind) {\n const bg = parseColor(getComputedStyle(node).backgroundColor);\n // `rgba(0, 0, 0, 0)` is what \"transparent\" resolves to almost everywhere: it contributes\n // nothing and must not shadow a real colour further down.\n if (bg && bg.a > 0.001) layers.push(bg);\n }\n const composited = compositeLayers(layers);\n if (composited) return composited;\n return canvasColor(el);\n}\n\n/**\n * The page's own background — the floor everything else is composited over.\n *\n * Reached whenever nothing in the stack is opaque, which is not an edge case: CSS propagates the\n * body's background to the CANVAS, so `getComputedStyle` reports `<html>` and often `<body>` as\n * transparent on a perfectly ordinary white page. Any element past the end of the body's box —\n * a widget pinned to a corner, say — sees a stack of nothing.\n *\n * This used to fall back to the topmost element's `color`, which is its TEXT colour: a white page\n * with black text read as black, and the material dressed itself for a dark backdrop over a light\n * one. The propagation rule says where to look instead — the root element's background, then the\n * body's, then the user agent's white.\n */\nfunction canvasColor(el: HTMLElement): RgbColor | null {\n const doc = el.ownerDocument;\n for (const node of [doc.documentElement, doc.body]) {\n if (!node) continue;\n const bg = parseColor(getComputedStyle(node).backgroundColor);\n if (bg && bg.a > 0.001) return bg.a >= 0.999 ? bg : compositeLayers([bg, WHITE]);\n }\n return WHITE;\n}\n\n/** What a browser paints the canvas when nobody says otherwise. */\nconst WHITE: RgbColor = { r: 255, g: 255, b: 255, a: 1 };\n\nexport type ProbeOptions = {\n /** Grid density override — wider for a hero element, narrower for a tight control. */\n cols?: number;\n rows?: number;\n};\n\n/**\n * Backdrop sample for the glass element from its live surroundings, blind to images/video/canvas\n * by construction (the caller overrides with its own sample there — cover art already knows its\n * own accent; see `attachGlass`'s `sample` option).\n */\nexport function probeBackdrop(el: HTMLElement, opts: ProbeOptions = {}): BackdropSample {\n const cols = opts.cols ?? GRID_COLS;\n const rows = opts.rows ?? GRID_ROWS;\n const rect = el.getBoundingClientRect();\n // A hidden or not-yet-laid-out element has no backdrop to speak of. Sampling it anyway collapses\n // the whole grid onto one corner point and reports whatever unrelated thing sits there as a\n // confident, perfectly flat reading.\n if (rect.width <= 0 || rect.height <= 0) return statsFromSamples([]);\n const samples: RgbColor[] = [];\n for (let j = 0; j < rows; j += 1) {\n const y = rect.top + ((j + 0.5) / rows) * rect.height;\n for (let i = 0; i < cols; i += 1) {\n const x = rect.left + ((i + 0.5) / cols) * rect.width;\n const color = sampleColorAt(el, x, y);\n if (color) samples.push(color);\n }\n }\n return statsFromSamples(samples);\n}\n","// Feature detection BY MEASUREMENT, never by sniffing the user agent — the agent string is the\n// first thing to lie about this after an engine update.\n//\n// Firefox does not support `url()` inside `backdrop-filter` and has closed the request as not\n// planned (bug 1578503). Safari doesn't support `backdrop-filter` with `url()` yet either, though\n// WebKit has patches in flight. Both can change without notice, so this asks the engine directly.\n\nlet backdropFilterSupport: boolean | null = null;\nlet svgBackdropFilterSupport: boolean | null = null;\n\n// `CSS.supports`, not a detached element read back through `getComputedStyle`: Chromium resolves\n// no style at all for an element outside the document, so that probe answered \"unsupported\" in the\n// very engine where the displacement demonstrably works.\n//\n// This answers that the engine PARSES the value. An engine could in principle parse `url()` and\n// render nothing; a host that meets one can override the decision through `attachGlass` instead of\n// being stuck with a wrong automatic answer.\nfunction probeProperty(property: string, value: string): boolean {\n if (typeof CSS === 'undefined' || typeof CSS.supports !== 'function') return false;\n return CSS.supports(property, value);\n}\n\n/** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */\nexport function supportsBackdropFilter(): boolean {\n if (backdropFilterSupport === null) {\n backdropFilterSupport =\n probeProperty('backdrop-filter', 'blur(1px)') || probeProperty('-webkit-backdrop-filter', 'blur(1px)');\n }\n return backdropFilterSupport;\n}\n\n/** `url(#filter)` specifically — the SVG displacement path's requirement. Checked separately from\n * `supportsBackdropFilter()`: an engine can support plain blur without supporting a filter\n * reference, which is exactly the Firefox case. */\nexport function supportsSvgBackdropFilter(): boolean {\n if (svgBackdropFilterSupport === null) {\n svgBackdropFilterSupport = probeProperty('backdrop-filter', 'url(#vireglass-support-probe)');\n }\n return svgBackdropFilterSupport;\n}\n\n/** Test-only: the two probes above cache after their first call, and a suite that stubs the DOM\n * differently per test needs a way to invalidate that. */\nexport function resetSupportCache(): void {\n backdropFilterSupport = null;\n svgBackdropFilterSupport = null;\n}\n","// The colour that bleeds into a shadow (docs/reference.md §4, 219 @8:22): \"the light reflects,\n// scatters, and bleeds into the shadow as well — much like it would in the physical world.\"\n//\n// JS twin of the lens surface's `vgShadowTint`. A shadow that is simply black leaves an element\n// over colourful content hanging above a grey blob, which reads as pasted on rather than resting\n// there.\n\nconst LUMA: readonly [number, number, number] = [0.2126, 0.7152, 0.0722];\n\nconst luma = (c: readonly [number, number, number]) => c[0] * LUMA[0] + c[1] * LUMA[1] + c[2] * LUMA[2];\n\n/**\n * Hue without lightness, scaled by how much light there is to bleed. Lightness is subtracted out\n * of the hue on purpose: left in, the shadow PALES and loses its depth instead of warming up. And\n * over a nearly black backdrop there is nothing to spill, so the result goes to zero on its own.\n */\nexport function shadowTint(ambient: readonly [number, number, number]): [number, number, number] {\n const peak = Math.max(ambient[0], ambient[1], ambient[2], 0.001);\n const hue: [number, number, number] = [ambient[0] / peak, ambient[1] / peak, ambient[2] / peak];\n const grey = luma(hue);\n const available = luma(ambient);\n return [(hue[0] - grey) * available, (hue[1] - grey) * available, (hue[2] - grey) * available];\n}\n","// Adaptive shadow (docs/reference.md §4). The law itself — density keyed to what is behind the\n// element, size keyed to its own half-size — lives in `../geometry` as `shadowOpacityFrom` and\n// `shadowReachDp`; this turns those into a CSS `box-shadow`.\nimport { ambientFrom, type BackdropSample } from '../adaptation';\nimport { shadowOpacity, shadowOpacityFrom, shadowReachDp, type VireGlassGeometry } from '../geometry';\nimport { SHADOW, SHADOW_GAP } from '../law';\nimport { shadowTint } from '../shadow-tint';\n\n/**\n * The model carries shadow density as a multiplier the shader applies to its own per-pixel term,\n * so the DOM path has to convert it to one flat alpha. That conversion is not a taste constant:\n * §4 records both ends measured off reference frames 711–723 — 19.9% over text, 4.0% over a flat\n * light backdrop — and `shadowOpacity` spans exactly those two cases. Two measured points, one line.\n */\nconst FLAT_DENSITY = shadowOpacity(0);\nconst BUSY_DENSITY = shadowOpacity(1);\n\nexport function shadowAlphaFrom(sample: { busy: number }): number {\n const t = (shadowOpacityFrom(sample) - FLAT_DENSITY) / (BUSY_DENSITY - FLAT_DENSITY);\n const alpha = SHADOW.alphaFlat + t * (SHADOW.alphaBusy - SHADOW.alphaFlat);\n return Math.min(Math.max(alpha, 0), 1);\n}\n\nconst to255 = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * 255);\n\n/**\n * Symmetric and blur-only: §4 gives a density and a size, never a direction. The reference calls\n * the shadow \"soft, small\" — blur carries both.\n *\n * The colour is NOT black. \"The light reflects, scatters, and bleeds into the shadow as well —\n * much like it would in the physical world\" (219 @8:22). A black shadow leaves an element over\n * colourful content hanging above a grey blob, which is the one thing that reads as pasted on.\n */\n/**\n * `appear` is the same gate the surface shader puts on the shadow (`u_shadow * u_appear`, line\n * 176). An element that is not there yet does not cast: a shadow under nothing is the one part of\n * materialising that gives the trick away.\n */\nexport function boxShadowCss(\n geometry: VireGlassGeometry,\n sample: BackdropSample | { busy: number },\n appear = 1,\n): string {\n const reach = shadowReachDp(geometry);\n const present = appear < 0 ? 0 : appear > 1 ? 1 : appear;\n const alpha = shadowAlphaFrom(sample) * present;\n const ambient = 'luma' in sample ? ambientFrom(sample as BackdropSample) : null;\n if (!ambient) return `0 0 ${reach.toFixed(1)}px rgba(0, 0, 0, ${alpha.toFixed(3)})`;\n\n const [r, g, b] = shadowTint(ambient);\n const spill = SHADOW_GAP.tint;\n return (\n `0 0 ${reach.toFixed(1)}px ` +\n `rgba(${to255(r * spill)}, ${to255(g * spill)}, ${to255(b * spill)}, ${alpha.toFixed(3)})`\n );\n}\n","// The glass BODY (docs/reference.md §3): how dense the medium has to be over this particular\n// backdrop, and which way it tints.\n//\n// The law is the lens shader's, ported to one value per element instead of one per\n// pixel — the DOM path has a single backdrop sample, not a plane. Constants keep their names from\n// the shader so the two stay comparable.\nimport { BODY, MEDIUM } from '../law';\nimport type { VireGlassOptics } from '../material';\n\nconst {\n capLoose: BODY_CAP_LOOSE,\n capTight: BODY_CAP_TIGHT,\n tintDark: TINT_DARK,\n tintLight: TINT_LIGHT,\n groundSpan: GROUND_SPAN,\n busyEdge: BUSY_EDGE,\n inkBusyFrom: INK_BUSY_FROM,\n inkBusyTo: INK_BUSY_TO,\n inkPoleTo: INK_POLE_TO,\n presenceDemand: PRESENCE_DEMAND,\n maxDemand: MAX_DEMAND,\n} = BODY;\n\nconst clamp = (v: number, lo: number, hi: number) => (v < lo ? lo : v > hi ? hi : v);\nconst mix = (a: number, b: number, t: number) => a + (b - a) * t;\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n const t = clamp((x - edge0) / (edge1 - edge0), 0, 1);\n return t * t * (3 - 2 * t);\n}\n\n/** Only the two figures the law reads — the same narrowing `shadowOpacityFrom` uses. */\nexport type BodyBackdrop = { luma: number; busy: number };\n\nexport type GlassBody = {\n /** How much medium stands between the backdrop and the eye, 0…1. */\n density: number;\n /** Lightness the body tints toward. */\n tintLuma: number;\n /** The part of the density the ink's legibility asked for, and the pole it asked toward. */\n need: number;\n pole: number;\n};\n\n/**\n * The body is lighter than its surroundings whatever the glyph on it is: glass concentrates light\n * (M 2:29), and the reference keeps a lighter body under a white glyph over sky as much as over\n * dark. It goes to the ink's own pole only where the ink's legibility is what holds the density —\n * or a system setting has raised it past anything a presence floor asks for.\n */\nfunction tintFor(density: number, need: number, pole: number): number {\n const asked = Math.max(clamp(need / Math.max(density, 1e-4), 0, 1), smoothstep(PRESENCE_DEMAND, INK_POLE_TO, density));\n return mix(TINT_LIGHT, pole, asked);\n}\n\n/**\n * `ink` is POLARITY, 1 light and 0 dark, matching the shader's uniform. The requirements are\n * evaluated at both ends and blended by it — computing at the current polarity alone makes the\n * glass dip toward the middle while a recolor is in flight.\n */\nexport function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody {\n const strict = clamp(optics.legibility * 2, 0, 1);\n const capLight = mix(BODY_CAP_LOOSE, BODY_CAP_TIGHT, strict);\n const floorDark = 1 - capLight;\n const pol = clamp(ink, 0, 1);\n // With no ink on it, the model promises transparent glass: the requirement fades out with\n // legibility rather than standing at a floor.\n const demand = clamp(optics.legibility * 4, 0, 1);\n\n const mean = clamp(sample.luma, 0, 1);\n const busy = Math.max(sample.busy, 0);\n\n const pole = mix(TINT_LIGHT, TINT_DARK, pol);\n\n // How much medium it takes to push the lightness under the ink past its threshold, measured\n // from whichever edge of the backdrop's spread is closer to the ink — a light ink drowns in a\n // light patch right beneath it, and the average knows nothing about that patch.\n const edge = busy * BUSY_EDGE;\n const inkHi = Math.min(mean + edge, 1);\n const inkLo = Math.max(mean - edge, 0);\n const needForLight = inkHi > capLight ? clamp((inkHi - capLight) / Math.max(inkHi - TINT_DARK, 1e-4), 0, MAX_DEMAND) : 0;\n const needForDark = inkLo < floorDark ? clamp((floorDark - inkLo) / Math.max(TINT_LIGHT - inkLo, 1e-4), 0, MAX_DEMAND) : 0;\n // Over a flat backdrop the ink asks for nothing: polarity flips before it drowns. It is spread\n // under the ink that the body has to answer.\n const structured = smoothstep(INK_BUSY_FROM, INK_BUSY_TO, busy);\n const needForInk = mix(needForDark, needForLight, pol) * demand * structured;\n\n // Fine texture the body has to stop being a window for, the same way roughness does it.\n const ground = busy * optics.legibility * GROUND_SPAN;\n\n const density = Math.max(Math.max(optics.bodyDensity, ground), needForInk);\n return { density, tintLuma: tintFor(density, needForInk, pole), need: needForInk, pole };\n}\n\n/**\n * PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly\n * disappears — right for a piece of background, wrong for a control. It is a MINIMUM on the\n * density, toward light whatever the ink, and it does not read the backdrop: the lift it gives is\n * `presence` times the room left under the light pole, so it fades out as the room does and has no\n * step anywhere on the scale.\n */\nexport function withPresence(body: GlassBody, optics: VireGlassOptics, _sample?: BodyBackdrop): GlassBody {\n if (optics.presence <= 0) return body;\n const density = Math.max(body.density, Math.min(optics.presence / TINT_LIGHT, PRESENCE_DEMAND));\n return { ...body, density, tintLuma: tintFor(density, body.need, body.pole) };\n}\n\nexport type BodyLayer = {\n /** Straight (not premultiplied) colour, 0…1 per channel. */\n r: number;\n g: number;\n b: number;\n alpha: number;\n};\n\n/** The lens's `vgHue`: colour without lightness, and white below the lightness it has none at. */\nfunction hueOf(c: readonly [number, number, number]): [number, number, number] {\n const l = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];\n if (l < 0.02) return [1, 1, 1];\n return [clamp(c[0] / l, 0, 2), clamp(c[1] / l, 0, 2), clamp(c[2] / l, 0, 2)];\n}\n\n/**\n * The body as ONE translucent layer over the backdrop, which is the form the DOM can draw it in.\n *\n * The lens does not paint a body, it transforms what it refracts, in a chain that stays affine in\n * the backdrop: a mix toward the tint at `density`, the matte lift, the medium's pull toward its\n * own lightness, the ambient spill and the concentration of light (§3, `MEDIUM`). Composing it\n * gives `out = A * backdrop + B` per channel, and a layer of colour `B / (1 - A)` at opacity\n * `1 - A` over the backdrop is that, except where the colour clamps to 0..1: over a saturated dark\n * backdrop (dark blue) a channel is off by up to 0.024.\n *\n * This is what lifts the body over a dark backdrop. The tint alone, under light ink, is darker\n * than the dark it sits on; the medium's pull, the matte lift and the concentration are what make\n * it read lighter, as in the reference (M 2:29, A 2:17).\n *\n * `appear` multiplies the layers exactly where the lens's `u_appear` does, so `optics` is the\n * element's optics BEFORE `applyAppear`: scaling both would count it twice.\n */\nexport function bodyLayer(\n optics: VireGlassOptics,\n sample: BodyBackdrop,\n ink: number,\n ambient: readonly [number, number, number],\n appear = 1,\n): BodyLayer {\n const a = clamp(appear, 0, 1);\n const body = withPresence(resolveBody(optics, sample, ink), optics, sample);\n const hue = hueOf(ambient);\n const pickup = clamp(optics.colorPickup, 0, 1);\n const density = clamp(body.density * a, 0, 1);\n const matte = optics.legibility * MEDIUM.matteLift * a;\n const pull = MEDIUM.pull * a;\n const spill = optics.edgeLight * MEDIUM.ambientSpill * a;\n const lift = MEDIUM.concentrate * a;\n\n const alpha = 1 - (1 - lift) * (1 - pull) * (1 - density);\n const channel = (i: 0 | 1 | 2): number => {\n const tintHue = mix(1, hue[i], pickup);\n const added =\n (1 - pull) * (density * tintHue * body.tintLuma + matte * tintHue) +\n pull * hue[i] * MEDIUM.luma +\n ambient[i] * spill;\n return alpha > 1e-6 ? clamp(((1 - lift) * added + lift) / alpha, 0, 1) : 0;\n };\n return { r: channel(0), g: channel(1), b: channel(2), alpha };\n}\n","// System accessibility settings change the material's LAYERS, they don't override it (reference\n// 219 @18:15). So what's adjusted here are EFFECTS, like with toggles: the shader knows nothing\n// about accessibility.\nimport { ACCESSIBILITY, BODY } from './law';\nimport type { VireGlassOptics } from './material';\n\nexport type VireGlassAccessibility = {\n /** The glass becomes more frosted and hides content beneath it more strongly (219 @18:22). */\n reduceTransparency: boolean;\n /** The element moves nearly to black or white and picks up a contrasting border (219 @18:29). */\n increaseContrast: boolean;\n /** The material's springiness is turned off, effects are quieter (219 @18:35). */\n reduceMotion: boolean;\n};\n\nexport const NO_ACCESSIBILITY: VireGlassAccessibility = {\n reduceTransparency: false,\n increaseContrast: false,\n reduceMotion: false,\n};\n\n/** A system setting acts on the whole glass and outranks the material preset (219 @18:45): even\n * a transparent preset moves to the edge of the scale under contrast — the user needs contrast\n * more than they need aesthetics. */\nexport function applyAccessibility(\n optics: VireGlassOptics,\n mods: VireGlassAccessibility = NO_ACCESSIBILITY,\n): VireGlassOptics {\n if (!mods.reduceTransparency && !mods.increaseContrast) return optics;\n const out = { ...optics };\n if (mods.reduceTransparency) {\n out.blur = Math.max(out.blur, ACCESSIBILITY.frostMinDp);\n out.bodyDensity = Math.max(out.bodyDensity, ACCESSIBILITY.obscureMin);\n }\n if (mods.increaseContrast) {\n out.bodyDensity = Math.max(out.bodyDensity, ACCESSIBILITY.contrastDensity);\n out.presence = Math.max(out.presence, ACCESSIBILITY.contrastPresence);\n out.legibility = 1;\n }\n return out;\n}\n\n/**\n * The lightness of the contrasting border §9 asks for, for a body sitting at `tintLuma`.\n *\n * It is the one place the rim stops being an environmental thing. Everywhere else the hairline\n * takes its colour from what is around the element — \"over a yellow flower the rim is yellow\"\n * (§2) — and a hairline the colour of its surroundings is not a border that contrasts with the\n * element it outlines. Under this setting it is measured from the body instead.\n */\nexport function contrastRimLuma(tintLuma: number): number {\n const light = tintLuma < 0.5;\n return light\n ? Math.min(tintLuma + ACCESSIBILITY.contrastRim, BODY.tintLight)\n : Math.max(tintLuma - ACCESSIBILITY.contrastRim, BODY.tintDark);\n}\n\n/**\n * Whether the material may deform. §9: reduced motion \"disables any elastic properties for the\n * material\" — the spring and the ripple. It does NOT disable the response: the press that lights\n * an element from within (§5) is light, not motion, and survives at reduced intensity.\n */\nexport function elasticAllowed(mods: VireGlassAccessibility = NO_ACCESSIBILITY): boolean {\n return !mods.reduceMotion;\n}\n","// System accessibility on the web (docs/reference.md §9). The three settings the reference names\n// all have media queries, so nothing here has to be asked of the host: the browser already knows.\n//\n// `reduceMotion` leaves optics alone — it is about motion, and motion is computed by the\n// deformation model, which takes it as `elastic: false`. The element keeps answering a finger; it\n// stops springing and rippling.\nimport { NO_ACCESSIBILITY, type VireGlassAccessibility } from '../accessibility';\n\nconst QUERIES = {\n reduceTransparency: '(prefers-reduced-transparency: reduce)',\n increaseContrast: '(prefers-contrast: more)',\n reduceMotion: '(prefers-reduced-motion: reduce)',\n} as const;\n\nfunction matches(query: string): boolean {\n if (typeof matchMedia !== 'function') return false;\n try {\n return matchMedia(query).matches;\n } catch {\n // An engine that does not know a query throws rather than answering false. Not knowing it is\n // an answer of \"not set\", not a reason to fail.\n return false;\n }\n}\n\nexport function systemAccessibility(): VireGlassAccessibility {\n if (typeof matchMedia !== 'function') return NO_ACCESSIBILITY;\n return {\n reduceTransparency: matches(QUERIES.reduceTransparency),\n increaseContrast: matches(QUERIES.increaseContrast),\n reduceMotion: matches(QUERIES.reduceMotion),\n };\n}\n\n/** Fires whenever any of the three changes. The material has to follow a setting turned on while\n * the page is open, not only one that was on when it loaded. */\nexport function watchAccessibility(onChange: (next: VireGlassAccessibility) => void): () => void {\n if (typeof matchMedia !== 'function') return () => {};\n const lists: MediaQueryList[] = [];\n const handler = () => onChange(systemAccessibility());\n for (const query of Object.values(QUERIES)) {\n try {\n const list = matchMedia(query);\n list.addEventListener('change', handler);\n lists.push(list);\n } catch {\n // Same as above: an unknown query simply has nothing to watch.\n }\n }\n return () => {\n for (const list of lists) list.removeEventListener('change', handler);\n };\n}\n","// User-facing glass transparency scale: iOS 26.1 gave a choice between two options (\"default clear\n// look\" or \"tinted look which increases opacity of the material\"), iOS 27 a continuous slider\n// \"ultra clear → fully tinted\", and apps get it without recompiling.\n//\n// It adjusts EFFECTS, not causes, and that's not a compromise. The cause \"medium density\" is\n// deliberately absent from the model: the glass has no color of its own, `bodyDensity` is derived\n// from absorption through the body and never exceeds 0.03, and the visible density is held by the\n// legibility requirement and scattering. A thickness scale would move a number that isn't visible\n// in the frame (measured by the `check:optics` gate).\nimport { SCALE } from './law';\nimport type { VireGlassOptics } from './material';\n\n/** The point on the scale where the material stays exactly as it is today. */\nexport const GLASS_SCALE_DEFAULT = SCALE.default;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * `scale` 0 is ultra clear, 1 is fully tinted. Toward the transparent end, the legibility\n * requirement and the dimming layer are relaxed (the user chose clarity); toward the tinted end,\n * body density grows.\n *\n * Accessibility settings apply AFTER the scale: they set floors, and the user's chosen clarity\n * does not override them (219 @18:45).\n */\nexport function applyGlassScale(optics: VireGlassOptics, scale: number): VireGlassOptics {\n const s = clamp01(scale);\n if (s === GLASS_SCALE_DEFAULT) return optics;\n if (s < GLASS_SCALE_DEFAULT) {\n const k = s / GLASS_SCALE_DEFAULT;\n return { ...optics, legibility: optics.legibility * k, dimming: optics.dimming * k };\n }\n const k = (s - GLASS_SCALE_DEFAULT) / (1 - GLASS_SCALE_DEFAULT);\n return { ...optics, bodyDensity: Math.max(optics.bodyDensity, SCALE.tintedDensity * k) };\n}\n","// Materialising in and out (docs/reference.md §1, 219 @2:55): \"Instead of fading, Liquid Glass\n// objects materialize in and out by gradually modulating the light bending and lensing, ensuring a\n// graceful transition that preserves the optical integrity of the material.\"\n//\n// So an element must not arrive by opacity. Fading it leaves a half-transparent picture OF glass;\n// modulating the lens leaves glass that is not yet bending much light. The difference is visible:\n// a faded element shows the backdrop through a veil, a materialising one shows it undistorted.\n//\n// JS twin of what `u_appear` multiplies in the lens: the lens strength itself, the frost, the\n// body, the dimming layer and the rim's light. Everything that makes the material present, and\n// nothing that makes it opaque.\nimport type { VireGlassOptics } from './material';\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * `t` of 0 is an element indistinguishable from the backdrop beneath it; 1 is the material at\n * full strength. Between them the glass bends progressively more light.\n */\nexport function applyAppear(optics: VireGlassOptics, t: number): VireGlassOptics {\n const a = clamp01(t);\n if (a === 1) return optics;\n return {\n ...optics,\n refraction: optics.refraction * a,\n blur: optics.blur * a,\n bodyDensity: optics.bodyDensity * a,\n dimming: optics.dimming * a,\n edgeLight: optics.edgeLight * a,\n // A floor on how far the element must stand out from its backdrop (§3). Left alone it holds\n // the element visible at t = 0, which is the opposite of what materialising means.\n presence: optics.presence * a,\n // The spectral trio is lensing too — §1's \"light bending and lensing\" is not only the\n // displacement. The fringe map and the per-channel split are drawn from these, and a filter\n // graph that still paints them is an element that is not there but is casting a rainbow.\n dispersion: optics.dispersion * a,\n iridescence: optics.iridescence * a,\n diffraction: optics.diffraction * a,\n tintStrength: optics.tintStrength * a,\n // Legibility is a REQUIREMENT, not an effect: an element still arriving has no ink on it yet,\n // and holding a demand it cannot meet would darken the body exactly while it should be\n // clearing. It fades with the rest.\n legibility: optics.legibility * a,\n };\n}\n","// Tinting (docs/reference.md §7, 219 @16:31): \"Selecting a color generates a range of tones that\n// are mapped to content brightness underneath the tinted element. It draws inspiration from how\n// colored glass works in reality: changing its hue, brightness and saturation depending on what's\n// behind without deviating too much from the intended color.\"\n//\n// So a tint is not a fill. @17:03 is explicit about what a fill costs: \"it is completely opaque\n// and breaks the visual character of Liquid Glass.\" The colour has to be a property of the medium,\n// and the content has to keep coming through it.\n//\n// JS twin of the accent block in the lens shader.\nimport type { VireGlassAccent } from './adapters';\nimport { ACCENT } from './law';\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * The tone this accent takes over a backdrop of the given lightness — deeper over dark, lighter\n * over light, which is what \"a range of tones mapped to content brightness\" means.\n *\n * @17:21: tinting is for the primary action, not for everything. \"When every element is tinted,\n * nothing stands out.\" That is the host's call, not this function's.\n */\nexport function accentTone(\n color: readonly [number, number, number],\n backdropLuma: number,\n): [number, number, number] {\n const k = ACCENT.deep + (ACCENT.light - ACCENT.deep) * clamp01(backdropLuma);\n return [clamp01(color[0] * k), clamp01(color[1] * k), clamp01(color[2] * k)];\n}\n\n/** The fraction of the medium the colour occupies, which is what keeps the content showing\n * through it rather than being covered by it. */\nexport function accentAmount(accent: VireGlassAccent): number {\n return clamp01(accent.amount ?? ACCENT.amount);\n}\n","// Concentricity (reference 219 @7:53): nested shapes share the CENTER of curvature, not the radius.\n// So the inner shape's radius is smaller by exactly the inset — otherwise the corners don't run\n// parallel and the gap between the shapes either gets eaten or spreads apart.\n\n/**\n * Radius of a nested shape: outer radius minus inset. Zero is a square corner; it never goes\n * negative — once the inset exceeds the outer radius, the corner is simply a right angle.\n *\n * `minimum` — a floor on the radius (analogous to `concentric(minimum:)` in SwiftUI): far from\n * the edge, honest concentricity yields zero and the nested element drops out of the family with\n * a sharp corner. The floor breaks concentricity on purpose — here kinship between shapes matters\n * more than a shared center of curvature.\n */\nexport function concentricRadius(outerRadius: number, inset: number, minimum = 0): number {\n return Math.max(outerRadius - inset, Math.max(minimum, 0));\n}\n\n/**\n * The inset at which an inner shape with a given radius stays concentric with the outer one.\n * The inverse problem: the element's radius is known (its size dictates it), and what's needed\n * is the margin around it.\n */\nexport function concentricInset(outerRadius: number, innerRadius: number): number {\n return Math.max(outerRadius - innerRadius, 0);\n}\n\n/**\n * The three shape types the design system builds concentric layouts from (356 @3:42): \"fixed\n * shapes have a constant corner radius. Capsules use a radius that's half the height of the\n * container. And concentric shapes calculate their radius by subtracting padding from the\n * parent's.\"\n *\n * Naming them is the point. 356 @5:09: \"using the three shape types we covered earlier helps keep\n * your components aligned with the system.\" A host that only has a number has to decide what that\n * number means every time the layout changes; a host that has the type gets the number recomputed\n * for it.\n */\nexport type ShapeSpec =\n | { type: 'fixed'; radius: number }\n | { type: 'capsule' }\n /**\n * `fallback` is 356 @6:00: \"a neat trick for managing components that need to work both inside a\n * container and on their own: use a concentric shape with a fallback radius. The concentric value\n * adapts when nested, and the fallback kicks in when the component stands alone.\"\n *\n * It is not the same as `minimum`. A minimum is a floor that applies while nested and breaks\n * concentricity on purpose; a fallback applies only when there is no parent to be concentric\n * with, and never overrides a parent that exists.\n */\n | { type: 'concentric'; inset: number; minimum?: number; fallback?: number };\n\n/** What is around a shape, when there is something around it. */\nexport type ShapeParent = { cornerRadius: number };\n\n/**\n * The corner radius a shape takes in the place it finds itself. `height` is the shape's own, which\n * is what a capsule's radius is measured from; `parent` is absent when the shape stands alone.\n */\nexport function resolveShape(spec: ShapeSpec, height: number, parent?: ShapeParent): number {\n switch (spec.type) {\n case 'fixed':\n return Math.max(spec.radius, 0);\n case 'capsule':\n return Math.max(height, 0) / 2;\n case 'concentric':\n return parent\n ? concentricRadius(parent.cornerRadius, spec.inset, spec.minimum)\n : Math.max(spec.fallback ?? 0, 0);\n }\n}\n\n/**\n * Whether two nested shapes are concentric, and which way they are wrong when they are not.\n * 356 @5:19: \"keep an eye out for corners that feel too pinched — or flared. They can create\n * tension and break the sense of balance.\"\n *\n * Pinched is an inner radius smaller than concentricity asks for: the gap between the corners\n * widens through the curve. Flared is larger: the gap narrows and the corners crowd each other.\n * The defect is visible to the eye and usually goes unnamed, which is why this names it.\n */\nexport function concentricFit(\n outerRadius: number,\n inset: number,\n innerRadius: number,\n tolerance = 0.5,\n): 'concentric' | 'pinched' | 'flared' {\n const want = concentricRadius(outerRadius, inset);\n if (innerRadius < want - tolerance) return 'pinched';\n if (innerRadius > want + tolerance) return 'flared';\n return 'concentric';\n}\n","// Rim light (docs/reference.md §2): a hairline along the whole silhouette — \"not a band and not a\n// bevel\" — brighter toward the key light, with a second, weaker arc opposite it, outlined by a thin\n// dark line, its colour taken from the environment and its strength from how light that is.\n//\n// Every number here is the lens shader's own, read from the law. The only thing that differs is\n// the primitive: a conic gradient sampled at fixed angles instead of a per-pixel normal.\nimport { RIM } from '../law';\nimport type { VireGlassOptics } from '../material';\n\nconst {\n lobeExponent: LOBE_EXPONENT,\n opposingArc: OPPOSING_ARC,\n darkEdge: DARK_EDGE,\n contour: CONTOUR,\n whiteShare: WHITE_SHARE,\n reflectanceRef: REFLECTANCE_REF,\n} = RIM;\n\n/** One stop every 7.5°. Fine enough that a cubic lobe reads as a smooth arc rather than a fan. */\nconst STOPS = 48;\n\n/**\n * Screen space has y pointing down; a CSS conic gradient starts at 12 o'clock and runs clockwise.\n * A point at conic angle φ therefore has outward normal `(sin φ, -cos φ)`, which is what the lobe\n * is measured against.\n */\nexport function lightConicAngle(light: readonly [number, number]): number {\n const [lx, ly] = light;\n const deg = (Math.atan2(lx, -ly) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\n/** The shader's key-light lobe, evaluated for a rim point whose normal sits `deltaDeg` away from\n * the light. Both arcs come out of this one expression — that is why they are opposed. */\nexport function rimLobe(deltaDeg: number, specular: number): number {\n const facing = Math.cos((deltaDeg * Math.PI) / 180);\n const front = facing > 0 ? Math.pow(facing, LOBE_EXPONENT) : 0;\n const back = facing < 0 ? Math.pow(-facing, LOBE_EXPONENT) : 0;\n return specular * (front + OPPOSING_ARC * back);\n}\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\nconst to255 = (v: number) => Math.round(clamp01(v) * 255);\n\nexport type RimAmbient = readonly [number, number, number];\n\nconst mixTo = (a: number, b: number, t: number) => a + (b - a) * t;\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n const t = clamp01((x - edge0) / (edge1 - edge0));\n return t * t * (3 - 2 * t);\n}\n\n/** Lightness of an ambient colour, the weights the lens uses. */\nexport function ambientLuma(ambient: RimAmbient): number {\n return 0.2126 * ambient[0] + 0.7152 * ambient[1] + 0.0722 * ambient[2];\n}\n\n/** How strongly the line is drawn over a surround of this lightness (§2, §6). */\nexport function rimStrength(luma: number): number {\n return mixTo(RIM.strengthDark, RIM.strengthLight, smoothstep(RIM.ambientFrom, RIM.ambientTo, luma));\n}\n\n/**\n * The line's opacity where the rim's normal sits `deltaDeg` from the light: a floor all the way\n * round and the key-light lobe on top of it, all of it scaled by the medium's reflectance up to\n * the reference material's.\n */\nexport function rimLineAlpha(deltaDeg: number, optics: VireGlassOptics, luma: number): number {\n const reflect = Math.min(optics.fresnel / REFLECTANCE_REF, 1);\n const damping = optics.fresnel > 0 ? optics.specular / optics.fresnel : 0;\n const lobe = rimLobe(deltaDeg, damping);\n return clamp01(rimStrength(luma) * reflect * (CONTOUR + (1 - CONTOUR) * lobe));\n}\n\n/**\n * The gradient for the hairline: a light line round the whole contour, brighter toward the key\n * light, drawn over the dark edge. Its colour comes from the environment — \"over a yellow flower\n * the rim is yellow, over sky it is blue\" (§2) — lifted toward white, and its strength follows how\n * light the environment is.\n *\n * The opposing arc carries an iridescent fringe (§2), so `iridescence` pulls its channels apart\n * rather than lifting them together.\n *\n * Two layers, the line first: `--vireglass-rim` is a background list and paints as one.\n */\nexport function rimGradientCss(\n optics: VireGlassOptics,\n ambient: RimAmbient,\n light: readonly [number, number],\n appear = 1,\n): string {\n const present = clamp01(appear);\n const start = lightConicAngle(light);\n const [ar, ag, ab] = ambient;\n const luma = ambientLuma(ambient);\n const line: string[] = [];\n\n for (let i = 0; i <= STOPS; i += 1) {\n const angle = (i / STOPS) * 360;\n const facing = Math.cos((angle * Math.PI) / 180);\n // The far arc is where dispersion shows as a fringe; the near one is a clean specular.\n const fringe = facing < 0 ? optics.iridescence * OPPOSING_ARC : 0;\n\n const r = ar + (1 - ar) * clamp01(WHITE_SHARE + fringe);\n const g = ag + (1 - ag) * WHITE_SHARE;\n const b = ab + (1 - ab) * clamp01(WHITE_SHARE - fringe);\n const alpha = rimLineAlpha(angle, optics, luma) * present;\n line.push(`rgba(${to255(r)},${to255(g)},${to255(b)},${alpha.toFixed(3)}) ${angle.toFixed(1)}deg`);\n }\n\n // Scaled by presence, not floored: the dark edge would otherwise outline an element that is not\n // there yet.\n const dark = `rgba(0,0,0,${(DARK_EDGE * present).toFixed(3)})`;\n return (\n `conic-gradient(from ${start.toFixed(1)}deg, ${line.join(', ')}), ` +\n `conic-gradient(${dark} 0deg, ${dark} 360deg)`\n );\n}\n\nexport const RIM_WIDTH_PX = RIM.widthPx;\n\n/**\n * The border for increased contrast (§9: elements become \"predominantly black or white\" and are\n * highlighted \"with a contrasting border\").\n *\n * Not a gradient: the two arcs above are a light source reflecting off a curved edge, and under\n * this setting the edge is not reporting where the light is, it is separating the element from\n * everything around it. It has to hold at every angle, including the one facing away from the key\n * light where the ordinary rim falls back to a dim dark line.\n */\nexport function contrastRimCss(bodyLuma: number, rimLuma: number): string {\n const v = to255(rimLuma);\n // Opaque on purpose. A border that lets the backdrop through is the thing this setting exists\n // to replace, and the body behind it is already at its own pole.\n void bodyLuma;\n return `conic-gradient(rgb(${v},${v},${v}) 0deg, rgb(${v},${v},${v}) 360deg)`;\n}\n","// Glass inside glass (docs/reference.md §6). 219 @11:50 puts it among the principles: \"avoid\n// putting [glass] within or on top of other glass elements to maintain hierarchy and prevent\n// clutter.\" S 32:54 (\"Building CNN for iOS 26\") is the same rule reported from the other side, by a\n// team that had already shipped it: \"Applying the glass effect to both a parent and child views led to visual redundancy.\n// Double translucency, layered blur, and unpredictable rendering.\"\n//\n// On this renderer it is not only a matter of hierarchy. `backdrop-filter` samples what is already\n// composited behind the element, so a nested pane's backdrop is the outer pane's OUTPUT: the\n// displacement is applied twice to the same pixels and the two blurs multiply. The inner element\n// does not look like thicker glass, it looks like a mistake.\n//\n// Overlap is a different case and not this function's business — a sheet over a bar is two panes in\n// the stacking order, which is what two panes of glass actually do. Only containment is wrong.\nconst WARNED = new WeakSet<Element>();\n\n/** Set by `attachGlass`; exported so the check does not have to know the attribute's spelling. */\nexport const GLASS_ATTR = 'data-vireglass';\n\nexport function warnIfNested(el: Element): void {\n if (WARNED.has(el)) return;\n const outer = el.parentElement?.closest(`[${GLASS_ATTR}]`);\n if (!outer) return;\n WARNED.add(el);\n // Warned, not refused: where an element sits is the host's layout, and a library that silently\n // declines to render is harder to debug than one that says what is wrong.\n const where = outer.tagName.toLowerCase() + (outer.id ? `#${outer.id}` : '');\n console.warn(\n `vireglass: glass inside glass — this element is a descendant of <${where}>, which is also glass. ` +\n `Its backdrop is the outer element's output, so the refraction is applied twice and the blurs ` +\n `multiply. Put the glass on one of the two.`,\n );\n}\n","/** The inline value an element had for a property before the glass took it over, as a way back. */\nexport function holdProperty(style: Pick<CSSStyleDeclaration, 'getPropertyValue' | 'setProperty' | 'removeProperty'>, name: string): () => void {\n const saved = style.getPropertyValue(name);\n return () => {\n if (saved) style.setProperty(name, saved);\n else style.removeProperty(name);\n };\n}\n","import { ACCENT, MORPH } from './law';\nimport {\n bevelDp,\n bevelFraction,\n halfMinDp,\n rimDp,\n shadowReachDp,\n surfacePadDp,\n thicknessDp,\n type VireGlassGeometry,\n} from './geometry';\nimport { LENS_SHADER } from './lens-shader';\nimport { neckToBridge } from './sdf';\nimport { debugIndex, type VireGlassDebugMode, type VireGlassOptics } from './material';\n\n/** A second shape joined to the element by a smooth union: the geometry that merges and growth\n * transitions are built on (a capsule drawn into a drop, then grown into its menu). Offsets from\n * the element's centre and sizes in dp. */\nexport type VireGlassMorph = {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n cornerRadius: number;\n /** Seam smoothing radius in dp; 0 turns the second shape off. */\n smoothing: number;\n};\n\n\n/** Surface response to a finger: the field around the touch point deforms, not the shape's\n * bounding box (`vgTouchWarp` in `sdf.ts`). Lengths in dp; `radius` = 0 turns the response off\n * entirely. */\nexport type VireGlassTouch = {\n x: number;\n y: number;\n pullX: number;\n pullY: number;\n press: number;\n radius: number;\n waveAmp: number;\n wavePhase: number;\n};\n\nconst NO_TOUCH: VireGlassTouch = {\n x: 0, y: 0, pullX: 0, pullY: 0, press: 0, radius: 0, waveAmp: 0, wavePhase: 0,\n};\n\nconst NO_MORPH = { offsetX: 0, offsetY: 0, width: 0, height: 0, cornerRadius: 0, smoothing: 0 };\n\n/** No progress. Negative rather than zero: zero is the start of the track, a legitimate value. */\nconst NO_PROGRESS = -1;\n\n/** Tinted glass for the primary action (M 16:08). Color is RGB 0…1. */\nexport type VireGlassAccent = { color: readonly [number, number, number]; amount?: number };\n\n/** Default tint fraction: the color reads, but content beneath it is still visible. */\nexport const ACCENT_AMOUNT = ACCENT.amount;\nconst NO_ACCENT = [0, 0, 0, 0] as const;\n\n\n\n/** Magnification at the flat center. Kept separate from the uniform channel: it's also used by\n * the fallback below Android 13, where there's no RuntimeShader and only an affine magnifier is\n * left. */\nexport const lensMagnify = (o: VireGlassOptics) => 1 + (o.refractionScale - 1) * o.refraction;\n\n/**\n * Lens uniforms. Assembled as ONE channel: name, size and values travel together, so a mismatch\n * with the shader is caught immediately, with the name right there in the log. There used to be a\n * separate Kotlin `Prop` per value — Expo swallows an unknown prop silently, and the lens simply\n * never turned on (docs/material-lab.md E-01, which is how refraction ended up disabled for an\n * entire phase).\n *\n * Everything with a dimension is converted to PIXELS right here. The native view is left with\n * only the uniforms it alone knows: its own size and its own place on screen.\n */\n// The lens's uniform names and sizes are always the same — the set is fixed. They're handed over\n// as ONE instance for the whole process: otherwise every frame of a drag would send three dozen\n// fresh strings to the native side, React can't tell \"unchanged\" from \"a new array\", and motion\n// goes stepwise. The values are the only thing that actually changes.\nconst shapes = new Map<number, { names: string[]; sizes: number[] }>();\n\nfunction channel(entries: [string, number | readonly number[]][]) {\n const uniformValues: number[] = [];\n let shape = shapes.get(entries.length);\n let same = shape !== undefined;\n for (let i = 0; i < entries.length; i += 1) {\n const [name, value] = entries[i];\n const v = typeof value === 'number' ? [value] : value;\n if (same && (shape!.names[i] !== name || shape!.sizes[i] !== v.length)) same = false;\n for (const x of v) uniformValues.push(x);\n }\n if (!same) {\n shape = {\n names: entries.map((e) => e[0]),\n sizes: entries.map((e) => (typeof e[1] === 'number' ? 1 : e[1].length)),\n };\n shapes.set(entries.length, shape);\n }\n return { uniformNames: shape!.names, uniformSizes: shape!.sizes, uniformValues };\n}\n\n/** Props for the native view. Besides the uniform channel, only what the view uses itself lives\n * here: the shader source and the visible glass's size (the probe rectangle is taken from it). */\nexport function toLensProps(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n density: number,\n options: {\n debug?: VireGlassDebugMode;\n morph?: VireGlassMorph;\n /** Third shape of the fused body; a zero size turns it off. */\n morph2?: VireGlassMorph;\n groupProbe?: number[];\n touch?: VireGlassTouch;\n /** Progress fraction, 0…1: to the left of the boundary the element is active. `undefined` means no progress. */\n progress?: number;\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the lens builds up as the element appears — instead of a plain fade. */\n appear?: number;\n /** Tint for the primary action: the glass color and the fraction it lays over the content. */\n accent?: VireGlassAccent;\n } = {},\n) {\n const morph = options.morph ?? NO_MORPH;\n const morph2 = options.morph2 ?? NO_MORPH;\n const touch = options.touch ?? NO_TOUCH;\n // Backdrop estimate for the whole surface group. Travels through the same channel as the\n // material and applies AFTER the lens's own estimate — that is, it simply overrides it. It\n // can't travel as a separate prop: the lens view is wrapped in an animated component.\n const g = options.groupProbe;\n const group: [string, number | readonly number[]][] =\n g && g.length >= 9\n ? [\n ['u_probeLuma', g[0]],\n ['u_probeBusy', g[1]],\n ['u_probeRange', [g[2], g[3]]],\n ['u_probeSlope', [g[4], g[5]]],\n ['u_probe', [g[6], g[7], g[8]]],\n ]\n : [];\n const d = density;\n const halfW = (geometry.width * d) / 2;\n const halfH = (geometry.height * d) / 2;\n const halfMin = Math.min(halfW, halfH);\n\n return {\n shaderSource: LENS_SHADER,\n glassWidth: geometry.width,\n glassHeight: geometry.height,\n ...channel([\n ['u_halfSize', [halfW, halfH]],\n ['u_corner', Math.min(geometry.cornerRadius * d, halfMin)],\n ['u_bevel', Math.max(bevelDp(geometry, optics) * d, 1)],\n ['u_thick', thicknessDp(geometry, optics) * d],\n ['u_rim', rimDp(geometry, optics) * d],\n ['u_ior', optics.ior],\n ['u_iorSpread', optics.iorSpread],\n ['u_light', options.light ?? REST_LIGHT],\n ['u_appear', options.appear ?? 1],\n ['u_accent', options.accent ? [...options.accent.color, options.accent.amount ?? ACCENT_AMOUNT] : NO_ACCENT],\n // Haze from surface roughness. Lives in the same disc-gather pass as adaptive scattering,\n // and fades out toward the bevel: that's a different job there — bending the ray and\n // splitting it.\n ['u_frost', optics.blur * d],\n ['u_ink', optics.ink],\n ['u_legibility', optics.legibility],\n ['u_dim', optics.dimming],\n ['u_presence', optics.presence],\n ['u_adaptRadius', optics.adaptRadius * d],\n ['u_bodyDensity', optics.bodyDensity],\n ['u_edgeLight', optics.edgeLight],\n ['u_fresnel', optics.fresnel],\n ['u_specular', optics.specular],\n // The rim gathers light from the element's vicinity — this is a radius around the shape,\n // not its bevel.\n ['u_reflectReach', optics.gatherRadiusDp * d],\n ['u_film', optics.film],\n ['u_iridescence', optics.iridescence],\n ['u_diffraction', optics.diffraction],\n ['u_colorPickup', optics.colorPickup],\n ['u_morphOffset', [morph.offsetX * d, morph.offsetY * d]],\n ['u_morphHalf', [(morph.width * d) / 2, (morph.height * d) / 2]],\n ['u_morphCorner', morph.cornerRadius * d],\n ['u_morphK', morph.smoothing * d],\n ['u_morph2Offset', [morph2.offsetX * d, morph2.offsetY * d]],\n ['u_morph2Half', [(morph2.width * d) / 2, (morph2.height * d) / 2]],\n ['u_morph2Corner', morph2.cornerRadius * d],\n ['u_touch', [touch.x * d, touch.y * d]],\n ['u_pull', [touch.pullX * d, touch.pullY * d]],\n ['u_touchPress', touch.press],\n ['u_touchRadius', touch.radius * d],\n ['u_wave', [touch.waveAmp * d, touch.wavePhase]],\n ['u_progress', options.progress ?? NO_PROGRESS],\n ['u_debug', debugIndex(options.debug ?? 'normal')],\n ...group,\n ]),\n };\n}\n\n/** Static part of the surface uniforms. Dynamics (gesture, press, light) get mixed in inside the\n * component's worklet — the adapter must stay an ordinary function. */\nexport function toSurfaceUniforms(\n optics: VireGlassOptics,\n geometry: VireGlassGeometry,\n options: {\n debug?: VireGlassDebugMode;\n morph?: VireGlassMorph;\n /** Third shape of the fused body; a zero size turns it off. */\n morph2?: VireGlassMorph;\n dragLimit?: number;\n shadow?: number;\n /** Average ambient color around the element: light from it bleeds into the shadow (reference 219 @8:22). */\n ambient?: readonly [number, number, number];\n /** The lens draws the glass body — the surface is left with the highlight, shadow and icon. */\n bodyInLens?: boolean;\n touch?: VireGlassTouch;\n /** Progress fraction, 0…1: to the left of the boundary the element is active. `undefined` means no progress. */\n progress?: number;\n /** 0…1: the element is appearing — shadow and ink build up together with the lens. */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n } = {},\n) {\n const morph = options.morph ?? NO_MORPH;\n const morph2 = options.morph2 ?? NO_MORPH;\n const touch = options.touch ?? NO_TOUCH;\n const pad = surfacePadDp(geometry, options.dragLimit ?? 0, morph);\n return {\n u_center: [geometry.width / 2 + pad, geometry.height / 2 + pad],\n u_halfSize: [geometry.width / 2, geometry.height / 2],\n u_corner: Math.min(geometry.cornerRadius, halfMinDp(geometry)),\n u_bevel: bevelDp(geometry, optics),\n u_thickness: bevelFraction(geometry, optics),\n u_morphOffset: [morph.offsetX, morph.offsetY],\n u_morphHalf: [morph.width / 2, morph.height / 2],\n u_morphCorner: morph.cornerRadius,\n u_morphK: morph.smoothing,\n u_morph2Offset: [morph2.offsetX, morph2.offsetY],\n u_morph2Half: [morph2.width / 2, morph2.height / 2],\n u_morph2Corner: morph2.cornerRadius,\n u_edgeDensity: optics.edgeDensity,\n u_dispersion: optics.dispersion,\n u_refraction: optics.refraction,\n // Tint density is suppressed when the lens is drawing the body: painting it twice would\n // double the fill, and adaptation is impossible on the surface anyway — it can't see the\n // backdrop. The color itself stays: it drives absorption at the rim.\n u_tint: [\n optics.tint.r,\n optics.tint.g,\n optics.tint.b,\n options.bodyInLens ? 0 : optics.tintStrength,\n ],\n u_shadow: options.shadow ?? 1,\n // Neutral by default: without an ambient sample, the shadow stays exactly as it was.\n u_ambient: options.ambient ?? [0, 0, 0],\n u_shadowReach: shadowReachDp(geometry),\n u_touch: [touch.x, touch.y],\n u_pull: [touch.pullX, touch.pullY],\n u_touchPress: touch.press,\n u_touchRadius: touch.radius,\n u_wave: [touch.waveAmp, touch.wavePhase],\n u_presence: optics.presence,\n u_progress: options.progress ?? NO_PROGRESS,\n u_appear: options.appear ?? 1,\n // Zero by default: buttons sink in, the way every element behaved before this rule existed.\n u_lift: options.lift ?? 0,\n\n u_debug: debugIndex(options.debug ?? 'normal'),\n };\n}\n\n/**\n * Surface fields that are LENGTHS: the adapter's contract is specified in dp, and on the web each\n * one of them has to be multiplied by screen density. The list lives here rather than in the\n * renderer, where it used to be a dozen and a half manual multiplications in a row: a missed\n * field there was only caught by eye, and the miss isn't visible everywhere — at density 1,\n * multiplying is indistinguishable from not doing it.\n */\nexport type SurfaceUniforms = ReturnType<typeof toSurfaceUniforms>;\n\nexport const SURFACE_LENGTH_UNIFORMS = [\n 'u_halfSize',\n 'u_corner',\n 'u_bevel',\n 'u_morphOffset',\n 'u_morphHalf',\n 'u_morphCorner',\n 'u_morphK',\n 'u_morph2Offset',\n 'u_morph2Half',\n 'u_morph2Corner',\n 'u_shadowReach',\n 'u_touch',\n 'u_pull',\n 'u_touchRadius',\n // `satisfies`, not just `as const`: otherwise a typo in the name compiles silently and makes it\n // to runtime — the field with the garbage name gets NaN, and the real one is left un-multiplied.\n] as const satisfies readonly (keyof SurfaceUniforms)[];\n\n/**\n * Surface uniforms in device pixels. Android draws in dp and calls the adapter as-is; the web\n * needs this conversion. `u_center` isn't part of it: the renderer knows the element's center on\n * its own.\n */\nexport function toDeviceSurfaceUniforms(raw: SurfaceUniforms, density: number): SurfaceUniforms {\n const scaled: Record<string, unknown> = { ...raw };\n for (const key of SURFACE_LENGTH_UNIFORMS) {\n const value: unknown = scaled[key];\n scaled[key] = Array.isArray(value)\n ? (value as number[]).map((v) => v * density)\n : (value as number) * density;\n }\n // Of the wave, only the amplitude has a length; the phase is in turns and knows nothing about density.\n scaled.u_wave = [raw.u_wave[0] * density, raw.u_wave[1]];\n return scaled as SurfaceUniforms;\n}\n\n/** Key light direction in screen coordinates, for when the orientation response is off. */\nexport const REST_LIGHT: readonly [number, number] = [-0.577, -0.817];\n\n/** Uniforms the component mixes in inside the worklet (press, active, light direction) and via\n * the icon layer. Listed here so a test can check the shader contract's completeness without\n * importing the component itself (it pulls in Skia and doesn't come up in a node environment). */\nexport const DYNAMIC_UNIFORMS = ['u_press', 'u_active'] as const;\n\nexport const ICON_UNIFORMS = ['u_iconOn', 'u_iconScale', 'u_inkIdle', 'u_inkActive'] as const;\n\n/** App-colored overlay layer on the glass. The `u_overlay` sampler shares its contract with the\n * ink mask and is sampled at the SAME coordinate — otherwise deformation would carry them apart. */\nexport const OVERLAY_UNIFORMS = ['u_overlayOn'] as const;\n\n/**\n * Fusing two surfaces into one continuous medium.\n *\n * The second shape is described RELATIVE to the first one's center, because both live in the\n * same shader: the union has no \"two pieces of glass,\" just one body with two bulges — the mask,\n * the refraction and the rim are all computed from a single shared scene.\n *\n * `t` — how fused the shapes are: 0 turns the second shape off before any computation, 1 gives a\n * single shared medium. The seam's smoothing radius is a fraction of the smaller half-size: on\n * large elements the bridge has to be wider, otherwise the seam is left with a sharp corner,\n * which doesn't happen in a liquid.\n */\n\n\n/**\n * How wide the neck between two lobes has to be: enough to soften the seam on a large element, and\n * enough to actually SPAN whatever is between them. The second term is the one that was missing.\n */\nfunction neckFor(\n half: number,\n aw: number,\n ah: number,\n bw: number,\n bh: number,\n offsetX: number,\n offsetY: number,\n): number {\n // Surface-to-surface, measured between the bounding boxes. The rounded corners put the true\n // surfaces slightly further apart, so this errs toward a wider neck, which is the safe side.\n const gx = Math.abs(offsetX) - (aw + bw) / 2;\n const gy = Math.abs(offsetY) - (ah + bh) / 2;\n const gap = Math.hypot(Math.max(gx, 0), Math.max(gy, 0));\n // Capped at the narrowest of the two bodies. A neck wider than what it joins is not a neck, and\n // past that width the honest answer is that these are two things rather than one — a menu that\n // has finished leaving its button, two controls too far apart to be a segmented control. Being\n // separate is a legitimate state; being joined by a blob larger than either shape is not.\n const widest = Math.min(aw, ah, bw, bh);\n return Math.min(Math.max(half * MORPH.neck, neckToBridge(gap) * MORPH.fuse), widest);\n}\n\nexport function morphBetween(\n a: VireGlassGeometry,\n b: VireGlassGeometry,\n offsetX: number,\n offsetY: number,\n t: number,\n): VireGlassMorph | undefined {\n if (t <= 0) return undefined;\n const half = Math.min(halfMinDp(a), halfMinDp(b));\n return {\n offsetX,\n offsetY,\n width: b.width,\n height: b.height,\n cornerRadius: b.cornerRadius,\n smoothing: neckFor(half, a.width, a.height, b.width, b.height, offsetX, offsetY) * Math.min(t, 1),\n };\n}\n\n/**\n * MITOSIS: the second shape grows OUT OF the first and travels to its place, instead of appearing\n * beside it at full size. A menu coming out of its button, a control dividing into segments.\n *\n * `morphBetween` is the other half — two shapes that are both already where they belong, fusing\n * into one body — and run backwards it is meiosis, the neck thinning until it breaks. What neither\n * of them may do is pop: at any `t` above zero this returns one continuous body, because that is\n * the whole of what the reference says a material transition is.\n *\n * The choreography stays the host's: what the shapes MEAN is the app's business. How a silhouette\n * emerges from another silhouette is the material's, the same way the spring under a finger is.\n */\nexport function morphOutOf(\n source: VireGlassGeometry,\n target: VireGlassGeometry,\n offsetX: number,\n offsetY: number,\n t: number,\n): VireGlassMorph | undefined {\n if (t <= 0) return undefined;\n const k = Math.min(t, 1);\n // At t = 0 the lobe IS the parent, in the parent's place: the transition starts from one body and\n // never has a first frame in which a second one exists. The parent's own surface is what the neck\n // attaches to, so nothing has to be budded off to give it something to hold.\n const width = source.width + (target.width - source.width) * k;\n const height = source.height + (target.height - source.height) * k;\n const cornerRadius = source.cornerRadius + (target.cornerRadius - source.cornerRadius) * k;\n const half = Math.min(halfMinDp(source), Math.min(width, height) / 2);\n return {\n offsetX: offsetX * k,\n offsetY: offsetY * k,\n width,\n height,\n cornerRadius,\n // The lobe travels as it grows, so the span changes every frame and the neck is measured\n // against where the lobe actually is, not against where it will end up.\n smoothing: neckFor(half, source.width, source.height, width, height, offsetX * k, offsetY * k),\n };\n}\n","// The element's response to a finger — PART OF THE MATERIAL, not the app: the springs here\n// describe what the medium feels like, exactly the way ior describes what it looks like through.\n// Keeping them with the consumer would mean web and Android end up with two different glasses\n// under one name.\n//\n// It's the FIELD around the touch point that deforms (vgTouchWarp in sdf.ts), so four values are\n// computed here: where it was touched, how far it's being dragged, how deep the press is, and\n// what wave is currently running.\n//\n// The key point: drag is anchored to the touch BLOB. Pull the right edge and the right edge\n// moves, the left stays put; the finger has area, not a point — the plateau inside `vgTouchWarp`.\n// Scaling the shape's bounding box isn't an option: that would make a rightward pull also bulge\n// the left side, which liquid doesn't do.\n//\n// PRESS is viscous: it dents shallow and releases slowly.\n// DRAG is thick: the body noticeably lags the finger, travel is short, and on release it snaps\n// back quickly with almost no overshoot. A wide, springy overshoot would be liquid jelly, not\n// dense glass.\n// WAVE: touch and lift-off each throw a short ring that decays within a quarter second.\n\nimport { ACCESSIBILITY, SPRING } from './law';\n\nexport type DeformSample = {\n /** Touch point relative to the element's center, CSS pixels. */\n touchX: number;\n touchY: number;\n pullX: number;\n pullY: number;\n press: number;\n active: number;\n /** Wave amplitude in CSS pixels and its phase in turns. */\n waveAmp: number;\n wavePhase: number;\n};\n\n/**\n * `elastic: false` is reduced motion (§9): the spring and the ripple are the material's elastic\n * properties and stop, the press stays and is damped. An element that goes dead under the setting\n * would not be reduced motion — it would be no feedback at all, and the press is what lights the\n * element from within (§5), which is light rather than movement.\n */\nexport type DeformOptions = { elastic?: boolean };\n\nexport function createDeform(options: DeformOptions = {}) {\n let elastic = options.elastic !== false;\n let pressCeiling = elastic ? 1 : ACCESSIBILITY.stillPress;\n let touchX = 0;\n let touchY = 0;\n let targetTouchX = 0;\n let targetTouchY = 0;\n let pullX = 0;\n let pullY = 0;\n let vx = 0;\n let vy = 0;\n let targetX = 0;\n let targetY = 0;\n let held = false;\n let press = 0;\n let active = 0;\n let waveAmp = 0;\n let wavePhase = 0;\n\n /** `x`, `y` — touch point relative to the element's center, CSS pixels. */\n function grab(x: number, y: number, waveStart: number): void {\n // Rest is checked BEFORE the grab: idle() looks at !held, and after `held = true` it's\n // always false — the point would then jump even on a first touch of a resting element.\n const atRest = idle();\n held = true;\n targetTouchX = x;\n targetTouchY = y;\n // On a resting element the finger lands instantly; if it hasn't settled yet from the\n // previous touch, the point travels there over a couple of frames. An instant jump tears the\n // deformation, and on rapid taps that reads as jitter.\n if (atRest) {\n touchX = x;\n touchY = y;\n }\n targetX = 0;\n targetY = 0;\n // Impulses ADD UP rather than restart, and phase isn't reset: resetting it would cut off a\n // running wave mid-period, which is exactly what causes a jolt on rapid clicks.\n if (elastic) waveAmp = Math.min(waveAmp + waveStart, waveStart * SPRING.waveCapOnGrab);\n }\n\n function drag(dx: number, dy: number, limit: number): void {\n if (!held || !elastic) return;\n const len = Math.hypot(dx, dy);\n // Travel saturates rather than clips: near the limit the finger keeps moving while the field\n // barely does — that's how a thick liquid behaves once it hits its limit.\n const scale = len > 1e-3 ? (limit * Math.tanh(len / limit)) / len : 0;\n targetX = dx * scale;\n targetY = dy * scale;\n }\n\n /** Lifting the finger throws a second wave — weaker than the one from touching down. */\n function release(waveStart: number): void {\n held = false;\n targetX = 0;\n targetY = 0;\n if (elastic) waveAmp = Math.min(waveAmp + waveStart, waveStart * SPRING.waveCapOnRelease);\n }\n\n function integrate(dt: number): void {\n const k = held ? SPRING.holdStiffness : SPRING.releaseStiffness;\n const c = held ? SPRING.holdDamping : SPRING.releaseDamping;\n vx += (k * (targetX - pullX) - c * vx) * dt;\n vy += (k * (targetY - pullY) - c * vy) * dt;\n pullX += vx * dt;\n pullY += vy * dt;\n\n const pressTarget = held ? pressCeiling : 0;\n const tau = held ? SPRING.pressAttack : SPRING.pressRelease;\n press += (pressTarget - press) * (1 - Math.exp(-dt / tau));\n active += (pressTarget - active) * (1 - Math.exp(-dt / SPRING.activeFollow));\n\n // The touch point catches up to the finger fast, but not instantly — see grab().\n const follow = 1 - Math.exp(-dt / SPRING.pointFollow);\n touchX += (targetTouchX - touchX) * follow;\n touchY += (targetTouchY - touchY) * follow;\n\n wavePhase += dt * SPRING.waveTurnsPerSecond;\n waveAmp *= Math.exp(-dt / SPRING.waveDecay);\n if (waveAmp < 0.01) waveAmp = 0;\n }\n\n /**\n * The step is fixed, the frame isn't: on a software renderer there can be as few as ten frames\n * a second, and integrating \"however much time passed\" makes the response lag behind real time\n * (and at a large step the spring can even diverge). So time is caught up in sub-steps.\n */\n function step(dt: number): void {\n let rest = Math.min(Math.max(dt, 0), 0.25);\n const h = 1 / 120;\n while (rest > 1e-6) {\n const slice = Math.min(h, rest);\n integrate(slice);\n rest -= slice;\n }\n // Settled means exactly at rest. The `idle()` threshold stops rendering, but the values\n // themselves only approach zero asymptotically, and the element would stay forever very\n // slightly deformed: invisible to the eye, but a frame-vs-reference comparison would flag the\n // mismatch forever.\n if (idle()) {\n pullX = 0;\n pullY = 0;\n vx = 0;\n vy = 0;\n press = 0;\n active = 0;\n wavePhase = 0;\n }\n }\n\n /** Whether the element has settled — the bench uses this to decide whether to keep drawing frames. */\n function idle(): boolean {\n return (\n !held &&\n Math.abs(pullX) < 0.05 &&\n Math.abs(pullY) < 0.05 &&\n Math.hypot(vx, vy) < 0.5 &&\n press < 0.004 &&\n active < 0.004 &&\n waveAmp === 0\n );\n }\n\n /** The setting can be turned on while the page is open, and a deformation already in flight has\n * to stop rather than finish. */\n function setElastic(on: boolean): void {\n if (on === elastic) return;\n elastic = on;\n pressCeiling = on ? 1 : ACCESSIBILITY.stillPress;\n if (!on) {\n pullX = 0;\n pullY = 0;\n vx = 0;\n vy = 0;\n targetX = 0;\n targetY = 0;\n waveAmp = 0;\n wavePhase = 0;\n }\n }\n\n function sample(): DeformSample {\n return { touchX, touchY, pullX, pullY, press, active, waveAmp, wavePhase };\n }\n\n return { grab, drag, release, step, idle, sample, setElastic };\n}\n\n/**\n * RAISING INTO GLASS (reference §5, M 4:10–4:30). A control that isn't glass at rest — a switch\n * knob, a slider handle — stops being frosted under the finger and becomes a lens: whatever is\n * beneath it shows through.\n *\n * Glass comes in FASTER than frost leaves: the two fractions overlap, otherwise midway through\n * the transition the backdrop flashes through the knob for an instant — a hole where the control\n * should be.\n *\n * Lifting off the backdrop is NOT part of this. The shader's `u_lift` is a direction (\"this kind\n * of element sinks in or rises\"), not a magnitude — how far it has already risen is carried by\n * the press value that `u_lift` gets multiplied by. Returning a third fraction here would mean\n * multiplying press by itself — which is exactly what happened the first time the web bench wired\n * this up.\n */\nexport function raiseIntoGlass(press: number): { glass: number; solid: number } {\n const t = press < 0 ? 0 : press > 1 ? 1 : press;\n return { glass: Math.pow(t, 0.6), solid: 1 - Math.pow(t, 1.4) };\n}\n","// Scroll edge effect (reference 219 @8:52) — the SCREEN's job, not the material's: it sits over\n// the content beneath the panel, and the glass sees an already-dimmed backdrop. Only the general\n// rules live here.\nimport { SCROLL_EDGE } from './law';\n\n/**\n * 356 @11:48 names two styles across the system, \"soft and hard\", and says not to mix or stack\n * them. Soft is the default; hard is \"a stronger, more opaque boundary\", mostly macOS, for pinned\n * table headers and controls without backgrounds.\n *\n * Soft has two forms, and which one is in play is not a choice: 219 @9:16 dissolves the content\n * into the background, and @9:33, when darker content scrolls under and the glass itself turns to\n * its dark style, \"the effect intelligently switches to apply a subtle dimming instead\". Same\n * trigger as ink polarity, because it is the same problem — dark content under dark glass merges\n * with it unless the content is pushed down.\n */\nexport type ScrollEdgeStyle = 'dissolve' | 'dim' | 'hard';\n\nexport function scrollEdgeStyle(inkLight: boolean, pinned = false): ScrollEdgeStyle {\n if (pinned) return 'hard';\n return inkLight ? 'dim' : 'dissolve';\n}\n\n/** How far the content has to slide under the panel for the effect to fully engage, dp. */\nexport const SCROLL_EDGE_ENGAGE_DP = SCROLL_EDGE.engageDp;\n\n/**\n * How tall to make the edge, given the bar it sits under. The host positions the element; without\n * this it has to guess a height, and the reference has an answer — measured off the footage rather\n * than chosen (see `SCROLL_EDGE.reachOfBarHeight`).\n */\nexport function scrollEdgeReachDp(barHeightDp: number): number {\n return Math.max(barHeightDp, 0) * SCROLL_EDGE.reachOfBarHeight;\n}\n\n/**\n * Edge strength as a function of scroll. With no scroll, content near the top doesn't slide\n * under the panel yet — so there's no effect (a mail screen at the top: the header sits on a\n * clean background). At the bottom, content slides under it for as long as there's room left\n * to scroll.\n */\nexport function scrollEdgeStrength(side: 'top' | 'bottom', scroll: number, maxScroll: number): number {\n const room = side === 'top' ? scroll : maxScroll - scroll;\n return Math.min(Math.max(room / SCROLL_EDGE_ENGAGE_DP, 0), 1);\n}\n","// The scroll edge (docs/reference.md §10). Not the material's job but the SCREEN's: it sits over\n// the content beneath a panel, and the glass sees a backdrop that is already dimmed. The rules are\n// the core's (`../scroll-edge`); this attaches them to a real scroller and a real element.\nimport { SCROLL_EDGE } from '../law';\nimport { scrollEdgeStrength, scrollEdgeStyle, type ScrollEdgeStyle } from '../scroll-edge';\n\nexport type ScrollEdgeHandle = { update(): void; destroy(): void };\n\nexport type ScrollEdgeOptions = {\n /** Which edge of the scroller the panel sits at. */\n side?: 'top' | 'bottom';\n /** A view pinned under the panel — column headers — gets a flat band with no gradient (§10). */\n pinned?: boolean;\n /** Ink polarity of the nearest glass, 1 light and 0 dark. The edge style follows it: light ink\n * means dark glass and the content fades into a light dimming; dark ink means the opposite. */\n ink?: () => number;\n};\n\n/**\n * What the effect actually is. 356 @11:32: \"they don't block or darken like overlays.\"\n *\n * So the soft style is a BLUR with a mask, not a painted gradient: the content under the panel\n * goes out of focus into the background, which is what 219 @9:16 means by dissolving it, and\n * nothing is laid over it. The first version of this painted black at 22% down the ramp — an\n * overlay, doing the one thing the reference names as wrong.\n *\n * `dim` is the other soft form and it does carry a tone, because 219 @9:33 asks for one: over dark\n * content the glass turns dark and \"the effect intelligently switches to apply a subtle dimming\n * instead\". Dimming is a reduction in luminance. This painted white, which lightened the content\n * it was supposed to be pushing down.\n */\nexport type EdgePaint = { filter: string; mask: string; tone: string };\n\nexport function paintFor(style: ScrollEdgeStyle, side: 'top' | 'bottom'): EdgePaint {\n const direction = side === 'top' ? 'to top' : 'to bottom';\n if (style === 'hard') {\n // A flat band rather than a gradual fade (219 @9:41), and a stronger boundary (356 @12:12).\n return {\n filter: `blur(${SCROLL_EDGE.hardBlurDp}px)`,\n mask: '',\n tone: `linear-gradient(${direction}, rgba(0,0,0,${SCROLL_EDGE.hardAlpha}) 0 100%)`,\n };\n }\n const ramp = `linear-gradient(${direction}, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 100%)`;\n return {\n filter: `blur(${SCROLL_EDGE.dissolveBlurDp}px)`,\n mask: ramp,\n tone:\n style === 'dim'\n ? `linear-gradient(${direction}, rgba(0,0,0,${SCROLL_EDGE.dimAlpha}) 0%, rgba(0,0,0,0) 100%)`\n : 'none',\n };\n}\n\n/**\n * Paints the edge onto `edgeEl` — an element the host positions along the scroller's edge, under\n * the glass. It is the host's because §10 puts this on the screen, not on the material: the glass\n * must SEE the result, which means the effect has to be behind it in the stack.\n */\nexport function attachScrollEdge(\n scroller: HTMLElement,\n edgeEl: HTMLElement,\n opts: ScrollEdgeOptions = {},\n): ScrollEdgeHandle {\n const side = opts.side ?? 'top';\n let destroyed = false;\n\n function update(): void {\n if (destroyed) return;\n const maxScroll = Math.max(scroller.scrollHeight - scroller.clientHeight, 0);\n const strength = scrollEdgeStrength(side, scroller.scrollTop, maxScroll);\n const inkLight = (opts.ink?.() ?? 1) > 0.5;\n const style = scrollEdgeStyle(inkLight, opts.pinned);\n const paint = paintFor(style, side);\n // The blur is what dissolves the content; the mask is what makes it a ramp rather than a step.\n edgeEl.style.setProperty('backdrop-filter', paint.filter);\n edgeEl.style.setProperty('-webkit-backdrop-filter', paint.filter);\n if (paint.mask) {\n edgeEl.style.setProperty('mask-image', paint.mask);\n edgeEl.style.setProperty('-webkit-mask-image', paint.mask);\n } else {\n edgeEl.style.removeProperty('mask-image');\n edgeEl.style.removeProperty('-webkit-mask-image');\n }\n edgeEl.style.setProperty('background-image', paint.tone);\n edgeEl.style.setProperty('opacity', strength.toFixed(3));\n }\n\n const onScroll = () => update();\n scroller.addEventListener('scroll', onScroll, { passive: true });\n update();\n\n return {\n update,\n destroy() {\n destroyed = true;\n scroller.removeEventListener('scroll', onScroll);\n edgeEl.style.removeProperty('backdrop-filter');\n edgeEl.style.removeProperty('-webkit-backdrop-filter');\n edgeEl.style.removeProperty('mask-image');\n edgeEl.style.removeProperty('-webkit-mask-image');\n edgeEl.style.removeProperty('background-image');\n edgeEl.style.removeProperty('opacity');\n },\n };\n}\n","import { CONFIRMATIONS, FLIP_LUMA, RETURN_LUMA, type BackdropSample } from './adaptation';\n\n/**\n * GLASS GROUP ESTIMATE — the pure part of the surface group (`glass-group.tsx`).\n *\n * Everything that decides lives here: the lightness plane from members' samples, the group's\n * aggregates, the polarity requirement and its hysteresis. None of these rules need React or the\n * native layer, so they live apart from the component and are checked by a unit test.\n */\n\nexport type GroupMember = { x: number; y: number; sample: BackdropSample; legibility: number };\n\n/** Group estimate: center and average lightness, slope along x, the lightest spot, and the\n * measurement values shared by everyone — [variegation, lo, hi, r, g, b]. */\nexport type GroupPlane = {\n mx: number;\n ml: number;\n slope: number;\n base: number;\n rest: number[];\n};\n\n/** Input to the polarity decision: the lightness the group judges by, and the strictest of the requirements. */\nexport type GroupDecision = { decisive: number; legibility: number };\n\n/** Fraction of a new sample in the smoothed estimate. Samples come in from every member, so the\n * group collects roughly twenty a second — a quarter is enough for a response within ~200 ms. */\nexport const SMOOTH = 0.25;\n\n/** The remainder below which smoothing snaps the value to the sample. An exponential never\n * actually reaches its target, and the estimate kept \"changing\" by denormals for two more\n * minutes after the backdrop had settled. */\nexport const SETTLE = 1e-6;\n\n/**\n * Fraction of the slope that reaches the members.\n *\n * A plane through four points nearly interpolates them: right at a black/white border, buttons\n * were getting 0.0, 0.3, 0.7 and 1.0 — that is, exactly their own individual values, and the\n * group fell apart into independent elements again. Density is set by the group's LIGHTEST spot;\n * the slope only lets it off slightly at the dark end.\n */\nexport const GRADIENT = 0.35;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * Lightness plane from members' samples. The slope is a least-squares fit along x: the group's\n * members stand in a row, and one axis is enough — there's no vertical spread among them. The\n * coordinates are centered, so the normal equations decouple.\n */\nfunction fitLuma(members: readonly GroupMember[]): {\n mx: number;\n ml: number;\n slope: number;\n} {\n const n = members.length;\n let mx = 0;\n let ml = 0;\n for (const m of members) {\n mx += m.x;\n ml += m.sample.luma;\n }\n mx /= n;\n ml /= n;\n let sxx = 0;\n let sxl = 0;\n for (const m of members) {\n const dx = m.x - mx;\n sxx += dx * dx;\n sxl += dx * m.sample.luma;\n }\n return { mx, ml, slope: sxx > 1e-6 ? sxl / sxx : 0 };\n}\n\n/** Group estimate from its members. An empty group has nothing to estimate — that's `null`. */\nexport function aggregate(\n members: readonly GroupMember[],\n): { plane: GroupPlane; decision: GroupDecision } | null {\n if (members.length === 0) return null;\n\n const { mx, ml, slope } = fitLuma(members);\n let busy = 0;\n let lo = 1;\n let hi = 0;\n // The group's lightest SPOT: density for everyone is computed from it. Otherwise, right at a\n // black/white border the group would hold to the average, a light ink would never darken\n // against anything, and it would drown over the light half.\n let base = 0;\n let r = 0;\n let g = 0;\n let b = 0;\n // The legibility requirement is the group's strictest: polarity is one for all, and going by\n // the weakest requirement would leave a neighbor with pickier optics illegible.\n let legibility = 0;\n for (const m of members) {\n busy = Math.max(busy, m.sample.busy);\n lo = Math.min(lo, m.sample.lo);\n hi = Math.max(hi, m.sample.hi);\n base = Math.max(base, m.sample.luma);\n r += m.sample.r;\n g += m.sample.g;\n b += m.sample.b;\n legibility = Math.max(legibility, m.legibility);\n }\n const k = members.length;\n return {\n plane: { mx, ml, slope, base, rest: [busy, lo, hi, r / k, g / k, b / k] },\n // The polarity decision is one per group, by its AVERAGE lightness. Deciding on its own,\n // each button used to end up a different color over a busy backdrop.\n decision: { decisive: ml * 0.75 + hi * 0.25, legibility },\n };\n}\n\n/**\n * Smoothing runs over samples, not frames: the native lens smooths ITS OWN estimate, and the\n * group estimate overrides it with an already-finished value. Without this the group's tone\n * changed in steps — the probe's 180 ms cadence is too coarse for the adaptation to read as\n * unnoticeable.\n */\nexport function smoothPlane(prev: GroupPlane | null, next: GroupPlane): GroupPlane {\n if (!prev) return next;\n const e = (was: number, now: number) =>\n Math.abs(now - was) < SETTLE ? now : was + (now - was) * SMOOTH;\n const ml = e(prev.ml, next.ml);\n const slope = e(prev.slope, next.slope);\n const base = e(prev.base, next.base);\n const rest = next.rest.map((v, i) => e(prev.rest[i], v));\n // A converged estimate is handed back as the same object: otherwise `setPlane` would repaint\n // the group on every sample — twenty times a second, even on a still screen.\n const same =\n next.mx === prev.mx &&\n ml === prev.ml &&\n slope === prev.slope &&\n base === prev.base &&\n rest.every((v, i) => v === prev.rest[i]);\n return same ? prev : { mx: next.mx, ml, slope, base, rest };\n}\n\n/** The sample a member at position `x` hands its own lens — in the order of its prop. */\nexport function probeValuesAt(plane: GroupPlane, x: number): number[] {\n // Down from the group's lightest spot — by exactly as much as that spot is darker along the\n // plane, and even then only a GRADIENT fraction of it. This lets the dark end off on density,\n // without canceling it: the group stays a single material.\n const here = plane.ml + plane.slope * (x - plane.mx);\n const luma = clamp01(plane.base - (plane.base - here) * GRADIENT);\n // The slope doesn't carry over into the lens: the group's is measured in screen dp, while the\n // shader multiplies `u_probeSlope` by a normalized position within the element — different\n // units.\n return [luma, plane.rest[0], plane.rest[1], plane.rest[2], 0, 0, plane.rest[3], plane.rest[4], plane.rest[5]];\n}\n\n/** Whether the group needs to flip ink polarity given the current one (1 light, 0 dark). */\nfunction wantsPolarityChange(decision: GroupDecision, polarity: number): boolean {\n return polarity === 1 ? decision.decisive >= FLIP_LUMA : decision.decisive < RETURN_LUMA;\n}\n\nexport type GroupSink = {\n /** The group estimate has been recomputed: members take their values from it. */\n plane: (plane: GroupPlane | null) => void;\n /** The group flips ink polarity for everyone at once. */\n flip: (polarity: number) => void;\n};\n\nexport type GroupState = {\n report: (\n id: string,\n x: number,\n y: number,\n sample: BackdropSample,\n legibility: number,\n ) => void;\n release: (id: string) => void;\n plane: () => GroupPlane | null;\n polarity: () => number;\n confirmations: () => number;\n};\n\n/** Group state: members, the smoothed estimate, and polarity hysteresis. */\nexport function createGroupState(sink: GroupSink): GroupState {\n const members = new Map<string, GroupMember>();\n let plane: GroupPlane | null = null;\n let pending = 0;\n let polarity = 1;\n\n const measure = (): GroupDecision | null => {\n const next = aggregate([...members.values()]);\n if (!next) {\n pending = 0;\n plane = null;\n sink.plane(null);\n return null;\n }\n plane = smoothPlane(plane, next.plane);\n sink.plane(plane);\n return next.decision;\n };\n\n return {\n report(id, x, y, sample, legibility) {\n members.set(id, { x, y, sample, legibility });\n const decision = measure();\n if (!decision) return;\n if (!wantsPolarityChange(decision, polarity)) {\n pending = 0;\n return;\n }\n pending += 1;\n if (pending < CONFIRMATIONS) return;\n pending = 0;\n polarity = polarity === 1 ? 0 : 1;\n sink.flip(polarity);\n },\n // Only recomputes the estimate: losing a member isn't a backdrop sample and can't count as a\n // polarity confirmation — unmounting the group used to rack up CONFIRMATIONS instantly and\n // trigger a recolor nobody was left to cancel.\n release(id) {\n if (members.delete(id)) measure();\n },\n plane: () => plane,\n polarity: () => polarity,\n confirmations: () => pending,\n };\n}\n","// A row of glass that agrees with itself.\n//\n// Each element probing on its own is not merely wasteful — it is wrong. Neighbouring pieces of one\n// control sit over slightly different patches of backdrop, reach different polarities, and a tab\n// bar ends up with two light glyphs and two dark ones. §3 is explicit that small elements switch\n// WHOLESALE; a group is what \"wholesale\" means when the element is really four of them.\n//\n// Every decision is the core's (`../group-model`): the lightness plane, the smoothing, the polarity\n// requirement and its hysteresis. This binds them to real elements.\nimport { createGroupState, type GroupPlane } from '../group-model';\nimport { TOUCH } from '../law';\nimport { probeBackdrop } from './probe';\nimport type { BackdropSample } from '../adaptation';\nimport type { GlassHandle } from './index';\n\nexport type GroupEntry = {\n el: HTMLElement;\n handle: GlassHandle;\n /** Set by the group: pass it to this member's own `attachGlass` as `onGlow`. */\n onGlow?: (glow: { pageX: number; pageY: number; strength: number } | null) => void;\n /** How strongly this member needs its ink to stay legible. The strictest in the group wins. */\n legibility?: number;\n};\n\nexport type GlassGroupHandle = {\n /** Re-read every member and settle on one answer for all of them. */\n update(): void;\n /** The polarity the whole group agreed on, 1 light and 0 dark. */\n ink(): number;\n /** The group's current estimate, or null before the first reading. */\n plane(): GroupPlane | null;\n /** Spread a glow from one member to the rest. Members wired through `onGlow` call this for you. */\n carryGlow(from: number, glow: { pageX: number; pageY: number; strength: number } | null): void;\n destroy(): void;\n};\n\nexport type GlassGroupOptions = {\n /** Where a member reads its backdrop. Defaults to the DOM probe. */\n probe?: (el: HTMLElement) => BackdropSample;\n};\n\nexport function createGlassGroup(\n members: readonly GroupEntry[],\n opts: GlassGroupOptions = {},\n): GlassGroupHandle {\n let polarity = 1;\n let destroyed = false;\n\n const state = createGroupState({\n plane: () => {},\n flip: (next) => {\n polarity = next;\n // One flip, everyone at once — that is the whole point of the group.\n for (const { handle } of members) handle.update();\n },\n });\n\n /**\n * \"Starting right under your fingertips, the glow spreads throughout the element and onto any\n * Liquid Glass elements nearby\" (§5, 219 @12:11). The element being touched cannot know who is\n * nearby; the group does.\n */\n function carryGlow(from: number, glow: { pageX: number; pageY: number; strength: number } | null): void {\n members.forEach(({ el, handle }, index) => {\n if (index === from) return;\n if (!glow) {\n handle.setNeighbourGlow(null);\n return;\n }\n const rect = el.getBoundingClientRect();\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n const reach = (Math.min(rect.width, rect.height) / 2) * TOUCH.glowReach;\n const distance = Math.hypot(glow.pageX - cx, glow.pageY - cy);\n // Falls off with distance and stops: a glow that reached the whole screen would read as the\n // page flashing rather than as light travelling through neighbouring glass.\n const falloff = reach > 0 ? Math.max(0, 1 - distance / reach) : 0;\n handle.setNeighbourGlow(falloff <= 0 ? null : { ...glow, strength: glow.strength * falloff });\n });\n }\n\n /** Wire each member's own touch to the rest of the group. */\n function connect(): void {\n members.forEach((entry, index) => {\n entry.onGlow = (glow) => carryGlow(index, glow);\n });\n }\n\n function update(): void {\n if (destroyed) return;\n const probe = opts.probe ?? probeBackdrop;\n members.forEach(({ el, legibility }, index) => {\n const rect = el.getBoundingClientRect();\n // A member with no box has nothing behind it to read; reporting it anyway would drag the\n // group's estimate toward whatever sits at the page's origin.\n if (rect.width <= 0 || rect.height <= 0) {\n state.release(String(index));\n return;\n }\n state.report(\n String(index),\n rect.left + rect.width / 2,\n rect.top + rect.height / 2,\n probe(el),\n legibility ?? 0,\n );\n });\n }\n\n connect();\n update();\n\n return {\n update,\n ink: () => polarity,\n plane: () => state.plane(),\n carryGlow,\n destroy() {\n destroyed = true;\n carryGlow(-1, null);\n members.forEach((_, index) => state.release(String(index)));\n },\n };\n}\n","// The third VireGlass renderer: refracts LIVE DOM via `backdrop-filter: url(#svg-filter)` with an\n// `feDisplacementMap`, instead of drawing its own backdrop like the WebGL2 and AGSL renderers do.\n//\n// Everything is derived from the same model the shaders read, and where a law already exists in\n// the core or in the shader text, this mirrors it rather than restating it: the rim's two arcs are\n// the lens's own key-light lobe, the shadow is `shadowOpacityFrom`, dispersion is the shader's\n// per-channel index shift, and the finger response is `createDeform` driving the same `touchWarp`.\n//\n// Even the spectral edge, which looked impossible: a filter graph cannot evaluate a function per\n// pixel, but it can MULTIPLY by an image, so diffraction and interference are baked into one and\n// applied with an arithmetic composite.\n// See `docs/superpowers/specs/2026-09-19-vireglass-over-live-dom.md` for the technique and the\n// three findings that make it work (objectBoundingBox, prefiltering the source, the 8-bit step).\nimport { ambientFrom, INK_DARK, INK_LIGHT, shouldInkBeLight, type BackdropSample } from '../adaptation';\nimport { buildDisplacementMap } from './displacement';\nimport { buildSpectralMap, hasSpectralEdge, type SpectralMap } from './spectral-map';\nimport { cached } from './map-cache';\nimport { roundedRectGeometry, type VireGlassGeometry } from '../geometry';\nimport { resolveOptics, VIREGLASS_MATERIAL, type VireGlassMaterial, type VireGlassOptics } from '../material';\nimport { probeBackdrop } from './probe';\nimport { supportsSvgBackdropFilter } from './support';\nimport { boxShadowCss } from './shadow';\nimport { bodyLayer, resolveBody, withPresence } from './body';\nimport { systemAccessibility, watchAccessibility } from './preferences';\nimport { applyAccessibility, contrastRimLuma, elasticAllowed, type VireGlassAccessibility } from '../accessibility';\nimport { applyGlassScale, GLASS_SCALE_DEFAULT } from '../glass-scale';\nimport { applyAppear } from '../appear';\nimport { accentAmount, accentTone } from '../accent';\nimport type { VireGlassAccent } from '../adapters';\nimport { concentricRadius } from '../concentric';\nimport { RIM_WIDTH_PX, contrastRimCss, rimGradientCss } from './rim';\nimport { GLASS_ATTR, warnIfNested } from './nesting';\nimport { holdProperty } from './style-hold';\nimport { REST_LIGHT } from '../adapters';\nimport { refractionStrength } from '../optics';\nimport { DISPERSION, TOUCH } from '../law';\nimport type { MorphShape } from '../sdf';\nimport { createDeform, raiseIntoGlass, type DeformSample } from '../touch-response';\nimport { halfMinDp, MAX_STRETCH } from '../geometry';\n\nexport * from './support';\nexport * from './probe';\nexport * from './displacement';\nexport * from './rim';\nexport * from './shadow';\nexport * from './body';\nexport * from './preferences';\nexport * from './scroll-edge';\nexport * from './group';\nexport * from './spectral-map';\nexport * from './map-cache';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst FILTER_HOST_ATTR = 'data-vireglass-filters';\n\nlet filterCounter = 0;\n\n/** Live instances keyed by element, so a second attach can retire the first rather than orphan\n * its filter. Weak: a detached element takes its entry with it. */\nconst attached = new WeakMap<HTMLElement, GlassHandle>();\n\nconst TOUCH_RADIUS_FRACTION = TOUCH.radiusOfHalfSize;\n\nconst WAVE_OF_TRAVEL = TOUCH.waveOfTravel;\nconst RELEASE_WAVE = TOUCH.releaseWave;\n\nfunction waveImpulse(g: VireGlassGeometry): number {\n return halfMinDp(g) * MAX_STRETCH * WAVE_OF_TRAVEL;\n}\n\nconst STYLE_ATTR = 'data-vireglass-styles';\n\n\n/**\n * The hairline rim (docs/reference.md §2) needs a layer of its own over the element. A stylesheet\n * rule on `::after` keeps it out of the host's markup — injecting a child node would fight any\n * framework that owns these children.\n *\n * The mask pair is what makes it a ring rather than a fill: the same box painted twice, once\n * clipped to the content box, composited so only the padding band survives.\n */\n/**\n * Where the filter and the rim styles go.\n *\n * `backdrop-filter: url(#id)` resolves the reference in the element's OWN tree. From inside a\n * shadow root, a filter parked on the page is not found — and the failure is silent, because the\n * reference is valid CSS: the element gets no backdrop at all, not even the blur fallback. A\n * widget in a shadow root (which is how you survive a page full of global `!important`) came out\n * with no material whatsoever.\n *\n * So the host is the element's own root node, which is the shadow root when there is one and the\n * document otherwise. Nothing to configure and nothing to get wrong.\n */\nfunction hostFor(el: Element): Document | ShadowRoot {\n const root = el.getRootNode();\n return root instanceof ShadowRoot ? root : el.ownerDocument ?? document;\n}\n\n/** A shadow root has no `<head>`; a style element goes straight into it. */\nfunction styleParent(host: Document | ShadowRoot): Node {\n return host instanceof ShadowRoot ? host : host.head;\n}\n\nfunction ensureRimStyles(host: Document | ShadowRoot): void {\n if (host.querySelector(`style[${STYLE_ATTR}]`)) return;\n const style = document.createElement('style');\n style.setAttribute(STYLE_ATTR, '');\n style.textContent =\n `[${GLASS_ATTR}]::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;padding:var(--vireglass-rim-width,1px);background:var(--vireglass-rim,none);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}` +\n // The touch glow (§5) lights the material from the point of contact. Below the content, above\n // the refraction — it is light inside the glass, not a film over the label.\n `[${GLASS_ATTR}]::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:var(--vireglass-glow,none);opacity:var(--vireglass-glow-opacity,0)}`;\n styleParent(host).appendChild(style);\n}\n\nfunction getFilterHost(host: Document | ShadowRoot): SVGSVGElement {\n const existing = host.querySelector<SVGSVGElement>(`svg[${FILTER_HOST_ATTR}]`);\n if (existing) return existing;\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute(FILTER_HOST_ATTR, '');\n svg.setAttribute('width', '0');\n svg.setAttribute('height', '0');\n svg.setAttribute('aria-hidden', 'true');\n svg.style.position = 'absolute';\n svg.style.pointerEvents = 'none';\n svg.appendChild(document.createElementNS(SVG_NS, 'defs'));\n // A shadow root takes the svg directly; a document takes it on the body.\n (host instanceof ShadowRoot ? host : host.body).appendChild(svg);\n return svg;\n}\n\n/**\n * Finding #1 (do not re-litigate): `objectBoundingBox` with an explicit unit box. `userSpaceOnUse`\n * measures from something other than the element's own box and the displacement smears across\n * the page instead of staying at the rim.\n */\nfunction buildFilterElement(\n id: string,\n mapUrl: string,\n optics: VireGlassOptics,\n scale: number,\n spectral: SpectralMap | null,\n): SVGFilterElement {\n const filter = document.createElementNS(SVG_NS, 'filter');\n filter.setAttribute('id', id);\n filter.setAttribute('filterUnits', 'objectBoundingBox');\n filter.setAttribute('x', '0');\n filter.setAttribute('y', '0');\n filter.setAttribute('width', '1');\n filter.setAttribute('height', '1');\n // Without this the spec's default is linearRGB: the browser gamma-linearises the map's bytes\n // before reading them, so 128 stops meaning \"no shift\" and the flat middle of the glass drifts\n // by several pixels. Measured at ~57px of spurious displacement at scale 200.\n filter.setAttribute('color-interpolation-filters', 'sRGB');\n\n const feImage = document.createElementNS(SVG_NS, 'feImage');\n feImage.setAttribute('href', mapUrl);\n feImage.setAttribute('preserveAspectRatio', 'none');\n feImage.setAttribute('result', 'map');\n\n // Finding #2: prefiltering the source before displacement. This is `roughness`, not a hack —\n // without it, fine texture (1px diagonals) resamples into chevrons under the displacement.\n const feBlur = document.createElementNS(SVG_NS, 'feGaussianBlur');\n feBlur.setAttribute('in', 'SourceGraphic');\n feBlur.setAttribute('stdDeviation', String(Math.max(optics.blur, 0)));\n feBlur.setAttribute('result', 'blurred');\n\n filter.append(feImage, feBlur);\n\n // DISPERSION (docs/reference.md §1, and `lens-shader.ts` lines 283–284 for the law): the channels\n // refract at different indices — red at `ior - 0.4 * iorSpread`, blue at `ior + 0.6 * iorSpread`,\n // green at the base. One displacement pass cannot do that, so each channel gets its own and they\n // are summed back. Three passes instead of one, so it only runs when the spread is worth paying\n // for.\n const spread = optics.iorSpread;\n if (spread > 1e-4) {\n const base = refractionStrength(optics.ior);\n const ratio = (shift: number) => (base > 0 ? refractionStrength(optics.ior + shift) / base : 1);\n const channels: Array<[string, number, string]> = [\n ['dR', scale * ratio(DISPERSION.redShift * spread), '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'],\n ['dG', scale, '0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0'],\n ['dB', scale * ratio(DISPERSION.blueShift * spread), '0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0'],\n ];\n for (const [name, chScale, matrix] of channels) {\n const pass = document.createElementNS(SVG_NS, 'feDisplacementMap');\n pass.setAttribute('in', 'blurred');\n pass.setAttribute('in2', 'map');\n pass.setAttribute('scale', String(chScale));\n pass.setAttribute('xChannelSelector', 'R');\n pass.setAttribute('yChannelSelector', 'G');\n pass.setAttribute('result', `${name}raw`);\n // Each channel displaces by its own share of the base scale. The share is stored on the\n // element itself: under a press the scale is recomputed every frame, with nowhere else to\n // recover the shares from.\n pass.setAttribute('data-vireglass-ratio', String(scale > 0 ? chScale / scale : 1));\n const only = document.createElementNS(SVG_NS, 'feColorMatrix');\n only.setAttribute('in', `${name}raw`);\n only.setAttribute('type', 'matrix');\n only.setAttribute('values', matrix);\n only.setAttribute('result', name);\n filter.append(pass, only);\n }\n // Arithmetic add, not a blend: every channel is isolated, so the sum is the recombined colour.\n // Alpha stays at 1 on all three and clamps, which is what an opaque backdrop wants.\n const rg = document.createElementNS(SVG_NS, 'feComposite');\n rg.setAttribute('in', 'dR');\n rg.setAttribute('in2', 'dG');\n rg.setAttribute('operator', 'arithmetic');\n rg.setAttribute('k1', '0');\n rg.setAttribute('k2', '1');\n rg.setAttribute('k3', '1');\n rg.setAttribute('k4', '0');\n rg.setAttribute('result', 'dRG');\n const rgb = document.createElementNS(SVG_NS, 'feComposite');\n rgb.setAttribute('in', 'dRG');\n rgb.setAttribute('in2', 'dB');\n rgb.setAttribute('operator', 'arithmetic');\n rgb.setAttribute('k1', '0');\n rgb.setAttribute('k2', '1');\n rgb.setAttribute('k3', '1');\n rgb.setAttribute('k4', '0');\n rgb.setAttribute('result', 'refracted');\n filter.append(rg, rgb);\n return withSpectral(filter, spectral);\n }\n\n const feDisplace = document.createElementNS(SVG_NS, 'feDisplacementMap');\n feDisplace.setAttribute('in', 'blurred');\n feDisplace.setAttribute('in2', 'map');\n feDisplace.setAttribute('scale', String(scale));\n feDisplace.setAttribute('xChannelSelector', 'R');\n feDisplace.setAttribute('yChannelSelector', 'G');\n feDisplace.setAttribute('result', 'refracted');\n filter.append(feDisplace);\n return withSpectral(filter, spectral);\n}\n\n/**\n * Multiplies the refracted frame by the baked hue (docs/reference.md §1). `feComposite` in\n * arithmetic mode with `k1` is a per-pixel product, which is the only way a filter graph can apply\n * a function of position. The headroom the bake divided by is multiplied back here.\n */\nfunction withSpectral(filter: SVGFilterElement, spectral: SpectralMap | null): SVGFilterElement {\n if (!spectral) return filter;\n const image = document.createElementNS(SVG_NS, 'feImage');\n image.setAttribute('href', spectral.url);\n image.setAttribute('preserveAspectRatio', 'none');\n image.setAttribute('result', 'hue');\n const product = document.createElementNS(SVG_NS, 'feComposite');\n product.setAttribute('in', 'refracted');\n product.setAttribute('in2', 'hue');\n product.setAttribute('operator', 'arithmetic');\n product.setAttribute('k1', String(spectral.headroom));\n product.setAttribute('k2', '0');\n product.setAttribute('k3', '0');\n product.setAttribute('k4', '0');\n filter.append(image, product);\n return filter;\n}\n\nfunction measureGeometry(el: HTMLElement): VireGlassGeometry {\n const rect = el.getBoundingClientRect();\n // Uniform corner radius only, matching `VireGlassGeometry` itself — a per-corner or elliptical\n // radius isn't modeled by any renderer in this package.\n const radius = parseFloat(getComputedStyle(el).borderTopLeftRadius) || 0;\n return roundedRectGeometry(rect.width, rect.height, radius);\n}\n\nfunction devicePixelRatio(): number {\n return typeof window !== 'undefined' && window.devicePixelRatio ? window.devicePixelRatio : 1;\n}\n\n/**\n * No SVG filter reference support (Firefox, older Safari): a real path, not a stub — the Android\n * renderer degrades to an affine magnifier below API 33 and that's documented as normal too. Blur\n * and saturation stand in for refraction's optical effect; the tint carries what refraction can't:\n * a body of glass, not just a smudge over whatever's behind it.\n */\nfunction fallbackFilterCss(optics: VireGlassOptics): string {\n const blurPx = Math.max(optics.blur, 1.5);\n const saturate = 1 + optics.colorPickup;\n return `blur(${blurPx}px) saturate(${saturate})`;\n}\n\nconst to255 = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * 255);\n\nfunction rgbCss(r: number, g: number, b: number): string {\n return `rgb(${to255(r)} ${to255(g)} ${to255(b)})`;\n}\n\n/**\n * The body, from the model's own law (`./body`, ported from the lens shader §3): density is what\n * legibility and presence demand over THIS backdrop, the tint is the lightness it tints toward,\n * and the hue is the surroundings' — glass has no colour of its own, only the colour of what lies\n * beneath it. A flat fill in place of a tint is what breaks the material.\n */\nfunction bodyCss(\n optics: VireGlassOptics,\n sample: BackdropSample,\n ink: number,\n accent: VireGlassAccent | undefined,\n appear: number,\n): string {\n // A tinted element takes its colour from the accent rather than from its surroundings, but it is\n // still the MEDIUM that is coloured: the amount stays short of one so the content keeps coming\n // through. A fill at full opacity is the thing §7 says breaks the material.\n if (accent) {\n const settled = applyAppear(optics, appear);\n const body = withPresence(resolveBody(settled, sample, ink), settled, sample);\n const [r, g, b] = accentTone(accent.color, sample.luma);\n const amount = Math.max(accentAmount(accent), body.density);\n return `rgba(${to255(r)}, ${to255(g)}, ${to255(b)}, ${amount.toFixed(3)})`;\n }\n\n const layer = bodyLayer(optics, sample, ink, ambientFrom(sample), appear);\n return `rgba(${to255(layer.r)}, ${to255(layer.g)}, ${to255(layer.b)}, ${layer.alpha.toFixed(3)})`;\n}\n\nexport type AttachGlassOptions = {\n material?: Partial<VireGlassMaterial>;\n /** Defaults to the element's measured box (size + `border-radius`). */\n geometry?: VireGlassGeometry;\n /** Key-light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** Whether `attachGlass` writes `box-shadow` itself. Turn it off if the host owns that property —\n * is always emitted either way. */\n shadow?: boolean;\n /**\n * The user's clear-to-tinted preference (§3). iOS 27 made it continuous and apps get it without\n * recompiling, so the material has to stay usable across the WHOLE range, not at one point.\n */\n scale?: number;\n /** System accessibility (§9). Read from the browser's own media queries unless supplied. */\n accessibility?: VireGlassAccessibility;\n /**\n * Tint for a primary action (§7). A colour that belongs to the medium, generating a range of\n * tones from the backdrop's brightness — not a fill. Use it on the one element that should stand\n * out: \"when every element is tinted, nothing stands out\" (219 @17:31).\n */\n accent?: VireGlassAccent;\n /** Initial presence, 0 to 1 (§1). Defaults to fully present. */\n appear?: number;\n /**\n * `'interactive'` is glass that is not there until it is touched (S 42:34, \"Building Tide Guide\"): \"this effect doesn't\n * change the appearance of a view until you interact with it... as you start sliding it, the\n * interactive effect adds a soft, subtle highlight\". The element carries no material at rest and\n * materialises under the finger — §1's materialising, driven by touch instead of by the host.\n *\n * It is what makes glass usable on a control that is not chrome: a slider thumb, a chart scrubber,\n * a card. Permanent glass there would be glass in the content layer, which §6 says to avoid.\n */\n variant?: 'present' | 'interactive';\n /** Called while this element is being touched, so a group can carry the glow to its neighbours\n * (§5). Wired for you by `createGlassGroup`. */\n onGlow?: (glow: { pageX: number; pageY: number; strength: number } | null) => void;\n /** Pointer response (§5). On by default. */\n interactive?: boolean;\n /**\n * Overrides the probe entirely. The probe reads declared backgrounds, so images, video and\n * canvases are invisible to it; a host that knows its backdrop (a cover's accent, a gradient)\n * states it here, and changes it later with `setSample`. `statsFromSamples` builds one from\n * a handful of colours.\n */\n sample?: BackdropSample;\n /**\n * Whether `attachGlass` paints the body as the element's `background-color`. On by default;\n * turn it off if the host owns that property — `--vireglass-body-color` is always emitted\n * either way and carries the same colour.\n */\n body?: boolean;\n};\n\n/**\n * Shapes this element flows into (docs/reference.md §5): merging with a neighbour, or splitting\n * into parts across two bridges. Offsets and sizes are CSS px relative to this element's centre.\n *\n * `smoothing` is the width of the bridge — zero leaves the element alone. What each shape MEANS\n * (a menu growing out of its button, a control breaking into segments) is the host's choreography;\n * the material only knows how two silhouettes join.\n */\nexport type GlassMorph = {\n smoothing: number;\n shape?: MorphShape;\n shape2?: MorphShape;\n /**\n * Any number of shapes flowing into this one. Several independent elements becoming one whole is\n * the behaviour; how many of them there are is the host's business, and it used to be the\n * material's — the count lived in the field NAMES, so a fourth element had nowhere to go.\n *\n * `shape` and `shape2` still work and come first.\n */\n shapes?: readonly MorphShape[];\n};\n\nexport type GlassHandle = {\n update(): void;\n /**\n * How present the material is, 0 to 1 (docs/reference.md §1). Drive this to bring glass in and\n * out — NOT opacity. \"Instead of fading, Liquid Glass objects materialize in and out by\n * gradually modulating the light bending and lensing\" (219 @2:55). A faded element shows the\n * backdrop through a veil; one that is still arriving shows it undistorted.\n */\n setAppear(t: number): void;\n /** Tint the element, or clear it with null (§7). */\n setAccent(accent: VireGlassAccent | null): void;\n /** A glow that started on a neighbour, in page coordinates (§5). Null clears it. */\n setNeighbourGlow(glow: { pageX: number; pageY: number; strength: number } | null): void;\n setMorph(morph: GlassMorph | null): void;\n /**\n * Replaces the backdrop the glass adapts to, without re-attaching, and repaints. The same\n * object as `sample` in the options; `null` goes back to probing declared backgrounds.\n */\n setSample(sample: BackdropSample | null): void;\n destroy(): void;\n};\n\nexport function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): GlassHandle {\n if (typeof document === 'undefined') {\n throw new Error('vireglass/dom: attachGlass requires a browser DOM');\n }\n\n // One live instance per element. Re-attaching without destroying the previous handle used to\n // leave its filter in the shared <defs> forever, unreferenced, while the element quietly moved\n // to the new id.\n attached.get(el)?.destroy();\n\n const id = `vireglass-filter-${(filterCounter += 1)}`;\n const svgSupported = supportsSvgBackdropFilter();\n let wasLight = (opts.material?.ink ?? VIREGLASS_MATERIAL.ink) > 0.5;\n let filterEl: SVGFilterElement | null = null;\n let destroyed = false;\n let mapKey = '';\n let morph: GlassMorph | null = null;\n const onlyWhenTouched = opts.variant === 'interactive';\n let appear = onlyWhenTouched ? 0 : (opts.appear ?? 1);\n let accent = opts.accent;\n let supplied = opts.sample;\n // Read once at attach, then followed: a setting turned on while the page is open has to reach\n // the material, not wait for a reload.\n let a11y = systemAccessibility();\n const stopWatchingA11y = watchAccessibility((next) => {\n a11y = next;\n mapKey = '';\n deform.setElastic(elasticAllowed(opts.accessibility ?? a11y));\n apply();\n });\n\n warnIfNested(el);\n\n // The element's own tree: a shadow root when it is in one, the document otherwise.\n const host = hostFor(el);\n ensureRimStyles(host);\n el.setAttribute(GLASS_ATTR, '');\n // `inset: 0` on the rim needs a positioned ancestor. Only taken over when the host left it at\n // the initial value, and put back on destroy.\n const restoreBackground = holdProperty(el.style, 'background-color');\n const positionWasStatic = getComputedStyle(el).position === 'static';\n if (positionWasStatic) el.style.setProperty('position', 'relative');\n\n /**\n * Causes to effects, then the user's scale, then accessibility — in that order. §9 is explicit\n * that a system setting outranks the material preset: even a transparent preset moves to the\n * edge of the scale under increased contrast, because the user needs contrast more than they\n * need the aesthetic.\n */\n function settledOptics(patch?: Partial<VireGlassMaterial>): VireGlassOptics {\n const base = resolveOptics(patch ?? opts.material);\n const scaled = applyGlassScale(base, opts.scale ?? GLASS_SCALE_DEFAULT);\n return applyAccessibility(scaled, opts.accessibility ?? a11y);\n }\n\n function optics(patch?: Partial<VireGlassMaterial>): VireGlassOptics {\n // Appearance last, and by modulating the lens rather than by fading the element: §1 is\n // explicit that opacity is the wrong instrument for this.\n return applyAppear(settledOptics(patch), appear);\n }\n\n function morphState() {\n if (!morph) return {};\n return { smoothing: morph.smoothing, morph: morph.shape, morph2: morph.shape2, morphs: morph.shapes };\n }\n\n function morphKey(): string {\n if (!morph) return '0';\n const part = (s?: MorphShape) =>\n s ? `${s.offsetX},${s.offsetY},${s.width},${s.height},${s.cornerRadius}` : '-';\n return `${morph.smoothing}/${part(morph.shape)}/${part(morph.shape2)}`;\n }\n\n function apply(): void {\n if (destroyed) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n const opticsNow = optics();\n const sample = supplied ?? probeBackdrop(el);\n const light = shouldInkBeLight(sample, wasLight);\n wasLight = light;\n const body = opts.body === false ? null : bodyCss(settledOptics(), sample, light ? 1 : 0, accent, appear);\n\n if (svgSupported) {\n // The map depends only on geometry, optics and density — never on the backdrop. Rebuilding\n // it on every scroll would re-run a per-pixel loop and a PNG encode for a picture that did\n // not change; the refraction itself updates in the compositor with no JS at all.\n const key = `a${appear.toFixed(3)}|m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}:${opticsNow.blur}`;\n if (key !== mapKey || !filterEl) {\n // Keyed by exactly what the maps are functions of, which is exactly the cache key above.\n const map = cached(`d|${key}`, () => buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState()));\n const defs = getFilterHost(host).querySelector('defs') as SVGDefsElement;\n const hue = hasSpectralEdge(opticsNow)\n ? cached(`h|${key}`, () => buildSpectralMap(opticsNow, geometry, devicePixelRatio()))\n : null;\n const next = buildFilterElement(id, map.url, opticsNow, map.scale, hue);\n if (filterEl?.parentNode) defs.replaceChild(next, filterEl);\n else defs.appendChild(next);\n filterEl = next;\n mapKey = key;\n }\n el.style.setProperty('backdrop-filter', `url(#${id})`);\n el.style.setProperty('-webkit-backdrop-filter', `url(#${id})`);\n } else {\n el.style.setProperty('backdrop-filter', fallbackFilterCss(opticsNow));\n el.style.setProperty('-webkit-backdrop-filter', fallbackFilterCss(opticsNow));\n }\n if (body) el.style.backgroundColor = body;\n\n const [tr, tg, tb] = ambientFrom(sample);\n el.style.setProperty('--vireglass-ink', light ? '1' : '0');\n el.style.setProperty('--vireglass-tint', `${tr} ${tg} ${tb}`);\n el.style.setProperty('--vireglass-body-density', String(opticsNow.bodyDensity));\n\n // The raw numbers above are the model's own values; these are the same thing in a form CSS\n // can actually consume. Without them a host has to convert in script, which is the work this\n // renderer exists to do.\n const inkLevel = Math.round((light ? INK_LIGHT : INK_DARK) * 255);\n el.style.setProperty('--vireglass-ink-color', `rgb(${inkLevel} ${inkLevel} ${inkLevel})`);\n el.style.setProperty('--vireglass-tint-color', rgbCss(tr, tg, tb));\n el.style.setProperty(\n '--vireglass-body-color',\n body ?? bodyCss(settledOptics(), sample, light ? 1 : 0, accent, appear),\n );\n\n // Rim and shadow follow the SAMPLE, not just the geometry, so they sit outside the map's\n // cache key: the environment they take their colour and density from moves under a scroll\n // while the silhouette does not.\n // §9: under increased contrast the hairline stops reporting where the light is and starts\n // separating the element from what is behind it, so it is measured from the body, not the\n // environment.\n const pole = withPresence(resolveBody(opticsNow, sample, light ? 1 : 0), opticsNow, sample).tintLuma;\n el.style.setProperty(\n '--vireglass-rim',\n (opts.accessibility ?? a11y).increaseContrast\n ? contrastRimCss(pole, contrastRimLuma(pole))\n : rimGradientCss(opticsNow, [tr, tg, tb], opts.light ?? REST_LIGHT, appear),\n );\n el.style.setProperty('--vireglass-rim-width', `${RIM_WIDTH_PX}px`);\n\n // §11: a rounded child inside glass has to be concentric with it, or the two curves fight.\n // Emitted rather than applied — the inset is the host's, and CSS can do the arithmetic.\n el.style.setProperty('--vireglass-radius', `${geometry.cornerRadius}px`);\n el.style.setProperty('--vireglass-radius-min', `${concentricRadius(geometry.cornerRadius, geometry.cornerRadius, 0)}px`);\n\n const shadow = boxShadowCss(geometry, sample, appear);\n el.style.setProperty('--vireglass-shadow', shadow);\n if (opts.shadow !== false) el.style.setProperty('box-shadow', shadow);\n }\n\n apply();\n\n // INTERACTION (docs/reference.md §5). The physics is the core's — `createDeform` carries the\n // spring, the press attack and the wave, at its own fixed step. What lives here is only the\n // plumbing: pointer in, map and glow out.\n const deform = createDeform({ elastic: elasticAllowed(opts.accessibility ?? a11y) });\n let frame: number | null = null;\n let lastFrameAt = 0;\n let interacting = false;\n\n function localPoint(e: PointerEvent): [number, number] {\n const rect = el.getBoundingClientRect();\n return [e.clientX - rect.left - rect.width / 2, e.clientY - rect.top - rect.height / 2];\n }\n\n function paintInteraction(sampleOut: DeformSample): void {\n const geometry = opts.geometry ?? measureGeometry(el);\n const base = optics();\n // Under the finger a matte control stops being frosted and becomes a lens (§5, M 4:10–4:30).\n const rise = raiseIntoGlass(sampleOut.press);\n // The same chain as at rest — the user's scale and the system's settings do not stop\n // applying because a finger is down.\n const risen = optics({ ...opts.material, roughness: (opts.material?.roughness ?? VIREGLASS_MATERIAL.roughness) * rise.solid });\n\n // A reduced-resolution map while the finger is down: `feImage` stretches it over the element\n // regardless, the displacement is smooth, and a full device-pixel rebuild plus a PNG encode\n // every frame does not hold a frame budget.\n const map = buildDisplacementMap(risen, geometry, interacting ? 1 : devicePixelRatio(), {\n ...morphState(),\n touch: {\n x: sampleOut.touchX,\n y: sampleOut.touchY,\n pullX: sampleOut.pullX,\n pullY: sampleOut.pullY,\n press: sampleOut.press,\n radius: halfMinDp(geometry) * TOUCH_RADIUS_FRACTION,\n waveAmp: sampleOut.waveAmp,\n wavePhase: sampleOut.wavePhase,\n },\n });\n if (filterEl) {\n const feImage = filterEl.querySelector('feImage');\n feImage?.setAttribute('href', map.url);\n // EVERY pass, not the first. With dispersion there are three at different scales, and\n // querySelector returned only red: under a finger it got the undispersed scale while green\n // and blue kept their attach-time values, and the coloured rim stopped following the finger.\n for (const pass of filterEl.querySelectorAll('feDisplacementMap')) {\n const ratio = Number(pass.getAttribute('data-vireglass-ratio') ?? 1);\n pass.setAttribute('scale', String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));\n }\n }\n mapKey = '';\n\n paintGlow(sampleOut.touchX, sampleOut.touchY, sampleOut.active * base.edgeLight, geometry);\n\n // \"the glow spreads throughout the element and onto any Liquid Glass elements NEARBY\" (§5,\n // 219 @12:11). This element cannot know who is nearby; the group does, so it is told.\n const rect = el.getBoundingClientRect();\n opts.onGlow?.({\n pageX: rect.left + rect.width / 2 + sampleOut.touchX,\n pageY: rect.top + rect.height / 2 + sampleOut.touchY,\n strength: sampleOut.active,\n });\n }\n\n /**\n * The glow is a CONCENTRATION of the surroundings, not the glass's own whiteness: over a dark\n * backdrop the element lightens but never turns white, and ink over it stays legible.\n *\n * `x` and `y` are relative to the element's centre and may fall outside it — a glow that started\n * next door still has a direction, and dropping it to the centre would make a neighbour brighten\n * uniformly rather than from the side the finger is on.\n */\n function paintGlow(x: number, y: number, strength: number, geometry: VireGlassGeometry): void {\n if (strength <= 0.001) {\n el.style.setProperty('--vireglass-glow-opacity', '0');\n return;\n }\n const [gr, gg, gb] = ambientFrom(supplied ?? probeBackdrop(el));\n const cx = ((x + geometry.width / 2) / geometry.width) * 100;\n const cy = ((y + geometry.height / 2) / geometry.height) * 100;\n const reach = halfMinDp(geometry) * TOUCH_RADIUS_FRACTION;\n el.style.setProperty(\n '--vireglass-glow',\n `radial-gradient(circle ${reach.toFixed(0)}px at ${cx.toFixed(1)}% ${cy.toFixed(1)}%, rgba(${to255(gr)},${to255(gg)},${to255(gb)},1) 0%, rgba(${to255(gr)},${to255(gg)},${to255(gb)},0) 100%)`,\n );\n el.style.setProperty('--vireglass-glow-opacity', strength.toFixed(3));\n }\n\n function tick(now: number): void {\n if (destroyed) return;\n const dt = lastFrameAt ? (now - lastFrameAt) / 1000 : 1 / 60;\n lastFrameAt = now;\n deform.step(dt);\n const s = deform.sample();\n // The interactive variant materialises with the touch rather than being held present. `active`\n // rather than `press`: press is the depth of the dent, active is simply whether a finger is\n // there, and the material arriving has to track the second.\n if (onlyWhenTouched) appear = s.active;\n paintInteraction(s);\n if (deform.idle()) {\n interacting = false;\n frame = null;\n lastFrameAt = 0;\n // Settled: put the full-resolution map back and drop the glow.\n el.style.setProperty('--vireglass-glow-opacity', '0');\n opts.onGlow?.(null);\n apply();\n return;\n }\n frame = requestAnimationFrame(tick);\n }\n\n function run(): void {\n if (frame === null && !destroyed) frame = requestAnimationFrame(tick);\n }\n\n let grabX = 0;\n let grabY = 0;\n\n function onDown(e: PointerEvent): void {\n const [x, y] = localPoint(e);\n const geometry = opts.geometry ?? measureGeometry(el);\n interacting = true;\n grabX = x;\n grabY = y;\n // Pointer capture, or a drag that leaves the element stops reporting and the deformation\n // freezes mid-pull with the finger still down.\n el.setPointerCapture?.(e.pointerId);\n deform.grab(x, y, waveImpulse(geometry));\n run();\n }\n function onMove(e: PointerEvent): void {\n if (!interacting) return;\n const [x, y] = localPoint(e);\n const geometry = opts.geometry ?? measureGeometry(el);\n // `drag` takes the travel FROM the grab point, and saturates it against the limit itself.\n deform.drag(x - grabX, y - grabY, halfMinDp(geometry) * MAX_STRETCH);\n run();\n }\n function onUp(e?: PointerEvent): void {\n if (!interacting) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n if (e) el.releasePointerCapture?.(e.pointerId);\n // Lifting throws a second, weaker ring (§5) — the core caps the sum, so this only has to be\n // the smaller impulse.\n deform.release(waveImpulse(geometry) * RELEASE_WAVE);\n run();\n }\n\n if (opts.interactive !== false) {\n el.addEventListener('pointerdown', onDown);\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onUp);\n el.addEventListener('pointercancel', onUp);\n el.addEventListener('pointerleave', onUp);\n }\n\n // The \"listener\" `destroy()` has to remove: geometry defaults to the measured box, so a resize\n // of the element itself has to rebuild the map, or the displacement drifts from the element's\n // actual silhouette as soon as its layout changes.\n let resizeObserver: ResizeObserver | null = null;\n if (!opts.geometry && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => apply());\n resizeObserver.observe(el);\n }\n\n function destroy(): void {\n destroyed = true;\n stopWatchingA11y();\n if (attached.get(el) === handle) attached.delete(el);\n if (frame !== null) cancelAnimationFrame(frame);\n frame = null;\n el.removeEventListener('pointerdown', onDown);\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onUp);\n el.removeEventListener('pointercancel', onUp);\n el.removeEventListener('pointerleave', onUp);\n el.style.removeProperty('--vireglass-glow');\n el.style.removeProperty('--vireglass-glow-opacity');\n resizeObserver?.disconnect();\n resizeObserver = null;\n if (filterEl?.parentNode) filterEl.parentNode.removeChild(filterEl);\n filterEl = null;\n mapKey = '';\n el.style.removeProperty('backdrop-filter');\n el.style.removeProperty('-webkit-backdrop-filter');\n if (opts.body !== false) restoreBackground();\n el.style.removeProperty('--vireglass-ink');\n el.style.removeProperty('--vireglass-tint');\n el.style.removeProperty('--vireglass-body-density');\n el.style.removeProperty('--vireglass-ink-color');\n el.style.removeProperty('--vireglass-tint-color');\n el.style.removeProperty('--vireglass-body-color');\n el.style.removeProperty('--vireglass-rim');\n el.style.removeProperty('--vireglass-rim-width');\n el.style.removeProperty('--vireglass-shadow');\n el.style.removeProperty('--vireglass-radius');\n el.style.removeProperty('--vireglass-radius-min');\n el.style.removeProperty('box-shadow');\n el.removeAttribute(GLASS_ATTR);\n if (positionWasStatic) el.style.removeProperty('position');\n }\n\n const handle: GlassHandle = {\n update: apply,\n setAppear(t) {\n const next = t < 0 ? 0 : t > 1 ? 1 : t;\n if (next === appear) return;\n appear = next;\n apply();\n },\n setAccent(next) {\n accent = next ?? undefined;\n apply();\n },\n setNeighbourGlow(glow) {\n if (destroyed || interacting) return;\n const geometry = opts.geometry ?? measureGeometry(el);\n if (!glow) {\n paintGlow(0, 0, 0, geometry);\n return;\n }\n const rect = el.getBoundingClientRect();\n paintGlow(\n glow.pageX - (rect.left + rect.width / 2),\n glow.pageY - (rect.top + rect.height / 2),\n glow.strength,\n geometry,\n );\n },\n setMorph(next) {\n morph = next && next.smoothing > 0 ? next : null;\n mapKey = '';\n apply();\n },\n setSample(next) {\n supplied = next ?? undefined;\n apply();\n },\n destroy,\n };\n attached.set(el, handle);\n return handle;\n}\n"]}