snake-orm 0.1.0b1__py3-none-any.whl

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 (198) hide show
  1. snake_orm-0.1.0b1.dist-info/METADATA +366 -0
  2. snake_orm-0.1.0b1.dist-info/RECORD +198 -0
  3. snake_orm-0.1.0b1.dist-info/WHEEL +4 -0
  4. snake_orm-0.1.0b1.dist-info/entry_points.txt +2 -0
  5. snake_orm-0.1.0b1.dist-info/licenses/LICENSE +21 -0
  6. snakeorm/__init__.py +214 -0
  7. snakeorm/advisor.py +109 -0
  8. snakeorm/cli/__init__.py +3 -0
  9. snakeorm/cli/app.py +992 -0
  10. snakeorm/cli/discovery.py +179 -0
  11. snakeorm/cli/hooks.py +86 -0
  12. snakeorm/compiler/__init__.py +3 -0
  13. snakeorm/compiler/compiler.py +330 -0
  14. snakeorm/connection.py +228 -0
  15. snakeorm/contrib/__init__.py +17 -0
  16. snakeorm/contrib/asgi.py +192 -0
  17. snakeorm/contrib/config.py +264 -0
  18. snakeorm/contrib/deliver.py +256 -0
  19. snakeorm/contrib/django.py +245 -0
  20. snakeorm/contrib/sidecar.py +44 -0
  21. snakeorm/contrib/wsgi.py +176 -0
  22. snakeorm/core/__init__.py +1 -0
  23. snakeorm/core/config.py +173 -0
  24. snakeorm/core/converters.py +172 -0
  25. snakeorm/core/exceptions.py +175 -0
  26. snakeorm/core/placement.py +15 -0
  27. snakeorm/core/sentinels.py +37 -0
  28. snakeorm/core/signals.py +114 -0
  29. snakeorm/debug/__init__.py +42 -0
  30. snakeorm/debug/assets/css/panel.css +616 -0
  31. snakeorm/debug/assets/css/snake_orm_app.css +293 -0
  32. snakeorm/debug/assets/img/icon.svg +5 -0
  33. snakeorm/debug/assets/js/history.js +425 -0
  34. snakeorm/debug/assets/js/language.js +283 -0
  35. snakeorm/debug/assets/js/panel.js +241 -0
  36. snakeorm/debug/assets/js/snake_orm_app.js +82 -0
  37. snakeorm/debug/assets/pages/cli.html +28 -0
  38. snakeorm/debug/assets/pages/config.html +34 -0
  39. snakeorm/debug/assets/pages/database_first.html +29 -0
  40. snakeorm/debug/assets/pages/help.html +21 -0
  41. snakeorm/debug/assets/pages/history.html +27 -0
  42. snakeorm/debug/capture.py +234 -0
  43. snakeorm/debug/channel.py +131 -0
  44. snakeorm/debug/collector.py +144 -0
  45. snakeorm/debug/config.py +149 -0
  46. snakeorm/debug/html.py +578 -0
  47. snakeorm/debug/matrix.py +60 -0
  48. snakeorm/debug/origin.py +42 -0
  49. snakeorm/debug/otel/__init__.py +68 -0
  50. snakeorm/debug/otel/context.py +43 -0
  51. snakeorm/debug/otel/exporter.py +277 -0
  52. snakeorm/debug/otel/payload.py +97 -0
  53. snakeorm/debug/otel/report.py +29 -0
  54. snakeorm/debug/otel/spans.py +393 -0
  55. snakeorm/debug/otel/summary.py +59 -0
  56. snakeorm/debug/record.py +54 -0
  57. snakeorm/debug/report.py +311 -0
  58. snakeorm/debug/testing.py +23 -0
  59. snakeorm/decorators/__init__.py +13 -0
  60. snakeorm/decorators/abstract.py +26 -0
  61. snakeorm/decorators/db_first.py +104 -0
  62. snakeorm/decorators/function.py +28 -0
  63. snakeorm/decorators/model.py +268 -0
  64. snakeorm/decorators/polymorphic.py +140 -0
  65. snakeorm/decorators/result.py +167 -0
  66. snakeorm/decorators/row.py +90 -0
  67. snakeorm/decorators/trigger.py +47 -0
  68. snakeorm/decorators/view.py +149 -0
  69. snakeorm/dialects/__init__.py +6 -0
  70. snakeorm/dialects/base.py +373 -0
  71. snakeorm/dialects/capabilities.py +571 -0
  72. snakeorm/dialects/literals.py +46 -0
  73. snakeorm/dialects/matrix.py +384 -0
  74. snakeorm/dialects/mysql.py +519 -0
  75. snakeorm/dialects/postgres.py +504 -0
  76. snakeorm/dialects/sqlite.py +417 -0
  77. snakeorm/drivers/__init__.py +18 -0
  78. snakeorm/drivers/asyncbase.py +73 -0
  79. snakeorm/drivers/asyncdecorators.py +244 -0
  80. snakeorm/drivers/asyncpool.py +228 -0
  81. snakeorm/drivers/asyncpsycopg.py +124 -0
  82. snakeorm/drivers/asyncpymysql.py +50 -0
  83. snakeorm/drivers/asyncsqlite.py +30 -0
  84. snakeorm/drivers/base.py +76 -0
  85. snakeorm/drivers/failures.py +181 -0
  86. snakeorm/drivers/logging.py +167 -0
  87. snakeorm/drivers/pool.py +352 -0
  88. snakeorm/drivers/psycopg.py +188 -0
  89. snakeorm/drivers/pymysql.py +176 -0
  90. snakeorm/drivers/savepoints.py +46 -0
  91. snakeorm/drivers/sqlite.py +170 -0
  92. snakeorm/drivers/threaded.py +143 -0
  93. snakeorm/drivers/timeout.py +87 -0
  94. snakeorm/dto/__init__.py +55 -0
  95. snakeorm/dto/read.py +231 -0
  96. snakeorm/dto/region.py +326 -0
  97. snakeorm/dto/resolve.py +354 -0
  98. snakeorm/dto/spec.py +201 -0
  99. snakeorm/expressions/__init__.py +88 -0
  100. snakeorm/expressions/conditional.py +178 -0
  101. snakeorm/expressions/expression.py +810 -0
  102. snakeorm/expressions/functions.py +71 -0
  103. snakeorm/expressions/keys.py +299 -0
  104. snakeorm/expressions/paths.py +43 -0
  105. snakeorm/expressions/scalar.py +293 -0
  106. snakeorm/expressions/window.py +248 -0
  107. snakeorm/fields/__init__.py +68 -0
  108. snakeorm/fields/check.py +79 -0
  109. snakeorm/fields/column.py +316 -0
  110. snakeorm/fields/enum.py +64 -0
  111. snakeorm/fields/index.py +46 -0
  112. snakeorm/fields/relationship.py +738 -0
  113. snakeorm/fields/typed.py +736 -0
  114. snakeorm/helpers/__init__.py +1 -0
  115. snakeorm/helpers/annotations.py +21 -0
  116. snakeorm/helpers/inheritance.py +41 -0
  117. snakeorm/helpers/pyliteral.py +52 -0
  118. snakeorm/helpers/pytype.py +50 -0
  119. snakeorm/introspection/__init__.py +13 -0
  120. snakeorm/introspection/base.py +30 -0
  121. snakeorm/introspection/drift.py +78 -0
  122. snakeorm/introspection/models.py +633 -0
  123. snakeorm/introspection/mysql.py +367 -0
  124. snakeorm/introspection/postgres.py +397 -0
  125. snakeorm/introspection/sqlite.py +217 -0
  126. snakeorm/introspection/unsupported.py +94 -0
  127. snakeorm/linker/__init__.py +3 -0
  128. snakeorm/linker/linker.py +521 -0
  129. snakeorm/metadata/__init__.py +41 -0
  130. snakeorm/metadata/check.py +37 -0
  131. snakeorm/metadata/column.py +201 -0
  132. snakeorm/metadata/enum_storage.py +33 -0
  133. snakeorm/metadata/fk_action.py +19 -0
  134. snakeorm/metadata/foreign_key.py +26 -0
  135. snakeorm/metadata/index.py +43 -0
  136. snakeorm/metadata/index_method.py +19 -0
  137. snakeorm/metadata/int_size.py +20 -0
  138. snakeorm/metadata/json_storage.py +21 -0
  139. snakeorm/metadata/polymorphic.py +30 -0
  140. snakeorm/metadata/primary_key.py +23 -0
  141. snakeorm/metadata/relationship.py +60 -0
  142. snakeorm/metadata/relationship_kind.py +43 -0
  143. snakeorm/metadata/routine.py +26 -0
  144. snakeorm/metadata/server_default.py +20 -0
  145. snakeorm/metadata/table.py +97 -0
  146. snakeorm/metadata/table_kind.py +23 -0
  147. snakeorm/metadata/trigger.py +62 -0
  148. snakeorm/metadata/type_params.py +348 -0
  149. snakeorm/migration/__init__.py +88 -0
  150. snakeorm/migration/asyncrunner.py +168 -0
  151. snakeorm/migration/autodetect.py +96 -0
  152. snakeorm/migration/ddl.py +1172 -0
  153. snakeorm/migration/diff.py +701 -0
  154. snakeorm/migration/loader.py +77 -0
  155. snakeorm/migration/operations.py +952 -0
  156. snakeorm/migration/planner.py +78 -0
  157. snakeorm/migration/realize.py +420 -0
  158. snakeorm/migration/renames.py +153 -0
  159. snakeorm/migration/render.py +1095 -0
  160. snakeorm/migration/runner.py +314 -0
  161. snakeorm/migration/squash.py +60 -0
  162. snakeorm/migration/state.py +107 -0
  163. snakeorm/model.py +162 -0
  164. snakeorm/py.typed +0 -0
  165. snakeorm/query/__init__.py +9 -0
  166. snakeorm/query/compound.py +288 -0
  167. snakeorm/query/join_kind.py +19 -0
  168. snakeorm/query/joined.py +143 -0
  169. snakeorm/query/query.py +1001 -0
  170. snakeorm/query/recursive.py +244 -0
  171. snakeorm/registry/__init__.py +5 -0
  172. snakeorm/registry/by_module.py +163 -0
  173. snakeorm/registry/registry.py +166 -0
  174. snakeorm/session/__init__.py +8 -0
  175. snakeorm/session/asyncsession.py +638 -0
  176. snakeorm/session/coercion.py +306 -0
  177. snakeorm/session/factory.py +29 -0
  178. snakeorm/session/guards.py +269 -0
  179. snakeorm/session/isolation.py +23 -0
  180. snakeorm/session/mapper.py +213 -0
  181. snakeorm/session/planning.py +815 -0
  182. snakeorm/session/retry.py +96 -0
  183. snakeorm/session/session.py +871 -0
  184. snakeorm/session/shared.py +355 -0
  185. snakeorm/sql/__init__.py +18 -0
  186. snakeorm/sql/adapt.py +104 -0
  187. snakeorm/sql/aggregate.py +232 -0
  188. snakeorm/sql/condition.py +359 -0
  189. snakeorm/sql/delete.py +46 -0
  190. snakeorm/sql/insert.py +149 -0
  191. snakeorm/sql/joins.py +158 -0
  192. snakeorm/sql/pk_subquery.py +54 -0
  193. snakeorm/sql/refs.py +19 -0
  194. snakeorm/sql/resolver.py +28 -0
  195. snakeorm/sql/select.py +175 -0
  196. snakeorm/sql/update.py +82 -0
  197. snakeorm/sql/value.py +552 -0
  198. snakeorm/times.py +276 -0
@@ -0,0 +1,616 @@
1
+ /* COMPONENTES del panel de debug: lo que va DENTRO del chasis (que define `snake_orm_app.css`) —
2
+ métricas/KPIs, avisos, herramientas, paginador, lista de queries y tarjetas de ayuda. Usa los
3
+ tokens (`var(--...)`) definidos en el shell, que se inlinea ANTES que este fichero. */
4
+ .snk .snk-metrics {
5
+ display: grid;
6
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
7
+ gap: 10px;
8
+ padding: 16px 20px
9
+ }
10
+
11
+ .snk .snk-m {
12
+ background: var(--bg);
13
+ border: 1px solid var(--bd);
14
+ border-radius: 12px;
15
+ padding: 11px 14px
16
+ }
17
+
18
+ .snk .snk-m[title] {
19
+ cursor: help
20
+ }
21
+
22
+ .snk .snk-m[title] span {
23
+ text-decoration: underline dotted;
24
+ text-decoration-color: var(--bd);
25
+ text-underline-offset: 2px
26
+ }
27
+
28
+ .snk .snk-m b {
29
+ display: block;
30
+ font-size: 20px;
31
+ font-weight: 700;
32
+ color: var(--txt)
33
+ }
34
+
35
+ .snk .snk-m b small {
36
+ font-size: 12px;
37
+ font-weight: 600;
38
+ color: var(--sub)
39
+ }
40
+
41
+ .snk .snk-m span {
42
+ color: var(--sub);
43
+ font-size: 10px;
44
+ text-transform: uppercase;
45
+ letter-spacing: .05em
46
+ }
47
+
48
+ .snk .snk-m.snk-hot b {
49
+ color: var(--warn)
50
+ }
51
+
52
+ /* Avisos (N+1) y sugerencias de índice: `<details>` colapsados por defecto para NO robarle alto a
53
+ la lista de queries. El summary es una línea (contador + título + caret); al abrir, la lista se
54
+ acota a 22vh y hace su propio scroll. Cero JS: es `<details>` nativo. */
55
+ .snk .snk-warns {
56
+ margin: 0 20px 12px;
57
+ border-radius: 12px;
58
+ background: rgba(251, 191, 36, .12);
59
+ border: 1px solid rgba(251, 191, 36, .32);
60
+ color: var(--acc);
61
+ font-size: 12px
62
+ }
63
+
64
+ .snk .snk-warns-sum,
65
+ .snk .snk-hints-sum {
66
+ display: flex;
67
+ align-items: center;
68
+ gap: 8px;
69
+ padding: 9px 14px;
70
+ cursor: pointer;
71
+ font-weight: 700;
72
+ list-style: none;
73
+ user-select: none
74
+ }
75
+
76
+ /* Ocultamos el triángulo nativo (no se puede tematizar) y ponemos uno propio que rota al abrir. */
77
+ .snk .snk-warns-sum::-webkit-details-marker,
78
+ .snk .snk-hints-sum::-webkit-details-marker {
79
+ display: none
80
+ }
81
+
82
+ .snk .snk-warns-sum::after,
83
+ .snk .snk-hints-sum::after {
84
+ content: '▸';
85
+ margin-left: auto;
86
+ font-size: 10px;
87
+ transition: transform .15s
88
+ }
89
+
90
+ .snk details[open] .snk-warns-sum::after,
91
+ .snk details[open] .snk-hints-sum::after {
92
+ transform: rotate(90deg)
93
+ }
94
+
95
+ .snk .snk-warns-badge,
96
+ .snk .snk-hints-badge {
97
+ background: rgba(251, 191, 36, .28);
98
+ color: var(--warn);
99
+ border-radius: 6px;
100
+ padding: 1px 8px;
101
+ font-size: 11px;
102
+ font-weight: 700
103
+ }
104
+
105
+ .snk .snk-warns-list,
106
+ .snk .snk-hints-list {
107
+ margin: 0;
108
+ padding: 0 14px 11px;
109
+ list-style: none;
110
+ max-height: 22vh;
111
+ overflow-y: auto
112
+ }
113
+
114
+ .snk .snk-warns-list li {
115
+ margin: 2px 0
116
+ }
117
+
118
+ .snk .snk-hints {
119
+ margin: 0 20px 12px;
120
+ border-radius: 12px;
121
+ background: rgba(61, 220, 132, .1);
122
+ border: 1px solid rgba(61, 220, 132, .3);
123
+ color: var(--sub);
124
+ font-size: 12px;
125
+ font-family: ui-monospace, monospace
126
+ }
127
+
128
+ .snk .snk-hints-sum {
129
+ font-family: ui-sans-serif, system-ui, sans-serif;
130
+ color: var(--acc)
131
+ }
132
+
133
+ .snk .snk-hints-badge {
134
+ background: rgba(61, 220, 132, .22);
135
+ color: var(--sel)
136
+ }
137
+
138
+ .snk .snk-hints-list li {
139
+ margin: 2px 0
140
+ }
141
+
142
+ .snk .snk-hints-list b {
143
+ color: var(--txt)
144
+ }
145
+
146
+ .snk .snk-hint-ms {
147
+ color: var(--warn);
148
+ font-weight: 700
149
+ }
150
+
151
+ .snk .snk-tools {
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 8px;
155
+ padding: 0 20px 12px
156
+ }
157
+
158
+ .snk .snk-btn {
159
+ background: var(--bg);
160
+ border: 1px solid var(--bd);
161
+ color: var(--sub);
162
+ border-radius: 8px;
163
+ padding: 6px 12px;
164
+ font-size: 12px;
165
+ font-weight: 600;
166
+ cursor: pointer
167
+ }
168
+
169
+ .snk .snk-btn:hover {
170
+ color: var(--txt);
171
+ border-color: var(--sub)
172
+ }
173
+
174
+ .snk .snk-ps {
175
+ margin-left: auto;
176
+ background: var(--bg);
177
+ border: 1px solid var(--bd);
178
+ color: var(--sub);
179
+ border-radius: 8px;
180
+ padding: 5px 8px;
181
+ font-size: 12px;
182
+ font-weight: 600;
183
+ cursor: pointer
184
+ }
185
+
186
+ .snk .snk-ps:hover {
187
+ color: var(--txt);
188
+ border-color: var(--sub)
189
+ }
190
+
191
+ .snk .snk-pager {
192
+ display: none;
193
+ align-items: center;
194
+ gap: 6px
195
+ }
196
+
197
+ .snk .snk-pager.snk-on {
198
+ display: flex
199
+ }
200
+
201
+ .snk .snk-pg {
202
+ background: var(--bg);
203
+ border: 1px solid var(--bd);
204
+ color: var(--txt);
205
+ border-radius: 7px;
206
+ width: 28px;
207
+ height: 28px;
208
+ cursor: pointer;
209
+ font-size: 16px;
210
+ line-height: 1;
211
+ display: flex;
212
+ align-items: center;
213
+ justify-content: center
214
+ }
215
+
216
+ .snk .snk-pg:disabled {
217
+ opacity: .4;
218
+ cursor: default
219
+ }
220
+
221
+ .snk .snk-pglabel {
222
+ font-size: 12px;
223
+ color: var(--sub);
224
+ min-width: 48px;
225
+ text-align: center
226
+ }
227
+
228
+ .snk .snk-help {
229
+ flex: 1;
230
+ overflow-y: auto;
231
+ padding: 16px 20px;
232
+ display: flex;
233
+ flex-direction: column;
234
+ gap: 12px
235
+ }
236
+
237
+ .snk .snk-help-card {
238
+ background: var(--bg);
239
+ border: 1px solid var(--bd);
240
+ border-radius: 12px;
241
+ padding: 12px 14px
242
+ }
243
+
244
+ .snk .snk-help-card h4 {
245
+ margin: 0 0 6px;
246
+ font-size: 13px;
247
+ font-weight: 700;
248
+ color: var(--txt)
249
+ }
250
+
251
+ .snk .snk-help-card p {
252
+ margin: 0;
253
+ font-size: 12px;
254
+ line-height: 1.6;
255
+ color: var(--sub)
256
+ }
257
+
258
+ .snk .snk-help-card p + p {
259
+ margin-top: 6px
260
+ }
261
+
262
+ .snk .snk-help-card code {
263
+ font-family: ui-monospace, monospace;
264
+ font-size: 12px;
265
+ background: var(--surf);
266
+ border: 1px solid var(--bd);
267
+ border-radius: 6px;
268
+ padding: 2px 6px;
269
+ color: var(--acc2)
270
+ }
271
+
272
+ .snk .snk-list {
273
+ flex: 1;
274
+ overflow-y: auto;
275
+ padding: 0 20px 24px
276
+ }
277
+
278
+ /* Scrollbar del panel: fino y en el tono del tema (WebKit + Firefox), no el nativo del SO. Aplica a
279
+ TODAS las zonas con scroll dentro del panel: la lista de queries, warnings/hints, el SQL ancho, etc. */
280
+ .snk ::-webkit-scrollbar {
281
+ width: 10px;
282
+ height: 10px
283
+ }
284
+
285
+ .snk ::-webkit-scrollbar-track {
286
+ background: transparent
287
+ }
288
+
289
+ .snk ::-webkit-scrollbar-thumb {
290
+ background: var(--bd);
291
+ border: 2px solid transparent;
292
+ border-radius: 8px;
293
+ background-clip: padding-box
294
+ }
295
+
296
+ .snk ::-webkit-scrollbar-thumb:hover {
297
+ background: var(--sub);
298
+ background-clip: padding-box
299
+ }
300
+
301
+ .snk * {
302
+ scrollbar-width: thin;
303
+ scrollbar-color: var(--bd) transparent
304
+ }
305
+
306
+ .snk .snk-q {
307
+ border: 1px solid var(--bd);
308
+ border-radius: 12px;
309
+ margin-bottom: 8px;
310
+ background: var(--bg);
311
+ overflow: hidden
312
+ }
313
+
314
+ .snk .snk-qh {
315
+ display: flex;
316
+ align-items: center;
317
+ gap: 10px;
318
+ width: 100%;
319
+ padding: 10px 14px;
320
+ background: transparent;
321
+ border: 0;
322
+ cursor: pointer;
323
+ text-align: left;
324
+ font-size: 11px;
325
+ color: var(--sub)
326
+ }
327
+
328
+ .snk .snk-qh:hover {
329
+ background: rgba(127, 127, 127, .06)
330
+ }
331
+
332
+ .snk .snk-tag {
333
+ padding: 2px 8px;
334
+ border-radius: 6px;
335
+ font-weight: 600;
336
+ font-size: 10px;
337
+ text-transform: uppercase
338
+ }
339
+
340
+ .snk .snk-tag.snk-select {
341
+ background: rgba(74, 222, 128, .16);
342
+ color: var(--sel)
343
+ }
344
+
345
+ .snk .snk-tag.snk-write {
346
+ background: rgba(251, 113, 133, .18);
347
+ color: var(--wrt)
348
+ }
349
+
350
+ .snk .snk-dup {
351
+ background: rgba(251, 191, 36, .18);
352
+ color: var(--warn);
353
+ padding: 2px 8px;
354
+ border-radius: 6px;
355
+ font-size: 10px;
356
+ font-weight: 600
357
+ }
358
+
359
+ .snk .snk-qn {
360
+ font-weight: 700;
361
+ color: var(--sub)
362
+ }
363
+
364
+ .snk .snk-qsql {
365
+ flex: 1;
366
+ min-width: 0;
367
+ font-family: ui-monospace, monospace;
368
+ font-size: 12px;
369
+ color: var(--sub);
370
+ white-space: nowrap;
371
+ overflow: hidden;
372
+ text-overflow: ellipsis
373
+ }
374
+
375
+ .snk .snk-q.snk-exp .snk-qsql {
376
+ display: none
377
+ }
378
+
379
+ .snk .snk-ms {
380
+ margin-left: auto;
381
+ font-weight: 700;
382
+ color: var(--txt);
383
+ white-space: nowrap;
384
+ font-size: 12px
385
+ }
386
+
387
+ .snk .snk-caret {
388
+ color: var(--sub);
389
+ transition: transform .15s;
390
+ font-size: 10px
391
+ }
392
+
393
+ .snk .snk-q.snk-exp .snk-caret {
394
+ transform: rotate(90deg)
395
+ }
396
+
397
+ .snk .snk-qbody {
398
+ display: none;
399
+ padding: 0 14px 14px
400
+ }
401
+
402
+ .snk .snk-q.snk-exp .snk-qbody {
403
+ display: block
404
+ }
405
+
406
+ .snk .snk-bar {
407
+ height: 5px;
408
+ border-radius: 3px;
409
+ background: var(--bd);
410
+ margin: 2px 0 10px;
411
+ overflow: hidden
412
+ }
413
+
414
+ .snk .snk-bar>i {
415
+ display: block;
416
+ height: 100%;
417
+ border-radius: 3px;
418
+ background: var(--sel)
419
+ }
420
+
421
+ .snk .snk-q.snk-w .snk-bar>i {
422
+ background: var(--wrt)
423
+ }
424
+
425
+ .snk .snk-sql {
426
+ font-family: ui-monospace, SFMono-Regular, monospace;
427
+ font-size: 13px;
428
+ line-height: 1.7;
429
+ white-space: pre-wrap;
430
+ word-break: break-word;
431
+ margin: 0;
432
+ color: var(--txt)
433
+ }
434
+
435
+ .snk .snk-kw {
436
+ color: var(--kw);
437
+ font-weight: 700
438
+ }
439
+
440
+ .snk .snk-pa {
441
+ font-family: ui-monospace, monospace;
442
+ font-size: 12px;
443
+ color: var(--sub);
444
+ margin: 8px 0 0;
445
+ word-break: break-word
446
+ }
447
+
448
+ .snk .snk-pa b {
449
+ color: var(--txt);
450
+ font-weight: 600
451
+ }
452
+
453
+ .snk .snk-origin {
454
+ font-family: ui-monospace, monospace;
455
+ font-size: 11px;
456
+ color: var(--acc);
457
+ margin-top: 8px;
458
+ word-break: break-word
459
+ }
460
+
461
+ .snk .snk-origin b {
462
+ color: var(--txt);
463
+ font-weight: 600
464
+ }
465
+
466
+ .snk .snk-origin span {
467
+ color: var(--sub)
468
+ }
469
+
470
+ .snk .snk-meta {
471
+ font-size: 11px;
472
+ color: var(--sub);
473
+ margin-top: 8px
474
+ }
475
+
476
+ .snk .snk-empty {
477
+ padding: 28px 20px;
478
+ text-align: center;
479
+ color: var(--sub);
480
+ font-size: 13px
481
+ }
482
+
483
+ /* Historial: la vista dinámica. El servidor pinta el esqueleto y el cliente añade sus `<li>` a
484
+ `.snk-history-list`. El aviso de canal solo se ve cuando la vista lleva `data-envelope="off"`,
485
+ y entonces la zona en vivo se va: sin envelope no puede haber nada que pintar. */
486
+ .snk .snk-history-off {
487
+ display: none
488
+ }
489
+
490
+ .snk .snk-view-history[data-envelope="off"] .snk-history-off {
491
+ display: block
492
+ }
493
+
494
+ .snk .snk-view-history[data-envelope="off"] .snk-history-live {
495
+ display: none
496
+ }
497
+
498
+ /* Las tarjetas del histórico: la MISMA rejilla y la misma tarjeta que la cabecera (`.snk-metrics`
499
+ / `.snk-m`), sin padding propio porque ya viven dentro de una `.snk-help-card`. `.snk-m-part` es
500
+ la cobertura: "3/5" cuando el agregado no ha podido contar con todas las llamadas. Va en ámbar
501
+ —el color de aviso del panel— y desaparece sola cuando el dato lo trajeron todas. */
502
+ .snk .snk-hmetrics {
503
+ padding: 0 0 10px
504
+ }
505
+
506
+ .snk .snk-m-part {
507
+ display: block;
508
+ margin-top: 2px;
509
+ font-size: 10px;
510
+ font-style: normal;
511
+ letter-spacing: .05em;
512
+ color: var(--warn)
513
+ }
514
+
515
+ .snk .snk-m-part:empty {
516
+ display: none
517
+ }
518
+
519
+ .snk .snk-history-list {
520
+ list-style: none;
521
+ margin: 8px 0 0;
522
+ padding: 0;
523
+ display: flex;
524
+ flex-direction: column;
525
+ gap: 6px
526
+ }
527
+
528
+ .snk .snk-history-list:empty {
529
+ margin: 0
530
+ }
531
+
532
+ /* El estado vacío se retira solo en cuanto el cliente añade la primera entrada: así la fase 2 solo
533
+ tiene que hacer `append`, sin acordarse de esconder nada. */
534
+ .snk .snk-history-live:has(.snk-history-list li) .snk-history-empty {
535
+ display: none
536
+ }
537
+
538
+ /* One entry: a native `<details>`, collapsed, whose `<summary>` is the line the reader scans. */
539
+ .snk .snk-h {
540
+ background: var(--surf);
541
+ border: 1px solid var(--bd);
542
+ border-radius: 8px
543
+ }
544
+
545
+ .snk .snk-h-head {
546
+ display: flex;
547
+ align-items: center;
548
+ gap: 8px;
549
+ padding: 7px 10px;
550
+ cursor: pointer;
551
+ font-size: 12px;
552
+ list-style: none
553
+ }
554
+
555
+ .snk .snk-h-head::-webkit-details-marker {
556
+ display: none
557
+ }
558
+
559
+ .snk .snk-h-head:hover {
560
+ background: rgba(127, 127, 127, .06)
561
+ }
562
+
563
+ .snk .snk-h-seq {
564
+ font-weight: 700;
565
+ color: var(--acc2);
566
+ min-width: 26px
567
+ }
568
+
569
+ .snk .snk-h-path {
570
+ flex: 1;
571
+ min-width: 0;
572
+ font-family: ui-monospace, monospace;
573
+ color: var(--txt);
574
+ white-space: nowrap;
575
+ overflow: hidden;
576
+ text-overflow: ellipsis
577
+ }
578
+
579
+ .snk .snk-h-status,
580
+ .snk .snk-h-n {
581
+ color: var(--sub);
582
+ white-space: nowrap
583
+ }
584
+
585
+ .snk .snk-h-body {
586
+ padding: 0 10px 10px;
587
+ border-top: 1px solid var(--bd)
588
+ }
589
+
590
+ .snk .snk-h-note {
591
+ margin: 8px 0 0;
592
+ font-size: 12px;
593
+ color: var(--sub)
594
+ }
595
+
596
+ .snk .snk-h-warn {
597
+ margin: 8px 0 0;
598
+ font-size: 12px;
599
+ color: var(--warn)
600
+ }
601
+
602
+ .snk .snk-h-q {
603
+ display: flex;
604
+ align-items: baseline;
605
+ gap: 8px;
606
+ margin-top: 8px
607
+ }
608
+
609
+ .snk .snk-h-sql {
610
+ flex: 1;
611
+ min-width: 0;
612
+ font-family: ui-monospace, monospace;
613
+ font-size: 12px;
614
+ color: var(--sub);
615
+ word-break: break-all
616
+ }