pgkiln 0.71.0 → 0.73.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 (77) hide show
  1. package/db/migrations/139_opentelemetry.sql +36 -0
  2. package/db/migrations/140_item_region_types.sql +27 -0
  3. package/docs/apex-feature-parity.md +86 -9
  4. package/docs/guide/01-installation.md +108 -0
  5. package/docs/guide/03-builder.md +9 -0
  6. package/docs/guide/04-pages-and-regions.md +41 -1
  7. package/docs/guide/05-items.md +43 -3
  8. package/docs/guide/09-reference.md +3 -0
  9. package/docs/guide/11-from-apex.md +3 -0
  10. package/docs/guide/12-development.md +23 -2
  11. package/examples/hr/hr_75_item_region_types.sql +81 -0
  12. package/package.json +1 -1
  13. package/public/app.css +48 -0
  14. package/public/app.js +427 -1
  15. package/public/builder.css +3 -0
  16. package/src/ai/service.ts +14 -0
  17. package/src/app.ts +10 -0
  18. package/src/builder/advisor.ts +5 -1
  19. package/src/builder/arrange.ts +7 -0
  20. package/src/builder/components.ts +5 -5
  21. package/src/builder/designer.ts +8 -2
  22. package/src/builder/home.ts +1 -0
  23. package/src/builder/i18n/de.ts +8 -0
  24. package/src/builder/i18n/en.ts +8 -0
  25. package/src/builder/i18n/es.ts +8 -0
  26. package/src/builder/i18n/fr.ts +8 -0
  27. package/src/builder/i18n/it.ts +8 -0
  28. package/src/builder/i18n/ja.ts +8 -0
  29. package/src/builder/i18n/ko.ts +8 -0
  30. package/src/builder/i18n/nl.ts +8 -0
  31. package/src/builder/i18n/pt.ts +8 -0
  32. package/src/builder/i18n/zh-cn.ts +8 -0
  33. package/src/builder/i18n/zh-tw.ts +8 -0
  34. package/src/builder/region-help.ts +8 -2
  35. package/src/builder/telemetry.ts +206 -0
  36. package/src/builder/workspaces.ts +2 -1
  37. package/src/i18n/ar.ts +13 -0
  38. package/src/i18n/cs.ts +13 -0
  39. package/src/i18n/da.ts +13 -0
  40. package/src/i18n/de.ts +13 -0
  41. package/src/i18n/el.ts +13 -0
  42. package/src/i18n/es.ts +13 -0
  43. package/src/i18n/fi.ts +13 -0
  44. package/src/i18n/fr.ts +13 -0
  45. package/src/i18n/he.ts +13 -0
  46. package/src/i18n/it.ts +13 -0
  47. package/src/i18n/ja.ts +13 -0
  48. package/src/i18n/ko.ts +13 -0
  49. package/src/i18n/nb.ts +13 -0
  50. package/src/i18n/pl.ts +13 -0
  51. package/src/i18n/pt.ts +13 -0
  52. package/src/i18n/ru.ts +13 -0
  53. package/src/i18n/sv.ts +13 -0
  54. package/src/i18n/tr.ts +13 -0
  55. package/src/i18n/uk.ts +13 -0
  56. package/src/i18n/zh.ts +13 -0
  57. package/src/i18n.ts +26 -0
  58. package/src/instance-checks.ts +11 -4
  59. package/src/layout.ts +2 -1
  60. package/src/mail/mail.ts +14 -0
  61. package/src/metadata.ts +5 -2
  62. package/src/runtime/ai-agents.ts +9 -0
  63. package/src/runtime/items.ts +32 -3
  64. package/src/runtime/page-regions.ts +50 -0
  65. package/src/runtime/region-cache.ts +1 -1
  66. package/src/runtime/regions.ts +11 -0
  67. package/src/runtime/render.ts +3 -17
  68. package/src/runtime/report.ts +55 -3
  69. package/src/runtime/routes.ts +3 -0
  70. package/src/session.ts +26 -0
  71. package/src/telemetry/browser.ts +91 -0
  72. package/src/telemetry/config.ts +342 -0
  73. package/src/telemetry/export.ts +484 -0
  74. package/src/telemetry/http.ts +126 -0
  75. package/src/telemetry/trace.ts +456 -0
  76. package/src/webclient.ts +25 -0
  77. package/src/workflow.ts +14 -7
@@ -649,6 +649,9 @@ pgkiln's icons; its filter box also searches the Lucide icons by name and search
649
649
  | `GET/POST /a/:alias/account`, `POST /a/:alias/account/password`, `POST /a/:alias/account/theme`, `POST /a/:alias/account/style` | My account, own password, the light/dark switch, the [style variant](14-globalization.md#style-variants-theme-roller) switch |
650
650
  | `POST /a/:alias/tz` | The browser's time zone for the session (automatic time zone; sent by `app.js`, CSRF token required) |
651
651
  | any page `?lang=xx` | Switch the language for the session |
652
+ | `POST /a/:alias/telemetry` | (0.72) Browser spans of a page whose trace goes to an OpenTelemetry collector (sent by `app.js`; a signed token of the page, 204) |
653
+ | `GET /metrics` | (0.72) Metrics in the Prometheus text format, when switched on: an administrator's builder session or `Authorization: Bearer <metrics token>` ([chapter 1](01-installation.md#monitoring-with-opentelemetry)) |
654
+ | `GET /healthz` | `ok` when the database is reachable (503 otherwise) |
652
655
  | `/builder/...` | Builder |
653
656
  | PostgREST (separate service, `API_URL`) | REST API of each app's `api` schema, see [chapter 13](13-rest-api.md) |
654
657
  | `/static/...` | CSS, JavaScript, icons |
@@ -59,6 +59,9 @@ What's missing is listed in the [feature parity matrix](../apex-feature-parity.m
59
59
  | `APEX_DATA_EXPORT.EXPORT` | `meta.data_export(query, format, options)` (CSV, JSON, XML, HTML) and the download process's `{"export": "xlsx"}` (also PDF) ([chapter 6](06-processing.md#data-export-from-sql)) |
60
60
  | `APEX_LANG.LANG`, dynamic translations | Shared Components → Dynamic translations and `meta.lang(text)` ([chapter 14](14-globalization.md#dynamic-translations)) |
61
61
  | Display Image, Geocoded Address items | Item types `image` and `address` (geocoder: `GEOCODER_URL`) ([chapter 5](05-items.md#display-image-and-geocoded-address)) |
62
+ | Shuttle, Select One, Select Many (24.2) items | Item types `shuttle` (ordered, colon-separated), `select_one` and `select_many` (a search field over the list of values; chips): plain selects without JavaScript ([chapter 5](05-items.md#shuttle-select-one-and-select-many)) |
63
+ | Classic Report region (report templates, pagination types) | Region type `classic_report`: `report_template` `standard`, `value_pairs`, `badges` or `media_list`; `pagination` `total`, `range` or `none` ([chapter 4](04-pages-and-regions.md#classic_report-classic-report)) |
64
+ | Breadcrumb region (Breadcrumb Bar), Help Text region and page help | Region types `breadcrumb` (from each page's *Breadcrumb parent*; no separate breadcrumb shared component) and `help_text`; the page's *Help text* (Markdown) ([chapter 4](04-pages-and-regions.md#breadcrumb-and-help_text)) |
62
65
  | Translated applications (XLIFF), `APEX_LANG.MESSAGE`, `&APP_TEXT$NAME.` | Translations in the app (XLIFF/CSV import and export), `meta.message()`, `&APP_TEXT$NAME.` ([chapter 14](14-globalization.md)) |
63
66
  | Application date format mask | Settings → Globalization → Date format (Oracle-style masks) |
64
67
  | Number format masks (`FML999G999G990D00`) on columns and items | `{"formats": {...}}` on report, grid and cards columns, `{"format_mask": "..."}` on charts and number/display items ([chapter 14](14-globalization.md#number-formats)) |
@@ -190,6 +190,16 @@ src/
190
190
  debug.ts debug messages: DebugLog (levels, timed steps, NOTICEs of meta.debug from appTx), started in
191
191
  loadContext, stored after the response (onResponse hook → meta.debug_save), hourly purge
192
192
  icons.ts icon helper (sprite in public/icons.svg)
193
+ telemetry/ (sprint 139, AP-6) OpenTelemetry without the SDK: trace.ts (the current trace in AsyncLocalStorage,
194
+ startTrace/endTrace, withSpan/rootSpan/recordSpan, traceApp, traceparent, a span per statement by
195
+ patching pg.Client#query, sanitizeSql/redactText, counters and histograms), config.ts (the instance's
196
+ settings: meta.setting otel_* over OTEL_* variables; workspaces' telemetry columns; app → workspace,
197
+ cached 30 s), export.ts (a queue per collector, OTLP/HTTP JSON for traces, logs and metrics, values
198
+ only where included, gauges from the queues, prometheusText(), sendTest()), http.ts (a trace per
199
+ request, request metrics, GET /metrics, POST /a/:alias/telemetry), browser.ts (the page's signed
200
+ <meta name="pgkiln-trace"> in layout.ts and relay() of what app.js reports). Spans come from
201
+ webclient.ts (outgoing calls, traceparent), ai/service.ts logUsage, runtime/ai-agents.ts logToolCall,
202
+ mail/mail.ts sendOne, workflow.ts runWorkflow; logs from session.ts logActivity
193
203
  history.ts (sprint 138, AP-5) change history and checksums: meta.app_snapshot (the export after the last recorded
194
204
  change), recordHistory() (export again, workingcopy.ts components() of both, each added/changed/deleted
195
205
  component with its files before and after into meta.component_change; called by app-updates.ts onSend,
@@ -211,6 +221,8 @@ src/
211
221
  logic.ts computations (the page's and (102) the application's), branches (page, URL, function returning a URL, another application) and their conditions
212
222
  shortcuts.ts (103) "NAME" shortcuts in static content, help texts and confirm messages
213
223
  render.ts page chrome (nav, breadcrumb), dynamic action JSON, theme (the page's nonce'd <style>, light/dark and style switches)
224
+ page-regions.ts (sprint 140) breadcrumb and help_text regions: breadcrumbLinks (also the title bar's trail, left out when the
225
+ page has a breadcrumb region), the page's help text (meta.page.help) as Markdown with escaped &ITEM. values
214
226
  styles.ts base styles (BASE_STYLES: Iris, Lavender, Standard; baseStyleOf → html data-style), Theme Roller style variants: fixed lists (fonts, sizes, corners), parseStyle/appStyles checks, the request's
215
227
  style (user choice, default), themeCss() (only hex values and constants reach the CSS); (sprint 117) NAV_APPEARANCES
216
228
  (Pillar Light / Dark), navAppearance() → the <body> classes nav-pillar-*, the header strip (--strip)
@@ -218,7 +230,10 @@ src/
218
230
  regions.ts region shell + chart (drill-down links, gauge settings)/cards/dynamic dispatch with row limits, lazy placeholder and cache, buttons (menu buttons, badges; (124) menu entries {action} → data-menu-entry for menu_entry dynamic actions)
219
231
  report.ts, report-views.ts (group by, pivot, chart), compute.ts (computed column expressions), grid.ts (aggregates, row actions, Actions menu, single row view, layoutFromForm), grid-layout.ts (column layouts: clean, arrange, per user), master-detail.ts (signed master row selection, details), facets.ts (facetChart: a facet's counts as a chart, sprint 65), items.ts
220
232
  (report.ts: paging with row ranges and max_rows, keyset paging (keysetPlan, seekCondition, signed r<id>_k), pagerNav, streamed CSV/Excel downloads with a cursor;
221
- items.ts: lovOptions, searchLov/lovLookup for popup LOVs, served by POST /a/:alias/:page/lov/:item/search in routes.ts)
233
+ (140) classic_report through renderReport: reportState drops the interactive settings, classicTemplate (value_pairs, badges, media_list),
234
+ pagination total/range/none;
235
+ items.ts: lovOptions, searchLov/lovLookup for popup LOVs, served by POST /a/:alias/:page/lov/:item/search in routes.ts;
236
+ LOV_TYPES / LOV_CHECKED / MULTI_VALUE: the list item types (shuttle, select_one, select_many since 140) checked on submit and colon-separated)
222
237
  region-cache.ts region caching (keys per scope, CSRF placeholder, invalidation on submit) and lazy regions (GET …/region/:id is in routes.ts)
223
238
  gantt-move.ts (sprint 69) Gantt drag and drop: ganttEditable, targetTime, moveGanttTask (the task in the region's
224
239
  query, gantt_move with :TASK_ID/:NEW_START/:NEW_END); the dragging itself is in app.js
@@ -392,6 +407,9 @@ src/
392
407
  vector-providers.ts (sprint 136, AP-1) Shared Components → Vector providers (/apps/:id/vector-providers: list, provider form,
393
408
  test, delete) and Workspace utilities → Vector providers (/vector-providers: pgvector status, Create
394
409
  extension for administrators, the workspace's providers and vector columns); pgvectorNote()
410
+ telemetry.ts (sprint 139, AP-6) Workspace utilities → OpenTelemetry (/telemetry: the collector, signals, values, user,
411
+ browser spans, /metrics and its token, status per collector, Send a test span; administrators) and a
412
+ workspace's own (/workspaces/:id/telemetry: as the instance / off / own collector; its administrators)
395
413
  data-security.ts (sprint 119) a table's Security: GET/POST /sql/objects/security?o= (policies, roles × columns, masks), Preview / Apply
396
414
  object-actions.ts (sprint 94) an object's ⋯ menu (objectMenu) in the worksheet and the Object Browser: Quick DDL (objectDdl), Drop with
397
415
  dependents, Add index / trigger / policy as drafts; GET /sql/objects/action, /sql/objects/panel (Open in a panel)
@@ -506,7 +524,8 @@ public/
506
524
  (sprint 117) navigation tree states, RTL via logical properties, body.nav-pillar-*, u-color-*-subtle, the busy bar)
507
525
  app.js client runtime: dialogs (dialog_closed actions), popup LOVs (sprint 115: the next page loads on scroll through an
508
526
  IntersectionObserver, ‹/More without one), dynamic actions (focus, classes, messages; sprint 115: wait_popup /
509
- remove_wait_popup as a modal <dialog class="wait-popup">, pgkiln.waitPopup(), the menu_entry event), grids (add/duplicate rows, master-detail refresh, move/resize columns, copy/paste of cell ranges), menus, lazy regions, maps (Leaflet layers, marker clusters, heat layer, layer legend, area/distance filter) (no inline JS)
527
+ remove_wait_popup as a modal <dialog class="wait-popup">, pgkiln.waitPopup(), the menu_entry event), (sprint 140) shuttle()
528
+ and selectPick() (Select One / Many: combobox + listbox, chips) over the item's hidden <select>, grids (add/duplicate rows, master-detail refresh, move/resize columns, copy/paste of cell ranges), menus, lazy regions, maps (Leaflet layers, marker clusters, heat layer, layer legend, area/distance filter) (no inline JS)
510
529
  code-editor.js, .css builder code editor: enhances <textarea data-code>, highlighting, suggestions (no dependencies);
511
530
  (sprint 108) the current line, and read-only <pre data-code-view="sql|plpgsql|json|html"> highlighted;
512
531
  its colours are the --ce-* tokens in builder.css
@@ -532,6 +551,7 @@ test/
532
551
  globalization.test.ts masks on HR page 29, time zones, the de/fr/es texts
533
552
  files.test.ts file items: storage, limits, downloads, temporary files
534
553
  items.test.ts rich text, Markdown, rating, combobox, date range, password reveal and QR code items
554
+ item-region-types.test.ts (sprint 140) shuttle, select one/many, classic report, breadcrumb and help text: gallery, runtime, export, Advisor, HR page 50
535
555
  dataload.test.ts parsing, Load Data, the data_load process
536
556
  sampledata.test.ts Sample Data: CHECK parsing, proposals, option errors, seeds and streams, preview/insert/rollback, parents first, downloads, saved generators
537
557
  unload.test.ts Unload Data: CSV/JSON/XLSX/XML output, read back with Load Data, read-only and one-statement checks, streaming
@@ -628,6 +648,7 @@ test/
628
648
  e2e/worksheet.test.ts (sprint 91) the SQL Worksheet in a browser: run keys, tabs, navigator, drag and drop, splitters, phone, no JavaScript;
629
649
  (107) transaction mode: badge, reload, Rollback, closing a tab, Autocommit switch, beforeunload
630
650
  e2e/items.test.ts sprint 26 item types in a browser: editors, tags, stars, dates, reveal; without JavaScript
651
+ e2e/item-region-types.test.ts (sprint 140) the shuttle (buttons, keyboard, order) and Select One / Many in a browser; without JavaScript; 390 px
631
652
  e2e/designer.test.ts page designer: panes per width, drag and drop, keyboard, Arrange buttons, builder theme
632
653
  e2e/calendar.test.ts calendar drag and drop and create on click, view switching, chart drill-down
633
654
  e2e/gantt.test.ts Gantt drag and drop: moving a task, its end, the keyboard, a click still drills down, the phone
@@ -0,0 +1,81 @@
1
+ -- =====================================================================
2
+ -- HR example, part 75: the item and region types of sprint 140 (AP-4;
3
+ -- migration 140; docs/guide/05-items.md, 04-pages-and-regions.md)
4
+ --
5
+ -- Page 50 "Project team" (Administration → Project team) puts a team
6
+ -- together the way an APEX page would:
7
+ --
8
+ -- - P50_DEPTNO, a Select One (a searchable single pick) of the
9
+ -- departments;
10
+ -- - P50_MEMBERS, a Shuttle of that department's employees (a cascading
11
+ -- list of values: choosing another department reloads it). The chosen
12
+ -- employees keep their order (Move up / Move down), stored
13
+ -- colon-separated like a multiselect: 7839:7566:7902;
14
+ -- - P50_SKILLS, a Select Many (chips) of a static list of values.
15
+ -- Without JavaScript the three are a plain select list and two
16
+ -- multi-selection lists, and Save works the same;
17
+ -- - "Chosen team", a Classic Report (no Actions menu) of the chosen
18
+ -- employees in the shuttle's order, and "Head count", a classic report
19
+ -- with the badges template;
20
+ -- - a Breadcrumb region in the Breadcrumb bar position (the title bar
21
+ -- then leaves its own trail out), and a Help Text region showing the
22
+ -- page's help text (Page → Help text, Markdown).
23
+ -- Save keeps the values in the session only: the page has no table.
24
+ -- =====================================================================
25
+
26
+ insert into meta.page (app_id, page_no, name, title, parent_page, help)
27
+ select id, 50, 'Project team', 'Project team', 1,
28
+ $h$Put a **project team** together:
29
+
30
+ 1. Choose a *department* (type to search the list).
31
+ 2. Move its employees from **Available** to **Selected** (double-click, Enter, or the › and » buttons) and put them in order with the arrow buttons.
32
+ 3. Choose the skills the team needs, then **Save**.
33
+
34
+ Team lead for now: &APP_USER..$h$
35
+ from meta.app where alias = 'hr';
36
+
37
+ insert into meta.region (page_id, seq, title, type, columns, template, position, source, config)
38
+ select p.id, r.seq, r.title, r.type, r.cols, r.template, r.position, r.source, r.config::jsonb
39
+ from meta.page p join meta.app a on a.id = p.app_id, (values
40
+ (5, 'Breadcrumb', 'breadcrumb', 12, 'plain', 'breadcrumb', null, '{}'),
41
+ (10, 'Team', 'static', 8, 'standard', null, null, '{}'),
42
+ (20, 'How it works', 'help_text', 4, 'standard', null, null, '{}'),
43
+ (30, 'Chosen team', 'classic_report', 8, 'standard', null,
44
+ 'select e.empno, e.ename, e.job, d.dname
45
+ from unnest(string_to_array(:P50_MEMBERS, '':'')) with ordinality m(empno, n)
46
+ join hr.emp e on e.empno::text = m.empno
47
+ left join hr.dept d on d.deptno = e.deptno
48
+ order by m.n',
49
+ '{"headings": {"empno": "No.", "ename": "Name", "job": "Job", "dname": "Department"}, "sortable": false, "pagination": "none", "empty": "Nobody chosen yet: move employees to Selected and save."}'),
50
+ (40, 'Head count', 'classic_report', 4, 'standard', null,
51
+ 'select d.dname as label, count(e.empno) as value
52
+ from hr.dept d left join hr.emp e on e.deptno = d.deptno
53
+ group by d.dname order by d.dname',
54
+ '{"report_template": "badges", "pagination": "none"}')
55
+ ) as r (seq, title, type, cols, template, position, source, config)
56
+ where a.alias = 'hr' and p.page_no = 50;
57
+
58
+ insert into meta.item (page_id, region_id, seq, name, label, type, lov, config, help)
59
+ select p.id, r.id, i.seq, i.name, i.label, i.type, i.lov, i.config::jsonb, i.help
60
+ from meta.page p join meta.app a on a.id = p.app_id
61
+ join meta.region r on r.page_id = p.id and r.title = 'Team', (values
62
+ (10, 'P50_DEPTNO', 'Department', 'select_one', 'select dname, deptno from hr.dept order by 1', '{"wide": true}', null),
63
+ (20, 'P50_MEMBERS', 'Team members', 'shuttle',
64
+ 'select ename || '' ('' || coalesce(job, ''-'') || '')'' as d, empno as r from hr.emp where deptno = :P50_DEPTNO order by ename',
65
+ '{"cascade_parents": "P50_DEPTNO", "wide": true}', 'In the order they lead the project.'),
66
+ (30, 'P50_SKILLS', 'Skills needed', 'select_many',
67
+ 'STATIC:SQL;SQL,PL/pgSQL;PLPGSQL,TypeScript;TS,Design;DESIGN,Testing;TEST,Accessibility;A11Y',
68
+ '{"wide": true}', null)
69
+ ) as i (seq, name, label, type, lov, config, help)
70
+ where a.alias = 'hr' and p.page_no = 50;
71
+
72
+ insert into meta.button (page_id, region_id, seq, name, label, action, hot)
73
+ select p.id, r.id, 10, 'SAVE', 'Save', 'submit', true
74
+ from meta.page p join meta.app a on a.id = p.app_id
75
+ join meta.region r on r.page_id = p.id and r.title = 'Team'
76
+ where a.alias = 'hr' and p.page_no = 50;
77
+
78
+ insert into meta.nav_entry (app_id, parent_id, seq, label, icon, target_page)
79
+ select a.id, n.id, 70, 'Project team', 'users', 50
80
+ from meta.app a join meta.nav_entry n on n.app_id = a.id and n.label = 'Administration' and n.parent_id is null
81
+ where a.alias = 'hr';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.71.0",
3
+ "version": "0.73.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
package/public/app.css CHANGED
@@ -1693,6 +1693,54 @@ td.tc-cell { overflow-wrap: anywhere; }
1693
1693
  }
1694
1694
  .tag-remove:hover, .tag-remove:focus-visible { background: var(--surface-3); }
1695
1695
 
1696
+ /* (140) shuttle: two lists, the move buttons between them and the order buttons after them (stacked on phones) */
1697
+ .shuttle-ui { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto; gap: 0.5rem; align-items: stretch; }
1698
+ .shuttle-col { display: flex; flex-direction: column; gap: 0.35rem; min-width: 0; }
1699
+ .shuttle-col .shuttle-list { flex: 1; min-height: 9rem; }
1700
+ .shuttle-moves, .shuttle-order { display: flex; flex-direction: column; justify-content: center; gap: 0.3rem; }
1701
+ .shuttle-btn { min-width: 2.4rem; justify-content: center; font-size: 1rem; line-height: 1; }
1702
+ [dir=rtl] .shuttle-moves .shuttle-btn span { display: inline-block; transform: scaleX(-1); }
1703
+ @media (max-width: 640px) {
1704
+ .shuttle-ui { grid-template-columns: minmax(0, 1fr) auto; }
1705
+ .shuttle-col:first-child { grid-column: 1 / -1; }
1706
+ .shuttle-moves { grid-column: 1 / -1; flex-direction: row; justify-content: center; }
1707
+ .shuttle-moves .shuttle-btn span { display: inline-block; transform: rotate(90deg); }
1708
+ }
1709
+ /* (140) select one / select many: a search field with a list box under it; chips above it */
1710
+ .select-pick-ui { position: relative; display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
1711
+ .select-pick-list {
1712
+ position: absolute; z-index: 30; top: 100%; inset-inline: 0; margin: 0.15rem 0 0; padding: 0.25rem 0; list-style: none; max-height: 16rem; overflow-y: auto;
1713
+ background: var(--surface); border: 1px solid var(--border); border-radius: calc(var(--radius) * 0.75); box-shadow: var(--shadow);
1714
+ }
1715
+ .select-pick-list[hidden] { display: none; }
1716
+ .select-pick-list li { padding: 0.4rem 0.7rem; cursor: pointer; overflow-wrap: anywhere; }
1717
+ .select-pick-list li[aria-selected=true] { font-weight: 600; }
1718
+ .select-pick-list li[aria-selected=true]::before { content: "✓ "; }
1719
+ .select-pick-list li.is-active, .select-pick-list li:hover { background: var(--surface-3); }
1720
+ .select-pick-list li.select-pick-none { cursor: default; color: var(--muted); }
1721
+ /* (140) a breadcrumb region and a help text region */
1722
+ .region-crumbs .crumbs { font-size: 0.9rem; margin: 0; }
1723
+ .region-crumbs .crumbs [aria-current] { color: var(--text); font-weight: 600; }
1724
+ .help-text { overflow-wrap: anywhere; }
1725
+ .help-text > :first-child { margin-top: 0; }
1726
+ .help-text > :last-child { margin-bottom: 0; }
1727
+ /* (140) classic report templates */
1728
+ .cr-pairs { display: flex; flex-direction: column; gap: 0.75rem; }
1729
+ .cr-pairs dl { display: grid; grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr); gap: 0.25rem 1rem; margin: 0; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
1730
+ .cr-pairs dl:last-child { border-bottom: 0; padding-bottom: 0; }
1731
+ .cr-pairs dt { font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
1732
+ .cr-pairs dd { margin: 0; overflow-wrap: anywhere; }
1733
+ .cr-badges { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr)); gap: 0.6rem; list-style: none; margin: 0; padding: 0; }
1734
+ .cr-badges li { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; padding: 0.7rem; border: 1px solid var(--border); border-radius: var(--radius); text-align: center; overflow-wrap: anywhere; }
1735
+ .cr-badges .cr-badge-value { font-size: 1.4rem; font-weight: 700; }
1736
+ .cr-badges .cr-badge-label { font-size: 0.85rem; color: var(--muted); }
1737
+ .cr-media { list-style: none; margin: 0; padding: 0; }
1738
+ .cr-media li { padding: 0.6rem 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
1739
+ .cr-media li:last-child { border-bottom: 0; }
1740
+ .cr-media .cr-media-title { font-weight: 600; }
1741
+ .cr-media .cr-media-text { margin: 0.15rem 0 0; color: var(--muted); }
1742
+ @media (max-width: 640px) { .cr-pairs dl { grid-template-columns: minmax(0, 1fr); } }
1743
+
1696
1744
  .date-range { display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; }
1697
1745
  .range-part { display: flex; align-items: center; gap: 0.4rem; flex: 1 1 12rem; min-width: 0; }
1698
1746
  .range-part .sub { font-size: 0.85rem; color: var(--muted); min-width: 2.2rem; }