e11y 0.2.0 → 1.1.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 (288) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +130 -10
  3. data/CHANGELOG.md +80 -1
  4. data/CLAUDE.md +168 -0
  5. data/CONTRIBUTING.md +640 -0
  6. data/README.md +165 -701
  7. data/RELEASE.md +41 -12
  8. data/Rakefile +249 -57
  9. data/config/README.md +1 -1
  10. data/config/loki-local-config.yaml +12 -0
  11. data/config/otel-collector-config.yaml +44 -0
  12. data/cucumber.yml +1 -0
  13. data/docker-compose.yml +18 -2
  14. data/docs/ADAPTERS.md +76 -0
  15. data/docs/ADAPTIVE_SAMPLING.md +59 -0
  16. data/docs/COMPARISON.md +104 -0
  17. data/docs/CONFIGURATION.md +52 -0
  18. data/docs/DISTRIBUTED_TRACING.md +44 -0
  19. data/docs/LIMITATIONS.md +13 -0
  20. data/docs/METRICS_DSL.md +84 -0
  21. data/docs/PERFORMANCE.md +60 -0
  22. data/docs/PII_FILTERING.md +40 -0
  23. data/docs/PRESETS.md +65 -0
  24. data/docs/QUICK-START.md +546 -587
  25. data/docs/RAILS_INTEGRATION.md +79 -0
  26. data/docs/SCHEMA_VALIDATION.md +63 -0
  27. data/docs/SLO-PROMQL-ALERTS.md +161 -0
  28. data/docs/TESTING.md +69 -0
  29. data/docs/{ADR-001-architecture.md → architecture/ADR-001-architecture.md} +36 -65
  30. data/docs/{ADR-002-metrics-yabeda.md → architecture/ADR-002-metrics-yabeda.md} +62 -236
  31. data/docs/architecture/ADR-003-slo-observability.md +1402 -0
  32. data/docs/{ADR-004-adapter-architecture.md → architecture/ADR-004-adapter-architecture.md} +163 -146
  33. data/docs/{ADR-005-tracing-context.md → architecture/ADR-005-tracing-context.md} +10 -9
  34. data/docs/{ADR-006-security-compliance.md → architecture/ADR-006-security-compliance.md} +184 -191
  35. data/docs/{ADR-007-opentelemetry-integration.md → architecture/ADR-007-opentelemetry-integration.md} +3 -21
  36. data/docs/{ADR-008-rails-integration.md → architecture/ADR-008-rails-integration.md} +182 -743
  37. data/docs/{ADR-009-cost-optimization.md → architecture/ADR-009-cost-optimization.md} +45 -54
  38. data/docs/architecture/ADR-010-developer-experience.md +522 -0
  39. data/docs/{ADR-011-testing-strategy.md → architecture/ADR-011-testing-strategy.md} +44 -86
  40. data/docs/{ADR-012-event-evolution.md → architecture/ADR-012-event-evolution.md} +11 -11
  41. data/docs/{ADR-013-reliability-error-handling.md → architecture/ADR-013-reliability-error-handling.md} +37 -12
  42. data/docs/{ADR-014-event-driven-slo.md → architecture/ADR-014-event-driven-slo.md} +12 -24
  43. data/docs/{ADR-015-middleware-order.md → architecture/ADR-015-middleware-order.md} +43 -59
  44. data/docs/{ADR-016-self-monitoring-slo.md → architecture/ADR-016-self-monitoring-slo.md} +58 -355
  45. data/docs/{ADR-017-multi-rails-compatibility.md → architecture/ADR-017-multi-rails-compatibility.md} +4 -11
  46. data/docs/architecture/ADR-018-memory-optimization.md +366 -0
  47. data/docs/{ADR-INDEX.md → architecture/ADR-INDEX.md} +11 -6
  48. data/docs/plans/2026-03-20-browser-overlay-svelte.md +281 -0
  49. data/docs/{00-ICP-AND-TIMELINE.md → prd/00-ICP-AND-TIMELINE.md} +6 -6
  50. data/docs/{01-SCALE-REQUIREMENTS.md → prd/01-SCALE-REQUIREMENTS.md} +6 -6
  51. data/docs/prd/01-overview-vision.md +19 -14
  52. data/docs/use_cases/README.md +22 -23
  53. data/docs/use_cases/UC-001-request-scoped-debug-buffering.md +50 -44
  54. data/docs/use_cases/UC-002-business-event-tracking.md +26 -95
  55. data/docs/use_cases/UC-003-event-metrics.md +66 -0
  56. data/docs/use_cases/UC-004-zero-config-slo-tracking.md +33 -684
  57. data/docs/use_cases/UC-005-sentry-integration.md +13 -15
  58. data/docs/use_cases/UC-006-trace-context-management.md +30 -28
  59. data/docs/use_cases/UC-007-pii-filtering.md +35 -87
  60. data/docs/use_cases/UC-008-opentelemetry-integration.md +51 -89
  61. data/docs/use_cases/UC-009-multi-service-tracing.md +30 -178
  62. data/docs/use_cases/UC-010-background-job-tracking.md +24 -91
  63. data/docs/use_cases/UC-011-rate-limiting.md +95 -168
  64. data/docs/use_cases/UC-012-audit-trail.md +21 -46
  65. data/docs/use_cases/UC-013-high-cardinality-protection.md +29 -167
  66. data/docs/use_cases/UC-014-adaptive-sampling.md +2 -2
  67. data/docs/use_cases/UC-015-cost-optimization.md +46 -99
  68. data/docs/use_cases/UC-016-rails-logger-migration.md +39 -213
  69. data/docs/use_cases/UC-017-local-development.md +203 -777
  70. data/docs/use_cases/UC-018-testing-events.md +3 -3
  71. data/docs/use_cases/UC-019-retention-based-routing.md +53 -106
  72. data/docs/use_cases/UC-020-event-versioning.md +8 -9
  73. data/docs/use_cases/UC-021-error-handling-retry-dlq.md +18 -22
  74. data/docs/use_cases/UC-022-event-registry.md +15 -21
  75. data/docs/use_cases/backlog.md +119 -87
  76. data/e11y.gemspec +2 -2
  77. data/gems/e11y-devtools/README.md +158 -0
  78. data/gems/e11y-devtools/config/routes.rb +15 -0
  79. data/gems/e11y-devtools/e11y-devtools.gemspec +25 -0
  80. data/gems/e11y-devtools/exe/e11y +34 -0
  81. data/gems/e11y-devtools/frontend/.gitignore +24 -0
  82. data/gems/e11y-devtools/frontend/README.md +51 -0
  83. data/gems/e11y-devtools/frontend/index.html +14 -0
  84. data/gems/e11y-devtools/frontend/package-lock.json +3707 -0
  85. data/gems/e11y-devtools/frontend/package.json +28 -0
  86. data/gems/e11y-devtools/frontend/public/mocks/v1/events/recent.json +4205 -0
  87. data/gems/e11y-devtools/frontend/public/mocks/v1/interactions.json +194 -0
  88. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0a2e04027cfa22d014bc22e8b27cd913/events.json +86 -0
  89. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0e1543af6a630fb3af6b52283154b3e0/events.json +169 -0
  90. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/1838b691faa49564f97db8592ff3978d/events.json +78 -0
  91. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/29f198f6588dacffb687777eb5f8f118/events.json +197 -0
  92. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/34bc3c9c0097de28a7a6f99b90a8e7bc/events.json +194 -0
  93. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/3ba6c20d068ab9cee00e51b180e66444/events.json +184 -0
  94. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/435bfd8f17b9009146a79812d7c3726d/events.json +144 -0
  95. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/4c7676e3fe668e99edb2b94d7d5678a9/events.json +222 -0
  96. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/6daf0d47974bedfc55d5de7004a3ea9f/events.json +194 -0
  97. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8a81ada42834d15f287bb40010043605/events.json +194 -0
  98. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8c0a98900edaae105469df8daedccf02/events.json +198 -0
  99. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8e4f645180f8a7d1dce426b07380466b/events.json +222 -0
  100. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/93db346fa5d44a032605a13b627f4b80/events.json +128 -0
  101. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/98ff6146faf7bd9be8bd03a8275817ba/events.json +223 -0
  102. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/9997ddd0247bc7e25f2ca7a5c415c93d/events.json +197 -0
  103. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/99e35f8ef3baedd798cc4fd085980ad9/events.json +194 -0
  104. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b4f3095c1909924cbc98889a86c83d6d/events.json +131 -0
  105. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b54b7fc32b7575a7110de809d11ccda0/events.json +128 -0
  106. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c0b48033fa06746bcc5886745e053cff/events.json +169 -0
  107. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c44649ac76701b4558927cd2305ab535/events.json +169 -0
  108. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/d601ae3320057580a39dbdac2edfdf4a/events.json +248 -0
  109. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e67e724bab422d2b52eeb49635e512e1/events.json +194 -0
  110. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e6c72765a28f158a8485b35fa63f73da/events.json +194 -0
  111. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/f541b87405c9a54819b18ebe529f6419/events.json +194 -0
  112. data/gems/e11y-devtools/frontend/scripts/generate_mocks.rb +397 -0
  113. data/gems/e11y-devtools/frontend/src/App.svelte +827 -0
  114. data/gems/e11y-devtools/frontend/src/components/Fab.svelte +19 -0
  115. data/gems/e11y-devtools/frontend/src/components/FilterBar.svelte +38 -0
  116. data/gems/e11y-devtools/frontend/src/components/FullscreenPanel.svelte +82 -0
  117. data/gems/e11y-devtools/frontend/src/components/InteractionsTimeline.svelte +264 -0
  118. data/gems/e11y-devtools/frontend/src/components/RecentHistogram.svelte +354 -0
  119. data/gems/e11y-devtools/frontend/src/lib/api.ts +37 -0
  120. data/gems/e11y-devtools/frontend/src/lib/eventIdentity.ts +12 -0
  121. data/gems/e11y-devtools/frontend/src/lib/format.ts +37 -0
  122. data/gems/e11y-devtools/frontend/src/lib/listFilter.ts +43 -0
  123. data/gems/e11y-devtools/frontend/src/lib/recentVolume.ts +80 -0
  124. data/gems/e11y-devtools/frontend/src/lib/router.ts +12 -0
  125. data/gems/e11y-devtools/frontend/src/lib/transitions.ts +34 -0
  126. data/gems/e11y-devtools/frontend/src/lib/viewportOrigin.ts +25 -0
  127. data/gems/e11y-devtools/frontend/src/main.ts +8 -0
  128. data/gems/e11y-devtools/frontend/src/overlay-entry.ts +24 -0
  129. data/gems/e11y-devtools/frontend/src/overlay.css +1080 -0
  130. data/gems/e11y-devtools/frontend/svelte.config.js +2 -0
  131. data/gems/e11y-devtools/frontend/test_puppeteer.js +41 -0
  132. data/gems/e11y-devtools/frontend/test_scale.js +3 -0
  133. data/gems/e11y-devtools/frontend/tsconfig.app.json +21 -0
  134. data/gems/e11y-devtools/frontend/tsconfig.json +7 -0
  135. data/gems/e11y-devtools/frontend/tsconfig.node.json +26 -0
  136. data/gems/e11y-devtools/frontend/vite.config.ts +36 -0
  137. data/gems/e11y-devtools/lib/e11y/devtools/mcp/server.rb +96 -0
  138. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tool_base.rb +25 -0
  139. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/clear.rb +31 -0
  140. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/errors.rb +35 -0
  141. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/event_detail.rb +33 -0
  142. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/events_by_trace.rb +33 -0
  143. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/interactions.rb +40 -0
  144. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/recent_events.rb +34 -0
  145. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/search.rb +34 -0
  146. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/stats.rb +30 -0
  147. data/gems/e11y-devtools/lib/e11y/devtools/overlay/assets/overlay.js +20 -0
  148. data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +94 -0
  149. data/gems/e11y-devtools/lib/e11y/devtools/overlay/engine.rb +26 -0
  150. data/gems/e11y-devtools/lib/e11y/devtools/overlay/middleware.rb +80 -0
  151. data/gems/e11y-devtools/lib/e11y/devtools/overlay/rails_controller.rb +67 -0
  152. data/gems/e11y-devtools/lib/e11y/devtools/tui/app.rb +262 -0
  153. data/gems/e11y-devtools/lib/e11y/devtools/tui/grouping.rb +66 -0
  154. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_detail.rb +62 -0
  155. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_list.rb +70 -0
  156. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/interaction_list.rb +47 -0
  157. data/gems/e11y-devtools/lib/e11y/devtools/version.rb +8 -0
  158. data/gems/e11y-devtools/lib/e11y/devtools.rb +13 -0
  159. data/gems/e11y-devtools/spec/e11y/devtools/mcp/tools_spec.rb +107 -0
  160. data/gems/e11y-devtools/spec/e11y/devtools/overlay/controller_spec.rb +91 -0
  161. data/gems/e11y-devtools/spec/e11y/devtools/overlay/middleware_spec.rb +46 -0
  162. data/gems/e11y-devtools/spec/e11y/devtools/tui/app_spec.rb +85 -0
  163. data/gems/e11y-devtools/spec/e11y/devtools/tui/grouping_spec.rb +64 -0
  164. data/gems/e11y-devtools/spec/spec_helper.rb +5 -0
  165. data/gems/e11y-devtools/spec/tui/widgets/event_list_spec.rb +44 -0
  166. data/gems/e11y-devtools/spec/tui/widgets/interaction_list_spec.rb +62 -0
  167. data/lib/e11y/adapters/audit_encrypted.rb +53 -11
  168. data/lib/e11y/adapters/base.rb +33 -34
  169. data/lib/e11y/adapters/dev_log/file_store.rb +143 -0
  170. data/lib/e11y/adapters/dev_log/query.rb +219 -0
  171. data/lib/e11y/adapters/dev_log.rb +118 -0
  172. data/lib/e11y/adapters/file.rb +3 -6
  173. data/lib/e11y/adapters/in_memory.rb +52 -5
  174. data/lib/e11y/adapters/in_memory_test.rb +29 -0
  175. data/lib/e11y/adapters/loki.rb +58 -23
  176. data/lib/e11y/adapters/null.rb +82 -0
  177. data/lib/e11y/adapters/opentelemetry_collector.rb +183 -0
  178. data/lib/e11y/adapters/otel_logs.rb +136 -23
  179. data/lib/e11y/adapters/sentry.rb +4 -7
  180. data/lib/e11y/adapters/stdout.rb +73 -7
  181. data/lib/e11y/adapters/yabeda.rb +153 -29
  182. data/lib/e11y/buffers/adaptive_buffer.rb +3 -17
  183. data/lib/e11y/buffers/{request_scoped_buffer.rb → ephemeral_buffer.rb} +72 -58
  184. data/lib/e11y/buffers/ring_buffer.rb +3 -16
  185. data/lib/e11y/configuration.rb +272 -0
  186. data/lib/e11y/console.rb +10 -17
  187. data/lib/e11y/current.rb +53 -1
  188. data/lib/e11y/debug/pipeline_inspector.rb +96 -0
  189. data/lib/e11y/documentation/generator.rb +48 -0
  190. data/lib/e11y/event/base.rb +176 -82
  191. data/lib/e11y/event/value_sampling_config.rb +1 -5
  192. data/lib/e11y/events/rails/database/query.rb +1 -4
  193. data/lib/e11y/events/rails/job/failed.rb +2 -0
  194. data/lib/e11y/instruments/active_job.rb +44 -12
  195. data/lib/e11y/instruments/rails_instrumentation.rb +49 -24
  196. data/lib/e11y/instruments/sidekiq.rb +135 -31
  197. data/lib/e11y/linters/base.rb +11 -0
  198. data/lib/e11y/linters/pii/pii_declaration_linter.rb +120 -0
  199. data/lib/e11y/linters/slo/config_consistency_linter.rb +76 -0
  200. data/lib/e11y/linters/slo/explicit_declaration_linter.rb +36 -0
  201. data/lib/e11y/linters/slo/slo_status_from_linter.rb +41 -0
  202. data/lib/e11y/logger/bridge.rb +26 -7
  203. data/lib/e11y/metrics/cardinality_protection.rb +10 -15
  204. data/lib/e11y/metrics/cardinality_tracker.rb +16 -6
  205. data/lib/e11y/metrics/registry.rb +3 -5
  206. data/lib/e11y/metrics/test_backend.rb +62 -0
  207. data/lib/e11y/metrics.rb +56 -10
  208. data/lib/e11y/middleware/adapter_resolver.rb +40 -0
  209. data/lib/e11y/middleware/audit_signing.rb +43 -6
  210. data/lib/e11y/middleware/baggage_protection.rb +75 -0
  211. data/lib/e11y/middleware/dev_log_source.rb +24 -0
  212. data/lib/e11y/middleware/event_slo.rb +23 -9
  213. data/lib/e11y/middleware/otel_span.rb +23 -0
  214. data/lib/e11y/middleware/pii_filter.rb +104 -75
  215. data/lib/e11y/middleware/rate_limiting.rb +54 -27
  216. data/lib/e11y/middleware/request.rb +70 -23
  217. data/lib/e11y/middleware/routing.rb +78 -21
  218. data/lib/e11y/middleware/sampling.rb +66 -17
  219. data/lib/e11y/middleware/self_monitoring_emit.rb +39 -0
  220. data/lib/e11y/middleware/trace_context.rb +45 -10
  221. data/lib/e11y/middleware/track_latency.rb +34 -0
  222. data/lib/e11y/middleware/validation.rb +7 -16
  223. data/lib/e11y/middleware/versioning.rb +26 -22
  224. data/lib/e11y/opentelemetry/semantic_conventions.rb +109 -0
  225. data/lib/e11y/opentelemetry/span_creator.rb +142 -0
  226. data/lib/e11y/pii/patterns.rb +12 -1
  227. data/lib/e11y/pipeline/builder.rb +4 -4
  228. data/lib/e11y/presets/audit_event.rb +13 -2
  229. data/lib/e11y/railtie.rb +52 -14
  230. data/lib/e11y/registry.rb +306 -0
  231. data/lib/e11y/reliability/circuit_breaker.rb +19 -21
  232. data/lib/e11y/reliability/dlq/base.rb +71 -0
  233. data/lib/e11y/reliability/dlq/file_adapter.rb +301 -0
  234. data/lib/e11y/reliability/dlq/file_storage.rb +63 -34
  235. data/lib/e11y/reliability/dlq/filter.rb +37 -54
  236. data/lib/e11y/reliability/retry_handler.rb +26 -29
  237. data/lib/e11y/reliability/retry_rate_limiter.rb +3 -11
  238. data/lib/e11y/sampling/error_spike_detector.rb +0 -2
  239. data/lib/e11y/sampling/load_monitor.rb +5 -9
  240. data/lib/e11y/sampling/stratified_tracker.rb +18 -0
  241. data/lib/e11y/self_monitoring/buffer_monitor.rb +2 -0
  242. data/lib/e11y/self_monitoring/performance_monitor.rb +19 -61
  243. data/lib/e11y/self_monitoring/reliability_monitor.rb +4 -74
  244. data/lib/e11y/slo/config_loader.rb +40 -0
  245. data/lib/e11y/slo/config_validator.rb +58 -0
  246. data/lib/e11y/slo/dashboard_generator.rb +122 -0
  247. data/lib/e11y/slo/event_driven.rb +8 -0
  248. data/lib/e11y/slo/tracker.rb +31 -4
  249. data/lib/e11y/testing/have_tracked_event_matcher.rb +190 -0
  250. data/lib/e11y/testing/rspec_matchers.rb +21 -0
  251. data/lib/e11y/testing/snapshot_matcher.rb +86 -0
  252. data/lib/e11y/trace_context/sampler.rb +35 -0
  253. data/lib/e11y/tracing/faraday_middleware.rb +31 -0
  254. data/lib/e11y/tracing/net_http_patch.rb +33 -0
  255. data/lib/e11y/tracing/propagator.rb +144 -0
  256. data/lib/e11y/tracing.rb +47 -0
  257. data/lib/e11y/version.rb +1 -1
  258. data/lib/e11y/versioning/version_extractor.rb +32 -0
  259. data/lib/e11y.rb +123 -266
  260. data/lib/generators/e11y/event/event_generator.rb +22 -0
  261. data/lib/generators/e11y/event/templates/event.rb.tt +16 -0
  262. data/lib/generators/e11y/grafana_dashboard/grafana_dashboard_generator.rb +30 -0
  263. data/lib/generators/e11y/grafana_dashboard/templates/e11y_dashboard.json +81 -0
  264. data/lib/generators/e11y/install/install_generator.rb +34 -0
  265. data/lib/generators/e11y/install/templates/e11y.rb +239 -0
  266. data/lib/generators/e11y/prometheus_alerts/prometheus_alerts_generator.rb +29 -0
  267. data/lib/generators/e11y/prometheus_alerts/templates/e11y_alerts.yml +28 -0
  268. data/lib/tasks/e11y_docs.rake +30 -0
  269. data/lib/tasks/e11y_events.rake +71 -0
  270. data/lib/tasks/e11y_lint.rake +91 -0
  271. data/lib/tasks/e11y_slo.rake +29 -0
  272. metadata +186 -39
  273. data/docs/ADR-003-slo-observability.md +0 -3337
  274. data/docs/ADR-010-developer-experience.md +0 -2166
  275. data/docs/API-REFERENCE-L28.md +0 -914
  276. data/docs/COMPREHENSIVE-CONFIGURATION.md +0 -2366
  277. data/docs/CONTRIBUTING.md +0 -312
  278. data/docs/IMPLEMENTATION_NOTES.md +0 -2804
  279. data/docs/IMPLEMENTATION_PLAN.md +0 -1971
  280. data/docs/IMPLEMENTATION_PLAN_ARCHITECTURE.md +0 -586
  281. data/docs/PLAN.md +0 -148
  282. data/docs/README.md +0 -296
  283. data/docs/design/00-memory-optimization.md +0 -593
  284. data/docs/guides/MIGRATION-L27-L28.md +0 -692
  285. data/docs/guides/PERFORMANCE-BENCHMARKS.md +0 -434
  286. data/docs/guides/README.md +0 -44
  287. data/docs/use_cases/UC-003-pattern-based-metrics.md +0 -1627
  288. data/lib/e11y/adapters/registry.rb +0 -141
@@ -0,0 +1,1080 @@
1
+ /* Scoped to e11y devtools roots only — demo #app and embedded #e11y-devtools-root */
2
+ #e11y-devtools-root,
3
+ #e11y-devtools-root *,
4
+ #app.e11y-demo-host .e11y-dt,
5
+ #app.e11y-demo-host .e11y-dt * {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ #e11y-devtools-root,
10
+ #app.e11y-demo-host .e11y-dt {
11
+ /* Dark theme (default) */
12
+ --e11y-bg: #1a1a2e;
13
+ --e11y-bg2: #16213e;
14
+ --e11y-bg-hover: #2d3748;
15
+ --e11y-bg-input: #0f0f1a;
16
+ --e11y-border: #333;
17
+ --e11y-border-hover: #555;
18
+ --e11y-text: #e0e0e0;
19
+ --e11y-muted: #a0aec0;
20
+ --e11y-muted-dark: #718096;
21
+
22
+ --e11y-accent: #63b3ed;
23
+ --e11y-accent-bg: rgba(99, 179, 237, 0.12);
24
+ --e11y-accent-border: rgba(99, 179, 237, 0.45);
25
+
26
+ --e11y-job: #b794f4;
27
+ --e11y-job-border: rgba(159, 122, 234, 0.45);
28
+
29
+ --e11y-ok: #68d391;
30
+ --e11y-ok-bg: rgba(104, 211, 145, 0.15);
31
+ --e11y-ok-border: rgba(104, 211, 145, 0.35);
32
+
33
+ --e11y-warn: #f6ad55;
34
+ --e11y-warn-bg: rgba(246, 173, 85, 0.15);
35
+ --e11y-warn-dark: #c05621;
36
+
37
+ --e11y-err: #fc8181;
38
+ --e11y-err-dark: #e53e3e;
39
+ --e11y-err-bg: rgba(229, 62, 62, 0.12);
40
+ --e11y-err-border: rgba(252, 129, 129, 0.55);
41
+
42
+ --e11y-ix-bg: linear-gradient(145deg, #1f1f35 0%, #1a1a2e 100%);
43
+ --e11y-ix-bg-err: linear-gradient(145deg, #3a1c1c 0%, #1a1a2e 100%);
44
+ --e11y-ix-bg-warn: linear-gradient(145deg, #3a2a1c 0%, #1a1a2e 100%);
45
+
46
+ --e11y-syntax-str: #9ae6b4;
47
+ --e11y-syntax-num: #feb2b2;
48
+ --e11y-syntax-bool: #fbd38d;
49
+ --e11y-syntax-null: #718096;
50
+ --e11y-syntax-key: #63b3ed;
51
+
52
+ --e11y-histo-bg: rgba(45, 55, 72, 0.5);
53
+ --e11y-histo-err: rgba(252, 129, 129, 0.85);
54
+ --e11y-histo-warn: rgba(246, 173, 85, 0.85);
55
+ --e11y-histo-ok: rgba(104, 211, 145, 0.55);
56
+
57
+ --e11y-sel-bg: rgba(99, 179, 237, 0.32);
58
+ --e11y-sel-border: rgba(99, 179, 237, 0.65);
59
+ --e11y-backdrop: rgba(0, 0, 0, 0.45);
60
+ --e11y-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
61
+
62
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
63
+ font-size: 12px;
64
+ line-height: 1.4;
65
+ color: var(--e11y-text);
66
+ }
67
+
68
+ @media (prefers-color-scheme: light) {
69
+ #e11y-devtools-root,
70
+ #app.e11y-demo-host .e11y-dt {
71
+ --e11y-bg: #ffffff;
72
+ --e11y-bg2: #f7fafc;
73
+ --e11y-bg-hover: #edf2f7;
74
+ --e11y-bg-input: #ffffff;
75
+ --e11y-border: #e2e8f0;
76
+ --e11y-border-hover: #cbd5e0;
77
+ --e11y-text: #2d3748;
78
+ --e11y-muted: #718096;
79
+ --e11y-muted-dark: #a0aec0;
80
+
81
+ --e11y-accent: #3182ce;
82
+ --e11y-accent-bg: rgba(49, 130, 206, 0.1);
83
+ --e11y-accent-border: rgba(49, 130, 206, 0.45);
84
+
85
+ --e11y-job: #805ad5;
86
+ --e11y-job-border: rgba(128, 90, 213, 0.45);
87
+
88
+ --e11y-ok: #38a169;
89
+ --e11y-ok-bg: rgba(56, 161, 105, 0.1);
90
+ --e11y-ok-border: rgba(56, 161, 105, 0.35);
91
+
92
+ --e11y-warn: #dd6b20;
93
+ --e11y-warn-bg: rgba(221, 107, 32, 0.1);
94
+ --e11y-warn-dark: #c05621;
95
+
96
+ --e11y-err: #e53e3e;
97
+ --e11y-err-dark: #c53030;
98
+ --e11y-err-bg: rgba(229, 62, 62, 0.1);
99
+ --e11y-err-border: rgba(229, 62, 62, 0.55);
100
+
101
+ --e11y-ix-bg: linear-gradient(145deg, #ffffff 0%, #f7fafc 100%);
102
+ --e11y-ix-bg-err: linear-gradient(145deg, #fff5f5 0%, #f7fafc 100%);
103
+ --e11y-ix-bg-warn: linear-gradient(145deg, #fffff0 0%, #f7fafc 100%);
104
+
105
+ --e11y-syntax-str: #2f855a;
106
+ --e11y-syntax-num: #c53030;
107
+ --e11y-syntax-bool: #b7791f;
108
+ --e11y-syntax-null: #a0aec0;
109
+ --e11y-syntax-key: #2b6cb0;
110
+
111
+ --e11y-histo-bg: rgba(226, 232, 240, 0.6);
112
+ --e11y-histo-err: rgba(229, 62, 62, 0.85);
113
+ --e11y-histo-warn: rgba(221, 107, 32, 0.85);
114
+ --e11y-histo-ok: rgba(56, 161, 105, 0.55);
115
+
116
+ --e11y-sel-bg: rgba(49, 130, 206, 0.2);
117
+ --e11y-sel-border: rgba(49, 130, 206, 0.5);
118
+ --e11y-backdrop: rgba(0, 0, 0, 0.25);
119
+ --e11y-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
120
+ }
121
+ }
122
+
123
+ .e11y-fab {
124
+ position: fixed;
125
+ bottom: 16px;
126
+ right: 16px;
127
+ z-index: 2147483000;
128
+ margin: 0;
129
+ padding: 8px 14px;
130
+ border-radius: 8px;
131
+ border: 1px solid var(--e11y-border);
132
+ background: var(--e11y-bg);
133
+ color: var(--e11y-text);
134
+ cursor: pointer;
135
+ font: inherit;
136
+ max-width: min(320px, calc(100vw - 32px));
137
+ text-align: left;
138
+ transition:
139
+ border-color 0.2s,
140
+ box-shadow 0.2s;
141
+ }
142
+
143
+ .e11y-fab:hover {
144
+ border-color: var(--e11y-border-hover);
145
+ }
146
+
147
+ .e11y-fab:focus-visible {
148
+ outline: 2px solid var(--e11y-accent);
149
+ outline-offset: 2px;
150
+ }
151
+
152
+ .e11y-fab--state-warn {
153
+ border-color: var(--e11y-warn-dark);
154
+ color: var(--e11y-warn);
155
+ }
156
+
157
+ .e11y-fab--state-err {
158
+ border-color: var(--e11y-err-dark);
159
+ color: var(--e11y-err);
160
+ }
161
+
162
+ @media (prefers-reduced-motion: no-preference) {
163
+ @keyframes e11y-pulse-error {
164
+ 0%,
165
+ 100% {
166
+ box-shadow: 0 0 0 0 var(--e11y-err-border);
167
+ }
168
+ 50% {
169
+ box-shadow: 0 0 0 10px rgba(229, 62, 62, 0);
170
+ }
171
+ }
172
+
173
+ @keyframes e11y-pulse-warn {
174
+ 0%,
175
+ 100% {
176
+ box-shadow: 0 0 0 0 rgba(246, 173, 85, 0.55);
177
+ }
178
+ 50% {
179
+ box-shadow: 0 0 0 10px rgba(246, 173, 85, 0);
180
+ }
181
+ }
182
+
183
+ .e11y-fab--pulse-error {
184
+ animation: e11y-pulse-error 0.9s ease-out 2;
185
+ }
186
+
187
+ .e11y-fab--pulse-warn {
188
+ animation: e11y-pulse-warn 0.9s ease-out 2;
189
+ }
190
+ }
191
+
192
+ @media (prefers-reduced-motion: reduce) {
193
+ .e11y-fab--pulse-error {
194
+ border-color: var(--e11y-err-dark);
195
+ }
196
+
197
+ .e11y-fab--pulse-warn {
198
+ border-color: var(--e11y-warn-dark);
199
+ }
200
+ }
201
+
202
+ .e11y-backdrop {
203
+ position: fixed;
204
+ inset: 0;
205
+ z-index: 2147483640;
206
+ background: var(--e11y-backdrop);
207
+ display: flex;
208
+ align-items: stretch;
209
+ justify-content: stretch;
210
+ will-change: clip-path;
211
+ }
212
+
213
+ @media (prefers-reduced-motion: reduce) {
214
+ .e11y-backdrop {
215
+ will-change: auto;
216
+ }
217
+ }
218
+
219
+ .e11y-sheet {
220
+ flex: 1;
221
+ margin: 0;
222
+ background: var(--e11y-bg);
223
+ border: 1px solid var(--e11y-border);
224
+ border-radius: 12px 0 0 0;
225
+ box-shadow:
226
+ 0 0 0 1px var(--e11y-accent-bg),
227
+ -24px 0 80px var(--e11y-backdrop);
228
+ display: flex;
229
+ flex-direction: column;
230
+ min-height: 100%;
231
+ transform-origin: bottom right;
232
+ will-change: transform, opacity;
233
+ }
234
+
235
+ @media (prefers-reduced-motion: reduce) {
236
+ .e11y-sheet {
237
+ will-change: auto;
238
+ }
239
+ }
240
+
241
+ .e11y-panel-header {
242
+ flex-shrink: 0;
243
+ display: flex;
244
+ flex-direction: column;
245
+ background: var(--e11y-bg2);
246
+ border-bottom: 1px solid var(--e11y-border);
247
+ }
248
+
249
+ .e11y-panel-header-top {
250
+ display: flex;
251
+ align-items: center;
252
+ gap: 12px;
253
+ padding: 12px 16px;
254
+ }
255
+
256
+ .e11y-panel-header-left {
257
+ display: flex;
258
+ align-items: center;
259
+ gap: 12px;
260
+ flex: 1;
261
+ }
262
+
263
+ .e11y-panel-header-right {
264
+ display: flex;
265
+ align-items: center;
266
+ gap: 8px;
267
+ }
268
+
269
+ .e11y-panel-header-bottom {
270
+ padding: 0 16px 12px;
271
+ }
272
+
273
+ .e11y-panel-title {
274
+ font-weight: 700;
275
+ flex: 1;
276
+ }
277
+
278
+ .e11y-panel-title--sub {
279
+ font-size: 12px;
280
+ font-weight: normal;
281
+ color: var(--e11y-muted);
282
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
283
+ }
284
+
285
+ .e11y-breadcrumb-sep {
286
+ color: var(--e11y-border);
287
+ font-size: 16px;
288
+ user-select: none;
289
+ font-weight: 300;
290
+ }
291
+
292
+ .e11y-chip-row {
293
+ display: flex;
294
+ gap: 6px;
295
+ flex-wrap: wrap;
296
+ }
297
+
298
+ .e11y-chip-dot {
299
+ display: inline-block;
300
+ width: 8px;
301
+ height: 8px;
302
+ border-radius: 50%;
303
+ margin-right: 6px;
304
+ }
305
+
306
+ .e11y-chip-dot--all {
307
+ background: var(--e11y-muted);
308
+ }
309
+
310
+ .e11y-chip-dot--err {
311
+ background: var(--e11y-err);
312
+ }
313
+
314
+ .e11y-chip-dot--warn {
315
+ background: var(--e11y-warn);
316
+ }
317
+
318
+ .e11y-chip-dot--rest {
319
+ background: var(--e11y-ok);
320
+ }
321
+
322
+ .e11y-chip {
323
+ display: inline-flex;
324
+ align-items: center;
325
+ padding: 4px 12px 4px 8px;
326
+ border-radius: 999px;
327
+ border: 1px solid var(--e11y-border);
328
+ background: transparent;
329
+ color: var(--e11y-text);
330
+ font: inherit;
331
+ cursor: pointer;
332
+ transition: all 0.15s ease;
333
+ }
334
+
335
+ .e11y-chip:hover {
336
+ background: var(--e11y-bg-hover);
337
+ }
338
+
339
+ .e11y-chip--active {
340
+ border-color: var(--e11y-accent);
341
+ background: var(--e11y-accent-bg);
342
+ }
343
+
344
+ .e11y-chip--error.e11y-chip--active {
345
+ border-color: var(--e11y-err-border);
346
+ background: var(--e11y-err-bg);
347
+ }
348
+
349
+ .e11y-chip--warn.e11y-chip--active {
350
+ border-color: var(--e11y-warn);
351
+ background: var(--e11y-warn-bg);
352
+ }
353
+
354
+ .e11y-chip--rest.e11y-chip--active {
355
+ border-color: var(--e11y-ok-border);
356
+ background: var(--e11y-ok-bg);
357
+ }
358
+
359
+ .e11y-icon-btn {
360
+ border: none;
361
+ background: transparent;
362
+ color: var(--e11y-muted);
363
+ font-size: 18px;
364
+ line-height: 1;
365
+ cursor: pointer;
366
+ padding: 4px 8px;
367
+ }
368
+
369
+ .e11y-icon-btn:hover {
370
+ color: var(--e11y-text);
371
+ }
372
+
373
+ .e11y-panel-body {
374
+ flex: 1;
375
+ overflow: auto;
376
+ padding: 8px 12px 20px;
377
+ }
378
+
379
+ .e11y-row {
380
+ display: flex;
381
+ flex-wrap: wrap;
382
+ gap: 10px;
383
+ align-items: baseline;
384
+ padding: 8px 10px;
385
+ border-radius: 6px;
386
+ cursor: pointer;
387
+ border: 1px solid transparent;
388
+ }
389
+
390
+ .e11y-row:hover {
391
+ background: var(--e11y-bg-hover);
392
+ }
393
+
394
+ /* Interaction (trace group) cards */
395
+ .e11y-ix {
396
+ display: flex;
397
+ flex-wrap: wrap;
398
+ align-items: flex-start;
399
+ justify-content: space-between;
400
+ gap: 10px 16px;
401
+ padding: 12px 14px;
402
+ margin-bottom: 8px;
403
+ border-radius: 10px;
404
+ border: 1px solid var(--e11y-border);
405
+ background: var(--e11y-ix-bg);
406
+ cursor: pointer;
407
+ text-align: left;
408
+ transition:
409
+ border-color 0.2s,
410
+ box-shadow 0.25s ease;
411
+ }
412
+
413
+ .e11y-ix:hover {
414
+ border-color: var(--e11y-accent-border);
415
+ box-shadow: var(--e11y-shadow);
416
+ }
417
+
418
+ .e11y-ix:focus-visible {
419
+ outline: 2px solid var(--e11y-accent);
420
+ outline-offset: 2px;
421
+ }
422
+
423
+ .e11y-ix--error {
424
+ background: var(--e11y-ix-bg-err);
425
+ border-color: var(--e11y-err-border);
426
+ }
427
+
428
+ .e11y-ix--error:hover {
429
+ border-color: var(--e11y-err);
430
+ }
431
+
432
+ .e11y-ix-main {
433
+ flex: 1;
434
+ min-width: min(100%, 220px);
435
+ display: flex;
436
+ flex-direction: column;
437
+ gap: 8px;
438
+ }
439
+
440
+ .e11y-ix-time {
441
+ display: flex;
442
+ flex-wrap: wrap;
443
+ align-items: baseline;
444
+ gap: 8px;
445
+ }
446
+
447
+ .e11y-ix-time-abs {
448
+ font-weight: 600;
449
+ color: var(--e11y-text);
450
+ }
451
+
452
+ .e11y-ix-time-rel {
453
+ font-size: 11px;
454
+ color: var(--e11y-muted);
455
+ }
456
+
457
+ .e11y-ix-trace-line {
458
+ display: flex;
459
+ flex-wrap: wrap;
460
+ align-items: center;
461
+ gap: 8px;
462
+ }
463
+
464
+ .e11y-ix-trace-primary {
465
+ font-size: 11px;
466
+ padding: 3px 8px;
467
+ border-radius: 6px;
468
+ background: var(--e11y-bg-input);
469
+ border: 1px solid var(--e11y-bg-hover);
470
+ color: var(--e11y-accent);
471
+ word-break: break-all;
472
+ }
473
+
474
+ .e11y-ix-preview {
475
+ font-size: 11px;
476
+ color: var(--e11y-muted);
477
+ word-break: break-all;
478
+ line-height: 1.35;
479
+ }
480
+
481
+ .e11y-ix-hint {
482
+ font-size: 10px;
483
+ color: var(--e11y-muted-dark);
484
+ letter-spacing: 0.02em;
485
+ }
486
+
487
+ .e11y-ix-aside {
488
+ display: flex;
489
+ flex-direction: column;
490
+ align-items: flex-end;
491
+ gap: 6px;
492
+ flex-shrink: 0;
493
+ }
494
+
495
+ .e11y-pill {
496
+ font-size: 10px;
497
+ font-weight: 700;
498
+ text-transform: uppercase;
499
+ letter-spacing: 0.04em;
500
+ padding: 3px 8px;
501
+ border-radius: 999px;
502
+ border: 1px solid var(--e11y-border);
503
+ color: var(--e11y-muted);
504
+ }
505
+
506
+ .e11y-pill--web {
507
+ border-color: var(--e11y-accent-border);
508
+ color: var(--e11y-accent);
509
+ }
510
+
511
+ .e11y-pill--job {
512
+ border-color: var(--e11y-job-border);
513
+ color: var(--e11y-job);
514
+ }
515
+
516
+ .e11y-pill--ok {
517
+ border-color: var(--e11y-ok-border);
518
+ color: var(--e11y-ok);
519
+ }
520
+
521
+ .e11y-pill--err {
522
+ border-color: var(--e11y-err-border);
523
+ color: var(--e11y-err);
524
+ background: var(--e11y-err-bg);
525
+ }
526
+
527
+ .e11y-ix-count {
528
+ font-size: 11px;
529
+ color: var(--e11y-muted);
530
+ }
531
+
532
+ .e11y-sev {
533
+ flex-shrink: 0;
534
+ width: 4em;
535
+ font-weight: 600;
536
+ text-transform: uppercase;
537
+ font-size: 10px;
538
+ }
539
+
540
+ .e11y-sev--error,
541
+ .e11y-sev--fatal {
542
+ color: var(--e11y-err);
543
+ }
544
+
545
+ .e11y-sev--warn {
546
+ color: var(--e11y-warn);
547
+ }
548
+
549
+ .e11y-sev--info {
550
+ color: var(--e11y-ok);
551
+ }
552
+
553
+ .e11y-row-title {
554
+ flex: 1;
555
+ word-break: break-word;
556
+ }
557
+
558
+ .e11y-row-meta {
559
+ color: var(--e11y-muted);
560
+ flex-shrink: 0;
561
+ }
562
+
563
+ .e11y-detail-pre {
564
+ margin: 0;
565
+ padding: 12px;
566
+ background: var(--e11y-bg-input);
567
+ border-radius: 8px;
568
+ overflow: auto;
569
+ max-height: min(70vh, 600px);
570
+ font-size: 11px;
571
+ white-space: pre-wrap;
572
+ word-break: break-word;
573
+ }
574
+
575
+ .e11y-toolbar {
576
+ margin-bottom: 10px;
577
+ display: flex;
578
+ gap: 8px;
579
+ }
580
+
581
+ .e11y-btn {
582
+ padding: 6px 12px;
583
+ border-radius: 6px;
584
+ border: 1px solid var(--e11y-border);
585
+ background: var(--e11y-bg2);
586
+ color: var(--e11y-accent);
587
+ font: inherit;
588
+ cursor: pointer;
589
+ }
590
+
591
+ .e11y-btn--sm {
592
+ padding: 4px 8px;
593
+ font-size: 11px;
594
+ }
595
+
596
+ .e11y-btn:hover {
597
+ border-color: var(--e11y-accent);
598
+ }
599
+
600
+ .e11y-muted {
601
+ color: var(--e11y-muted);
602
+ }
603
+
604
+ .e11y-err-msg {
605
+ color: var(--e11y-err);
606
+ padding: 8px;
607
+ }
608
+
609
+ .e11y-header-nav {
610
+ display: flex;
611
+ flex-direction: column;
612
+ align-items: flex-end;
613
+ gap: 8px;
614
+ }
615
+
616
+ .e11y-tab-row {
617
+ display: flex;
618
+ gap: 4px;
619
+ flex-wrap: wrap;
620
+ justify-content: flex-end;
621
+ }
622
+
623
+ .e11y-tab {
624
+ padding: 5px 12px;
625
+ border-radius: 8px;
626
+ border: 1px solid var(--e11y-border);
627
+ background: transparent;
628
+ color: var(--e11y-muted);
629
+ font: inherit;
630
+ font-size: 11px;
631
+ font-weight: 600;
632
+ cursor: pointer;
633
+ text-transform: uppercase;
634
+ letter-spacing: 0.04em;
635
+ }
636
+
637
+ .e11y-tab:hover {
638
+ color: var(--e11y-text);
639
+ border-color: var(--e11y-border-hover);
640
+ }
641
+
642
+ .e11y-tab--active {
643
+ color: var(--e11y-text);
644
+ border-color: var(--e11y-accent);
645
+ background: var(--e11y-accent-bg);
646
+ }
647
+
648
+ .e11y-tab-badge {
649
+ display: inline-block;
650
+ min-width: 1.25em;
651
+ padding: 0 5px;
652
+ border-radius: 999px;
653
+ background: var(--e11y-err-bg);
654
+ color: var(--e11y-err);
655
+ font-size: 10px;
656
+ vertical-align: middle;
657
+ }
658
+
659
+ .e11y-chip-row--header {
660
+ justify-content: flex-end;
661
+ }
662
+
663
+ .e11y-split {
664
+ display: grid;
665
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
666
+ gap: 12px;
667
+ align-items: start;
668
+ min-height: min(60vh, 520px);
669
+ }
670
+
671
+ @media (max-width: 899px) {
672
+ .e11y-split {
673
+ display: block;
674
+ }
675
+ }
676
+
677
+ .e11y-split-primary,
678
+ .e11y-split-secondary {
679
+ min-height: 120px;
680
+ max-height: min(65vh, 560px);
681
+ overflow-y: auto;
682
+ padding-right: 4px;
683
+ }
684
+
685
+ .e11y-split-secondary {
686
+ border-left: 1px solid var(--e11y-border);
687
+ padding-left: 12px;
688
+ }
689
+
690
+ @media (max-width: 899px) {
691
+ .e11y-split-secondary {
692
+ border-left: none;
693
+ padding-left: 0;
694
+ }
695
+ }
696
+
697
+ .e11y-split-placeholder {
698
+ margin: 24px 8px;
699
+ color: var(--e11y-muted);
700
+ font-size: 12px;
701
+ line-height: 1.5;
702
+ }
703
+
704
+ .e11y-ix--selected {
705
+ border-color: var(--e11y-sel-border);
706
+ box-shadow: 0 0 0 1px var(--e11y-sel-bg);
707
+ }
708
+
709
+ .e11y-problems-hint {
710
+ margin: 0 0 12px;
711
+ font-size: 11px;
712
+ color: var(--e11y-muted);
713
+ line-height: 1.45;
714
+ }
715
+
716
+ .e11y-empty {
717
+ margin: 8px 0 12px;
718
+ }
719
+
720
+ .e11y-row--problem {
721
+ flex-wrap: wrap;
722
+ }
723
+
724
+ .e11y-mono {
725
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
726
+ font-size: 10px;
727
+ }
728
+
729
+ /* Recent volume (stacked by severity) + brush selection */
730
+ .e11y-histo-wrap {
731
+ margin: 0 0 14px;
732
+ user-select: none;
733
+ }
734
+
735
+ /* LayerCake: inner .layercake-container is height:100% — host height set inline from peak bucket volume */
736
+ .e11y-histo-chart-host {
737
+ position: relative;
738
+ width: 100%;
739
+ box-sizing: border-box;
740
+ touch-action: none;
741
+ cursor: crosshair;
742
+ border-radius: 6px;
743
+ border: 1px solid transparent;
744
+ }
745
+
746
+ .e11y-histo-chart-host:hover {
747
+ border-color: var(--e11y-accent-bg);
748
+ }
749
+
750
+ .e11y-histo-sel-shade {
751
+ position: absolute;
752
+ z-index: 1;
753
+ pointer-events: none;
754
+ box-sizing: border-box;
755
+ border-radius: 3px;
756
+ background-color: var(--e11y-sel-bg);
757
+ outline: 1px solid var(--e11y-sel-border);
758
+ outline-offset: -1px;
759
+ }
760
+
761
+ .e11y-histo-brush-overlay {
762
+ position: absolute;
763
+ inset: 0;
764
+ z-index: 2;
765
+ cursor: crosshair;
766
+ touch-action: none;
767
+ }
768
+
769
+ .e11y-histo-svg.layercake-layout-svg {
770
+ overflow: visible;
771
+ }
772
+
773
+ .e11y-histo-axis-tick {
774
+ font-size: 9px;
775
+ fill: var(--e11y-muted);
776
+ }
777
+
778
+ .e11y-histo-scale {
779
+ position: relative;
780
+ height: 14px;
781
+ margin-bottom: 4px;
782
+ padding: 0 1px;
783
+ }
784
+
785
+ .e11y-histo-tick {
786
+ position: absolute;
787
+ top: 0;
788
+ font-size: 9px;
789
+ line-height: 1;
790
+ color: var(--e11y-muted);
791
+ white-space: nowrap;
792
+ transform: translateX(-50%);
793
+ }
794
+
795
+ .e11y-histo-tick--start {
796
+ transform: translateX(0);
797
+ }
798
+
799
+ .e11y-histo-tick--end {
800
+ transform: translateX(-100%);
801
+ }
802
+
803
+ .e11y-histo {
804
+ display: flex;
805
+ gap: 1px;
806
+ align-items: flex-end;
807
+ height: 52px;
808
+ padding: 0 2px;
809
+ cursor: crosshair;
810
+ touch-action: none;
811
+ border-radius: 6px;
812
+ border: 1px solid transparent;
813
+ }
814
+
815
+ .e11y-histo:hover {
816
+ border-color: var(--e11y-accent-bg);
817
+ }
818
+
819
+ .e11y-histo-col {
820
+ flex: 1;
821
+ min-width: 2px;
822
+ height: 100%;
823
+ display: flex;
824
+ flex-direction: column;
825
+ justify-content: flex-end;
826
+ border-radius: 2px 2px 0 0;
827
+ transition:
828
+ background 0.12s ease,
829
+ box-shadow 0.12s ease;
830
+ }
831
+
832
+ .e11y-histo-col--selected {
833
+ background: var(--e11y-accent-bg);
834
+ box-shadow: inset 0 0 0 1px var(--e11y-accent-border);
835
+ }
836
+
837
+ .e11y-histo-bar {
838
+ width: 100%;
839
+ display: flex;
840
+ flex-direction: column-reverse;
841
+ border-radius: 2px 2px 0 0;
842
+ overflow: hidden;
843
+ min-height: 2px;
844
+ background: var(--e11y-histo-bg);
845
+ }
846
+
847
+ .e11y-histo-seg {
848
+ min-height: 2px;
849
+ width: 100%;
850
+ }
851
+
852
+ .e11y-histo-seg--err {
853
+ background: var(--e11y-histo-err);
854
+ }
855
+
856
+ .e11y-histo-seg--warn {
857
+ background: var(--e11y-histo-warn);
858
+ }
859
+
860
+ .e11y-histo-seg--rest {
861
+ background: var(--e11y-histo-ok);
862
+ }
863
+
864
+ .e11y-histo-footer {
865
+ display: flex;
866
+ flex-wrap: wrap;
867
+ align-items: flex-start;
868
+ justify-content: space-between;
869
+ gap: 10px 16px;
870
+ margin-top: 8px;
871
+ }
872
+
873
+ .e11y-histo-legend {
874
+ display: flex;
875
+ flex-wrap: wrap;
876
+ gap: 12px;
877
+ font-size: 10px;
878
+ color: var(--e11y-muted);
879
+ }
880
+
881
+ .e11y-histo-meta {
882
+ display: flex;
883
+ flex-wrap: wrap;
884
+ align-items: center;
885
+ gap: 8px 12px;
886
+ font-size: 10px;
887
+ color: var(--e11y-muted);
888
+ max-width: 100%;
889
+ justify-content: flex-end;
890
+ text-align: right;
891
+ }
892
+
893
+ .e11y-histo-span {
894
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
895
+ font-size: 9px;
896
+ opacity: 0.9;
897
+ }
898
+
899
+ .e11y-histo-filter {
900
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
901
+ font-size: 9px;
902
+ color: var(--e11y-accent);
903
+ }
904
+
905
+ .e11y-histo-hint {
906
+ font-size: 9px;
907
+ color: var(--e11y-muted-dark);
908
+ max-width: 220px;
909
+ line-height: 1.35;
910
+ }
911
+
912
+ .e11y-histo-clear {
913
+ padding: 3px 8px;
914
+ border-radius: 6px;
915
+ border: 1px solid var(--e11y-border);
916
+ background: var(--e11y-bg2);
917
+ color: var(--e11y-accent);
918
+ font: inherit;
919
+ font-size: 10px;
920
+ cursor: pointer;
921
+ }
922
+
923
+ .e11y-histo-clear:hover {
924
+ border-color: var(--e11y-accent);
925
+ }
926
+
927
+ .e11y-histo-dot {
928
+ display: inline-block;
929
+ width: 7px;
930
+ height: 7px;
931
+ border-radius: 1px;
932
+ margin-right: 4px;
933
+ vertical-align: middle;
934
+ }
935
+
936
+ .e11y-histo-dot--err {
937
+ background: var(--e11y-err);
938
+ }
939
+
940
+ .e11y-histo-dot--warn {
941
+ background: var(--e11y-warn);
942
+ }
943
+
944
+ .e11y-histo-dot--rest {
945
+ background: var(--e11y-ok);
946
+ }
947
+
948
+ .e11y-list-filters {
949
+ display: flex;
950
+ flex-wrap: wrap;
951
+ align-items: center;
952
+ gap: 8px;
953
+ }
954
+
955
+
956
+ .e11y-search {
957
+ flex: 1;
958
+ min-width: 140px;
959
+ max-width: 320px;
960
+ padding: 6px 10px;
961
+ border-radius: 6px;
962
+ border: 1px solid var(--e11y-border);
963
+ background: var(--e11y-bg-input);
964
+ color: var(--e11y-text);
965
+ font: inherit;
966
+ }
967
+
968
+ .e11y-search::placeholder {
969
+ color: var(--e11y-muted-dark);
970
+ }
971
+
972
+ .e11y-search:focus {
973
+ outline: 2px solid var(--e11y-accent-border);
974
+ outline-offset: 1px;
975
+ }
976
+
977
+ .e11y-context-hint {
978
+ margin: -6px 0 10px;
979
+ font-size: 10px;
980
+ color: var(--e11y-muted-dark);
981
+ }
982
+
983
+ .e11y-row-expand {
984
+ flex-shrink: 0;
985
+ width: 22px;
986
+ padding: 0;
987
+ border: none;
988
+ background: transparent;
989
+ color: var(--e11y-muted);
990
+ cursor: pointer;
991
+ font-size: 10px;
992
+ line-height: 1;
993
+ transition: transform 0.15s ease;
994
+ }
995
+
996
+ .e11y-row-expand:hover {
997
+ color: var(--e11y-accent);
998
+ }
999
+
1000
+ .e11y-row-expand--open {
1001
+ transform: rotate(90deg);
1002
+ }
1003
+
1004
+ .e11y-row-body {
1005
+ flex: 1 1 100%;
1006
+ margin-top: 6px;
1007
+ padding-top: 6px;
1008
+ border-top: 1px solid var(--e11y-border);
1009
+ }
1010
+
1011
+ .e11y-row-sum {
1012
+ margin: 0 0 6px;
1013
+ font-size: 11px;
1014
+ color: var(--e11y-muted);
1015
+ line-height: 1.4;
1016
+ word-break: break-word;
1017
+ }
1018
+
1019
+ .e11y-row-pre {
1020
+ margin: 0;
1021
+ padding: 8px;
1022
+ background: var(--e11y-bg-input);
1023
+ border-radius: 6px;
1024
+ font-size: 10px;
1025
+ max-height: 200px;
1026
+ overflow: auto;
1027
+ white-space: pre-wrap;
1028
+ word-break: break-word;
1029
+ }
1030
+
1031
+ .e11y-row--context {
1032
+ border-color: var(--e11y-accent-border);
1033
+ box-shadow: inset 3px 0 0 var(--e11y-accent);
1034
+ background: var(--e11y-accent-bg);
1035
+ }
1036
+
1037
+ .e11y-detail {
1038
+ display: flex;
1039
+ flex-direction: column;
1040
+ gap: 10px;
1041
+ }
1042
+
1043
+ .e11y-detail-dl {
1044
+ margin: 0;
1045
+ display: grid;
1046
+ grid-template-columns: 7em 1fr;
1047
+ gap: 4px 12px;
1048
+ font-size: 11px;
1049
+ }
1050
+
1051
+ .e11y-detail-dl dt {
1052
+ margin: 0;
1053
+ color: var(--e11y-muted);
1054
+ font-weight: 600;
1055
+ }
1056
+
1057
+ .e11y-detail-dl dd {
1058
+ margin: 0;
1059
+ word-break: break-all;
1060
+ }
1061
+
1062
+ .e11y-details {
1063
+ border: 1px solid var(--e11y-border);
1064
+ border-radius: 8px;
1065
+ padding: 0 10px;
1066
+ background: var(--e11y-bg2);
1067
+ }
1068
+
1069
+ .e11y-details summary {
1070
+ cursor: pointer;
1071
+ padding: 8px 0;
1072
+ font-weight: 600;
1073
+ font-size: 11px;
1074
+ color: var(--e11y-accent);
1075
+ }
1076
+
1077
+ .e11y-details .e11y-detail-pre {
1078
+ margin-bottom: 10px;
1079
+ max-height: min(40vh, 360px);
1080
+ }