mostlyright-data 0.9.0__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 (314) hide show
  1. mostlyright/data_harness/__init__.py +158 -0
  2. mostlyright/data_harness/acquisition/__init__.py +55 -0
  3. mostlyright/data_harness/acquisition/http.py +2773 -0
  4. mostlyright/data_harness/acquisition/parsing.py +809 -0
  5. mostlyright/data_harness/acquisition/ranges.py +495 -0
  6. mostlyright/data_harness/acquisition/result_download.py +360 -0
  7. mostlyright/data_harness/acquisition/retention_admission.py +248 -0
  8. mostlyright/data_harness/acquisition/sandbox.py +4888 -0
  9. mostlyright/data_harness/acquisition/url_policy.py +530 -0
  10. mostlyright/data_harness/agent_runtime.py +2743 -0
  11. mostlyright/data_harness/assets/logo-ink.svg +31 -0
  12. mostlyright/data_harness/backends/__init__.py +28 -0
  13. mostlyright/data_harness/backends/pandas_backend.py +350 -0
  14. mostlyright/data_harness/backends/polars_backend.py +366 -0
  15. mostlyright/data_harness/backends/protocol.py +124 -0
  16. mostlyright/data_harness/backends/reference.py +83 -0
  17. mostlyright/data_harness/backends/registry.py +55 -0
  18. mostlyright/data_harness/backends/restrictions.py +126 -0
  19. mostlyright/data_harness/canonical.py +333 -0
  20. mostlyright/data_harness/catalog_job.py +625 -0
  21. mostlyright/data_harness/cli.py +5398 -0
  22. mostlyright/data_harness/contracts.py +53 -0
  23. mostlyright/data_harness/coordinator.py +1307 -0
  24. mostlyright/data_harness/deploy.py +924 -0
  25. mostlyright/data_harness/deploy_target.py +312 -0
  26. mostlyright/data_harness/deployment_evidence.py +1067 -0
  27. mostlyright/data_harness/event_presentation.py +576 -0
  28. mostlyright/data_harness/events.py +2152 -0
  29. mostlyright/data_harness/fast_delimited.py +239 -0
  30. mostlyright/data_harness/fleet.py +237 -0
  31. mostlyright/data_harness/formats.py +236 -0
  32. mostlyright/data_harness/governors.py +1163 -0
  33. mostlyright/data_harness/hosted_bootstrap.py +972 -0
  34. mostlyright/data_harness/hosted_crawler.py +1115 -0
  35. mostlyright/data_harness/hosted_crawler_container_smoke.py +351 -0
  36. mostlyright/data_harness/hosted_crawler_fetch.py +423 -0
  37. mostlyright/data_harness/hosted_crawler_job.py +1277 -0
  38. mostlyright/data_harness/hosted_crawler_protocol.py +676 -0
  39. mostlyright/data_harness/hosted_dataset.py +1500 -0
  40. mostlyright/data_harness/hosted_deploy.py +3037 -0
  41. mostlyright/data_harness/hosted_handoff.py +62 -0
  42. mostlyright/data_harness/hosted_ingestion_contract.py +504 -0
  43. mostlyright/data_harness/hosted_ingestion_job.py +356 -0
  44. mostlyright/data_harness/hosted_ingestion_job_smoke.py +40 -0
  45. mostlyright/data_harness/hosted_session_container_smoke.py +194 -0
  46. mostlyright/data_harness/hosted_session_worker.py +3554 -0
  47. mostlyright/data_harness/hosted_session_worker_job_smoke.py +46 -0
  48. mostlyright/data_harness/hosted_worker.py +6784 -0
  49. mostlyright/data_harness/ingestion/__init__.py +56 -0
  50. mostlyright/data_harness/ingestion/contracts.py +461 -0
  51. mostlyright/data_harness/ingestion/faults.py +42 -0
  52. mostlyright/data_harness/ingestion/gcs_store.py +1162 -0
  53. mostlyright/data_harness/ingestion/spool.py +130 -0
  54. mostlyright/data_harness/ingestion/store.py +885 -0
  55. mostlyright/data_harness/key_seam.py +434 -0
  56. mostlyright/data_harness/linux_process_boundary.py +262 -0
  57. mostlyright/data_harness/local_contracts.py +2880 -0
  58. mostlyright/data_harness/local_search/__init__.py +5 -0
  59. mostlyright/data_harness/local_search/build_index.py +1087 -0
  60. mostlyright/data_harness/local_search/contracts.py +920 -0
  61. mostlyright/data_harness/local_search/query_trace.py +266 -0
  62. mostlyright/data_harness/local_search/retrieval.py +700 -0
  63. mostlyright/data_harness/local_search/sealed.py +474 -0
  64. mostlyright/data_harness/local_search/service.py +784 -0
  65. mostlyright/data_harness/nbrender/CONTRACT.md +212 -0
  66. mostlyright/data_harness/nbrender/__init__.py +12 -0
  67. mostlyright/data_harness/nbrender/chrome.py +359 -0
  68. mostlyright/data_harness/nbrender/code_body.py +266 -0
  69. mostlyright/data_harness/nbrender/document.py +407 -0
  70. mostlyright/data_harness/nbrender/frame.py +275 -0
  71. mostlyright/data_harness/nbrender/interactive.py +337 -0
  72. mostlyright/data_harness/nbrender/markdown_body.py +477 -0
  73. mostlyright/data_harness/nbrender/mr_components.py +134 -0
  74. mostlyright/data_harness/nbrender/outputs_data.py +595 -0
  75. mostlyright/data_harness/nbrender/outputs_rich.py +906 -0
  76. mostlyright/data_harness/nbrender/outputs_source.py +260 -0
  77. mostlyright/data_harness/nbrender/outputs_stage.py +176 -0
  78. mostlyright/data_harness/nbrender/outputs_text.py +400 -0
  79. mostlyright/data_harness/nbrender/parse.py +394 -0
  80. mostlyright/data_harness/nbrender/status.py +40 -0
  81. mostlyright/data_harness/nbrender/tokens.py +1295 -0
  82. mostlyright/data_harness/notebook.py +1710 -0
  83. mostlyright/data_harness/offline.py +2049 -0
  84. mostlyright/data_harness/operation_registry.py +1007 -0
  85. mostlyright/data_harness/operator_setup.py +239 -0
  86. mostlyright/data_harness/pipeline.py +6428 -0
  87. mostlyright/data_harness/plan_graph.py +2026 -0
  88. mostlyright/data_harness/preparation/__init__.py +104 -0
  89. mostlyright/data_harness/preparation/contracts.py +1017 -0
  90. mostlyright/data_harness/preparation/engine.py +221 -0
  91. mostlyright/data_harness/preparation/errors.py +14 -0
  92. mostlyright/data_harness/preparation/gates.py +751 -0
  93. mostlyright/data_harness/preparation/joins.py +574 -0
  94. mostlyright/data_harness/preparation/profile.py +384 -0
  95. mostlyright/data_harness/preparation/table.py +217 -0
  96. mostlyright/data_harness/preparation/transforms.py +568 -0
  97. mostlyright/data_harness/progress_events.py +534 -0
  98. mostlyright/data_harness/readers/__init__.py +46 -0
  99. mostlyright/data_harness/readers/containers.py +963 -0
  100. mostlyright/data_harness/readers/contracts.py +542 -0
  101. mostlyright/data_harness/readers/delimited.py +257 -0
  102. mostlyright/data_harness/readers/grib2/__init__.py +33 -0
  103. mostlyright/data_harness/readers/grib2/admission.py +722 -0
  104. mostlyright/data_harness/readers/grib2/decode.py +1009 -0
  105. mostlyright/data_harness/readers/grib2/geometry.py +1133 -0
  106. mostlyright/data_harness/readers/grib2/portable_math.py +501 -0
  107. mostlyright/data_harness/readers/json_tabular.py +485 -0
  108. mostlyright/data_harness/readers/registry.py +514 -0
  109. mostlyright/data_harness/readers/samples/README.md +110 -0
  110. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
  111. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +24 -0
  112. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
  113. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +24 -0
  114. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
  115. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +24 -0
  116. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
  117. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +24 -0
  118. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
  119. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +25 -0
  120. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  121. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +25 -0
  122. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  123. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +25 -0
  124. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +3 -0
  125. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +23 -0
  126. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +5 -0
  127. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +25 -0
  128. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +30 -0
  129. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +5 -0
  130. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +44 -0
  131. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +1 -0
  132. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +48 -0
  133. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +4 -0
  134. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
  135. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +24 -0
  136. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  137. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  138. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  139. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  140. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +20 -0
  141. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +55 -0
  142. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
  143. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +54 -0
  144. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  145. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +54 -0
  146. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
  147. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +54 -0
  148. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  149. mostlyright/data_harness/readers/samples.py +582 -0
  150. mostlyright/data_harness/readers/spreadsheet.py +803 -0
  151. mostlyright/data_harness/readers/tabular.py +510 -0
  152. mostlyright/data_harness/recipe.py +5321 -0
  153. mostlyright/data_harness/repair/__init__.py +78 -0
  154. mostlyright/data_harness/repair/adapters.py +274 -0
  155. mostlyright/data_harness/repair/contracts.py +872 -0
  156. mostlyright/data_harness/repair/coordinator.py +1099 -0
  157. mostlyright/data_harness/repair/errors.py +16 -0
  158. mostlyright/data_harness/review.py +2533 -0
  159. mostlyright/data_harness/rowset.py +283 -0
  160. mostlyright/data_harness/serving.py +1975 -0
  161. mostlyright/data_harness/serving_edge.py +590 -0
  162. mostlyright/data_harness/serving_http.py +1031 -0
  163. mostlyright/data_harness/session_probes.py +759 -0
  164. mostlyright/data_harness/signing.py +101 -0
  165. mostlyright/data_harness/source_discovery.py +898 -0
  166. mostlyright/data_harness/sources/__init__.py +209 -0
  167. mostlyright/data_harness/sources/_adapter_steps.py +213 -0
  168. mostlyright/data_harness/sources/adapters.py +1214 -0
  169. mostlyright/data_harness/sources/cadence.py +1428 -0
  170. mostlyright/data_harness/sources/cadence_emission.py +453 -0
  171. mostlyright/data_harness/sources/cadence_history.py +546 -0
  172. mostlyright/data_harness/sources/catalog/__init__.py +17 -0
  173. mostlyright/data_harness/sources/catalog/admission.py +477 -0
  174. mostlyright/data_harness/sources/catalog/authoring.py +1701 -0
  175. mostlyright/data_harness/sources/catalog/authoring_policy.py +701 -0
  176. mostlyright/data_harness/sources/catalog/authoring_shards.py +1217 -0
  177. mostlyright/data_harness/sources/catalog/bounded_io.py +231 -0
  178. mostlyright/data_harness/sources/catalog/channel.py +523 -0
  179. mostlyright/data_harness/sources/catalog/channel_client.py +296 -0
  180. mostlyright/data_harness/sources/catalog/contracts.py +825 -0
  181. mostlyright/data_harness/sources/catalog/coverage.py +137 -0
  182. mostlyright/data_harness/sources/catalog/delta.py +1340 -0
  183. mostlyright/data_harness/sources/catalog/embedding.py +532 -0
  184. mostlyright/data_harness/sources/catalog/entry_v2.py +1182 -0
  185. mostlyright/data_harness/sources/catalog/fill.py +3889 -0
  186. mostlyright/data_harness/sources/catalog/fill_partitions.py +459 -0
  187. mostlyright/data_harness/sources/catalog/fill_staging.py +1105 -0
  188. mostlyright/data_harness/sources/catalog/gating.py +374 -0
  189. mostlyright/data_harness/sources/catalog/generation_receipt.py +1607 -0
  190. mostlyright/data_harness/sources/catalog/harvest/__init__.py +7 -0
  191. mostlyright/data_harness/sources/catalog/harvest/ckan.py +384 -0
  192. mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +798 -0
  193. mostlyright/data_harness/sources/catalog/harvest/protocol.py +964 -0
  194. mostlyright/data_harness/sources/catalog/harvest/sdmx.py +445 -0
  195. mostlyright/data_harness/sources/catalog/harvest/stac.py +384 -0
  196. mostlyright/data_harness/sources/catalog/health.py +447 -0
  197. mostlyright/data_harness/sources/catalog/hosted_catalog.py +105 -0
  198. mostlyright/data_harness/sources/catalog/identity_history.py +1549 -0
  199. mostlyright/data_harness/sources/catalog/neural.py +1618 -0
  200. mostlyright/data_harness/sources/catalog/packed_catalog.py +2345 -0
  201. mostlyright/data_harness/sources/catalog/packed_retrieval.py +1517 -0
  202. mostlyright/data_harness/sources/catalog/packed_writer.py +2802 -0
  203. mostlyright/data_harness/sources/catalog/query_trace.py +1037 -0
  204. mostlyright/data_harness/sources/catalog/recommend.py +171 -0
  205. mostlyright/data_harness/sources/catalog/retrieval.py +230 -0
  206. mostlyright/data_harness/sources/catalog/retrieval_manifest.py +995 -0
  207. mostlyright/data_harness/sources/catalog/rights_decisions.py +254 -0
  208. mostlyright/data_harness/sources/catalog/sealed.py +560 -0
  209. mostlyright/data_harness/sources/catalog/search.py +230 -0
  210. mostlyright/data_harness/sources/catalog/streaming_delta.py +1097 -0
  211. mostlyright/data_harness/sources/catalog/update.py +891 -0
  212. mostlyright/data_harness/sources/collections.py +815 -0
  213. mostlyright/data_harness/sources/contracts.py +2223 -0
  214. mostlyright/data_harness/sources/deletion.py +761 -0
  215. mostlyright/data_harness/sources/fitness.py +162 -0
  216. mostlyright/data_harness/sources/governance.py +163 -0
  217. mostlyright/data_harness/sources/hosted.py +173 -0
  218. mostlyright/data_harness/sources/integration.py +218 -0
  219. mostlyright/data_harness/sources/range_reader.py +418 -0
  220. mostlyright/data_harness/sources/registry.py +514 -0
  221. mostlyright/data_harness/sources/rights_rule.py +59 -0
  222. mostlyright/data_harness/sources/source_cadence_vectors.v1.json +1 -0
  223. mostlyright/data_harness/sources/sports.py +521 -0
  224. mostlyright/data_harness/sources/stream.py +524 -0
  225. mostlyright/data_harness/sources/stream_connector.py +418 -0
  226. mostlyright/data_harness/sources/stream_recorder.py +1404 -0
  227. mostlyright/data_harness/studio_boundary.py +2019 -0
  228. mostlyright/data_harness/thin/__init__.py +37 -0
  229. mostlyright/data_harness/thin/acquire.py +1137 -0
  230. mostlyright/data_harness/thin/acquire_cancel.py +579 -0
  231. mostlyright/data_harness/thin/approvals.py +617 -0
  232. mostlyright/data_harness/thin/commands.py +406 -0
  233. mostlyright/data_harness/thin/download.py +194 -0
  234. mostlyright/data_harness/thin/narrative.py +589 -0
  235. mostlyright/data_harness/thin/parity.py +1070 -0
  236. mostlyright/data_harness/thin/propose.py +2759 -0
  237. mostlyright/data_harness/thin/research.py +1663 -0
  238. mostlyright/data_harness/thin/router.py +924 -0
  239. mostlyright/data_harness/thin/runs.py +519 -0
  240. mostlyright/data_harness/thin/session.py +281 -0
  241. mostlyright/data_harness/thin/stream.py +501 -0
  242. mostlyright/data_harness/thin/transport.py +187 -0
  243. mostlyright/data_harness/thin/vocabulary.py +368 -0
  244. mostlyright/data_harness/thin/workers.py +164 -0
  245. mostlyright/data_harness/ucum/TABLE-PIN.json +40 -0
  246. mostlyright/data_harness/ucum/ucum-subset.v1.json +632 -0
  247. mostlyright/data_harness/unit_flow.py +927 -0
  248. mostlyright/data_harness/units.py +572 -0
  249. mostlyright/data_harness/ux/__init__.py +9 -0
  250. mostlyright/data_harness/ux/approve.py +485 -0
  251. mostlyright/data_harness/ux/author_yaml.py +597 -0
  252. mostlyright/data_harness/ux/cloud_auth.py +447 -0
  253. mostlyright/data_harness/ux/commands/__init__.py +260 -0
  254. mostlyright/data_harness/ux/commands/approve.py +136 -0
  255. mostlyright/data_harness/ux/commands/auth.py +744 -0
  256. mostlyright/data_harness/ux/commands/author.py +79 -0
  257. mostlyright/data_harness/ux/commands/catalog_author.py +403 -0
  258. mostlyright/data_harness/ux/commands/catalog_fill.py +523 -0
  259. mostlyright/data_harness/ux/commands/catalog_harvest.py +545 -0
  260. mostlyright/data_harness/ux/commands/catalog_publish.py +1838 -0
  261. mostlyright/data_harness/ux/commands/catalog_search.py +71 -0
  262. mostlyright/data_harness/ux/commands/catalog_update.py +437 -0
  263. mostlyright/data_harness/ux/commands/deploy.py +134 -0
  264. mostlyright/data_harness/ux/commands/deploy_dataset.py +98 -0
  265. mostlyright/data_harness/ux/commands/deploy_plan.py +105 -0
  266. mostlyright/data_harness/ux/commands/deploy_status.py +104 -0
  267. mostlyright/data_harness/ux/commands/diff.py +74 -0
  268. mostlyright/data_harness/ux/commands/index.py +84 -0
  269. mostlyright/data_harness/ux/commands/inventory.py +47 -0
  270. mostlyright/data_harness/ux/commands/list_builds.py +143 -0
  271. mostlyright/data_harness/ux/commands/login.py +63 -0
  272. mostlyright/data_harness/ux/commands/peek.py +236 -0
  273. mostlyright/data_harness/ux/commands/plan_check.py +90 -0
  274. mostlyright/data_harness/ux/commands/preflight.py +97 -0
  275. mostlyright/data_harness/ux/commands/record.py +107 -0
  276. mostlyright/data_harness/ux/commands/review_setup.py +47 -0
  277. mostlyright/data_harness/ux/commands/search.py +440 -0
  278. mostlyright/data_harness/ux/commands/show.py +61 -0
  279. mostlyright/data_harness/ux/commands/whoami.py +37 -0
  280. mostlyright/data_harness/ux/credential_native.py +551 -0
  281. mostlyright/data_harness/ux/credential_store.py +1055 -0
  282. mostlyright/data_harness/ux/credentials.py +631 -0
  283. mostlyright/data_harness/ux/diffing.py +444 -0
  284. mostlyright/data_harness/ux/headline.py +671 -0
  285. mostlyright/data_harness/ux/hosted_acquisition.py +974 -0
  286. mostlyright/data_harness/ux/hosted_run_status.py +619 -0
  287. mostlyright/data_harness/ux/inventory.py +427 -0
  288. mostlyright/data_harness/ux/local_review.py +375 -0
  289. mostlyright/data_harness/ux/login.py +691 -0
  290. mostlyright/data_harness/ux/path_kind.py +147 -0
  291. mostlyright/data_harness/ux/peek.py +1000 -0
  292. mostlyright/data_harness/ux/plain_file.py +178 -0
  293. mostlyright/data_harness/ux/plan_check.py +311 -0
  294. mostlyright/data_harness/ux/preflight.py +918 -0
  295. mostlyright/data_harness/ux/readers.py +1124 -0
  296. mostlyright/data_harness/ux/remediation.py +2195 -0
  297. mostlyright/data_harness/ux/render.py +657 -0
  298. mostlyright/data_harness/ux/workload.py +1077 -0
  299. mostlyright/data_harness/viewer.py +3713 -0
  300. mostlyright/data_harness/visual_run/__init__.py +83 -0
  301. mostlyright/data_harness/visual_run/authoring.py +235 -0
  302. mostlyright/data_harness/visual_run/contracts.py +673 -0
  303. mostlyright/data_harness/visual_run/materialize.py +486 -0
  304. mostlyright/data_harness/visual_run/observations.py +874 -0
  305. mostlyright/data_harness/visual_run/query.py +259 -0
  306. mostlyright/data_harness/visual_run/reducer.py +280 -0
  307. mostlyright/data_harness/visual_run/sdk.py +892 -0
  308. mostlyright/data_harness/visual_run/store.py +584 -0
  309. mostlyright/data_harness/visual_run/transport.py +239 -0
  310. mostlyright/data_harness/watch.py +2999 -0
  311. mostlyright_data-0.9.0.dist-info/METADATA +607 -0
  312. mostlyright_data-0.9.0.dist-info/RECORD +314 -0
  313. mostlyright_data-0.9.0.dist-info/WHEEL +4 -0
  314. mostlyright_data-0.9.0.dist-info/entry_points.txt +12 -0
@@ -0,0 +1,1295 @@
1
+ """Design tokens and the single stylesheet the renderer ever emits.
2
+
3
+ This module is the design system of record: every hex, size, and geometry appears here exactly
4
+ once, and nowhere else in the package. Components never carry their own CSS — they emit
5
+ ``nb-``-prefixed kebab classes and this module owns the rules those classes resolve against, so
6
+ the palette cannot drift between modules. ``build_css`` is the only place literal color escapes
7
+ into output, and everything it emits is scoped under ``.nb-shell`` so an embed render cannot leak
8
+ style onto a host marketing page.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ # --- Color --------------------------------------------------------------------------------------
14
+ # Core palette.
15
+ BLACK = "#0D0D0D" # reserved — never the code panel
16
+ INK = "#17160F" # header bg, body text, headings
17
+ BODY = "#3B382F" # markdown paragraph text
18
+ MUTED = "#57534A" # secondary text, toolbar labels
19
+ FAINT = "#6E6959" # tertiary text, JSON punctuation
20
+ DIM = "#837D6E" # uppercase mono labels
21
+ DIMMER = "#9A9484" # metadata, timestamps
22
+ HAIRLINE = "#CFC9BA" # md / raw gutter marks
23
+ BORDER = "#E2DDD0" # all 1px borders
24
+ SURFACE = "#EDE9DF" # collapsed-input fill, stale banner
25
+ PAPER = "#F5F2EB" # page ground
26
+ COBALT = "#2B5FE3" # In [n] prompts, links, positive deltas, progress fill
27
+ ORANGE = "#F15B22" # Out [n] prompts, errors, running state, negative deltas
28
+ YELLOW = "#FFC613" # primary action, cell tags, annotation badges
29
+ SUCCESS = "#2F6B4F" # passed checks and verified terminal states
30
+
31
+ # Viewer-only additions.
32
+ PANEL = "#141414" # code input background
33
+ PANEL_BORDER = "#1E1E1C" # code panel internal dividers
34
+ PANEL_RAISE = "#232118" # code panel toolbar bg, kernel pill bg
35
+ PANEL_EDGE = "#2E2C22" # ghost button border on panel
36
+ SUB_PAPER = "#FAF8F3" # output wells, toolbar, outline rail
37
+ ROW_RULE = "#F1EDE3" # table row dividers, inline code fill
38
+ RUST = "#A34718" # stderr text, negative residuals on paper
39
+ WARN_BG = "#FDF3E4" # leakage / warning callout fill
40
+ WARN_BORDER = "#F0DCB4" # leakage callout border
41
+ WARN_INK = "#5C4315" # leakage callout body text
42
+ WARN_TITLE = "#8A5A16" # leakage callout title label (F28)
43
+ ERR_BG = "#FCEFEA" # traceback body fill
44
+ ERR_BORDER = "#F2D3C4" # traceback body border
45
+ MINIMAP_CODE = "#E5E9F6" # A04 minimap code-cell bar tint
46
+ MINIMAP_ERR = "#FBE4DA" # A04 minimap error-cell bar tint
47
+
48
+ # CSS custom properties emitted on ``.nb-shell`` and inherited by every descendant. The kebab
49
+ # names are the ``--nb-`` variable suffixes components reference.
50
+ CSS_TOKENS: dict[str, str] = {
51
+ "black": BLACK,
52
+ "ink": INK,
53
+ "body": BODY,
54
+ "muted": MUTED,
55
+ "faint": FAINT,
56
+ "dim": DIM,
57
+ "dimmer": DIMMER,
58
+ "hairline": HAIRLINE,
59
+ "border": BORDER,
60
+ "surface": SURFACE,
61
+ "paper": PAPER,
62
+ "cobalt": COBALT,
63
+ "orange": ORANGE,
64
+ "yellow": YELLOW,
65
+ "success": SUCCESS,
66
+ "panel": PANEL,
67
+ "panel-border": PANEL_BORDER,
68
+ "panel-raise": PANEL_RAISE,
69
+ "panel-edge": PANEL_EDGE,
70
+ "sub-paper": SUB_PAPER,
71
+ "row-rule": ROW_RULE,
72
+ "rust": RUST,
73
+ "warn-bg": WARN_BG,
74
+ "warn-border": WARN_BORDER,
75
+ "warn-ink": WARN_INK,
76
+ "warn-title": WARN_TITLE,
77
+ "err-bg": ERR_BG,
78
+ "err-border": ERR_BORDER,
79
+ "minimap-code": MINIMAP_CODE,
80
+ "minimap-err": MINIMAP_ERR,
81
+ }
82
+
83
+ # --- Type ---------------------------------------------------------------------------------------
84
+ # No webfont fetch is permitted in the harness; both stacks degrade to system faces.
85
+ FONT_SANS = '"Space Grotesk", "Helvetica Neue", sans-serif'
86
+ FONT_MONO = '"JetBrains Mono", Menlo, monospace'
87
+
88
+ # role -> (family, size_px, weight, line_height, notes). Consumed by build_css and available to
89
+ # components that need a size without re-deriving it from the stylesheet text.
90
+ TYPE_SCALE: dict[str, tuple[str, float, int, float, str]] = {
91
+ "md-h1": (FONT_SANS, 34, 700, 1.1, "letter-spacing:-0.025em"),
92
+ "md-h2": (FONT_SANS, 25, 600, 1.15, "letter-spacing:-0.02em"),
93
+ "md-h3": (FONT_SANS, 19, 600, 1.25, "letter-spacing:-0.01em"),
94
+ "md-h4": (FONT_SANS, 16, 600, 1.3, ""),
95
+ "md-body": (FONT_SANS, 16, 400, 1.68, "max-width:62ch;text-wrap:pretty"),
96
+ "md-list": (FONT_SANS, 16, 400, 1.6, "max-width:60ch"),
97
+ "code": (FONT_MONO, 13, 400, 1.75, ""),
98
+ "output": (FONT_MONO, 12.5, 400, 1.7, "white-space:pre-wrap"),
99
+ "table-cell": (FONT_MONO, 12.5, 400, 1.5, "font-variant-numeric:tabular-nums"),
100
+ "prompt": (FONT_MONO, 11.5, 400, 1, ""),
101
+ "chrome-button": (FONT_MONO, 11.5, 500, 1, ""),
102
+ "meta": (FONT_MONO, 10.5, 600, 1.4, "letter-spacing:0.12em;text-transform:uppercase"),
103
+ "inline-code": (FONT_MONO, 13.5, 400, 1.0, ""),
104
+ }
105
+
106
+ # --- Geometry -----------------------------------------------------------------------------------
107
+ GUTTER_PX = 62 # fixed prompt column; outputs re-enter with margin-left:-62px
108
+ GUTTER_NARROW_PX = 44 # 560-799 container width
109
+ CELL_GAP_PX = 26 # cell-to-cell
110
+ IO_GAP_PX = 10 # input-to-output
111
+ DOC_PADDING = "34px clamp(20px, 3vw, 40px) 40px"
112
+ SHELL_RADIUS_PX = 16
113
+ SHELL_BORDER = f"1px solid {BORDER}"
114
+ SHELL_SHADOW = "0 1px 2px rgba(23,22,15,0.04), 0 12px 32px rgba(23,22,15,0.05)"
115
+ OUTLINE_WIDTH_PX = 216
116
+
117
+ # MR01 distribution chart. Axis labels alternate over two rows, so each visible label may use the
118
+ # horizontal span of two bar slots while remaining inside the fixed viewBox.
119
+ CHART_VIEWBOX_WIDTH = 724.0
120
+ CHART_VIEWBOX_HEIGHT = 212.0
121
+ CHART_PLOT_LEFT = 42.0
122
+ CHART_PLOT_RIGHT = 682.0
123
+ CHART_BASELINE = 156.0
124
+ CHART_PLOT_HEIGHT = 108.0
125
+ CHART_BAR_MIN_WIDTH = 12.0
126
+ CHART_BAR_MAX_WIDTH = 72.0
127
+ CHART_LABEL_BASELINES = (180.0, 198.0)
128
+ CHART_LABEL_CHAR_WIDTH = 7.0
129
+ CHART_LABEL_GAP = 12.0
130
+
131
+ RADIUS = {
132
+ "panel": "10px", # cell panels, output wells
133
+ "callout": "12px", # callouts
134
+ "scrolled": "8px", # scrolled boxes, collapsed bars
135
+ "chrome-btn": "7px",
136
+ "toolbar-btn": "6px",
137
+ "chip": "4px", # chips, tags, badges (4-5px)
138
+ "pill": "999px", # pills, progress tracks
139
+ }
140
+
141
+ # --- Motion -------------------------------------------------------------------------------------
142
+ # Three animations, all <= 1.6s, all gated behind prefers-reduced-motion.
143
+ KEYFRAMES = """
144
+ @keyframes nb-spin { to { transform: rotate(360deg); } }
145
+ @keyframes nb-pulse { 0%,100% { opacity: 1 } 50% { opacity: 0.35 } }
146
+ @keyframes nb-bar { 0% { transform: translateX(-100%) } 100% { transform: translateX(340%) } }
147
+ """.strip()
148
+
149
+ HOVER_TRANSITION = "0.15s ease" # color and border-color only; never layout
150
+
151
+ VALID_MODES = ("static", "connected", "embed")
152
+
153
+
154
+ def _root_vars() -> str:
155
+ decls = "".join(f"--nb-{name}:{value};" for name, value in CSS_TOKENS.items())
156
+ return (
157
+ ".nb-shell{" + decls + f"container-type:inline-size;box-sizing:border-box;"
158
+ "--nb-inset-x:16px;--nb-inset-y:12px;--nb-stack-gap:8px;--nb-section-gap:16px;"
159
+ f"border:{SHELL_BORDER};border-radius:{SHELL_RADIUS_PX}px;overflow:hidden;"
160
+ f"box-shadow:{SHELL_SHADOW};background:var(--nb-paper);"
161
+ f"font-family:{FONT_SANS};color:var(--nb-ink);"
162
+ "}"
163
+ ".nb-shell *,.nb-shell *::before,.nb-shell *::after{box-sizing:border-box;}"
164
+ )
165
+
166
+
167
+ # Structural + component rules. Written as one literal block (no f-string) so CSS braces stay
168
+ # unescaped; every color is a var so this text carries no hex of its own except the six
169
+ # syntax/traceback/kernel accents that belong to a single component each.
170
+ _BASE_CSS = """
171
+ /* Layout · spec section 3 */
172
+ .nb-body { display: flex; align-items: flex-start; }
173
+ .nb-document {
174
+ flex: 1; min-width: 0;
175
+ padding: 34px clamp(20px, 3vw, 40px) 40px;
176
+ display: flex; flex-direction: column; gap: 26px;
177
+ }
178
+ .nb-cell {
179
+ display: grid; grid-template-columns: 62px minmax(0, 1fr);
180
+ align-items: start;
181
+ }
182
+ .nb-gutter { grid-column: 1; user-select: none; -webkit-user-select: none; }
183
+ .nb-content { grid-column: 2; min-width: 0; }
184
+ .nb-io { margin-left: -62px; }
185
+ .nb-io { display: grid; grid-template-columns: 62px minmax(0, 1fr); align-items: start; }
186
+ /* The output row owns the input-to-output gap: 10px is IO_GAP_PX, and the reset covers every
187
+ child of the row body — one output can render as several sibling roots (E26 stale banner + E25
188
+ widget), so resetting only the first child would leave a seam between them. */
189
+ .nb-io { margin-top: 10px; }
190
+ .nb-io > .nb-io-body > * { margin-top: 0; }
191
+ .nb-io-gutter { grid-column: 1; user-select: none; -webkit-user-select: none; }
192
+ .nb-io-body { grid-column: 2; min-width: 0; }
193
+
194
+ /* A01 · notebook header */
195
+ .nb-header {
196
+ display: flex; justify-content: space-between; align-items: center;
197
+ gap: 16px; padding: 16px 22px; background: var(--nb-ink);
198
+ }
199
+ .nb-header-id { display: flex; align-items: center; gap: 12px; min-width: 0; }
200
+ .nb-header-crumbs { font-family: var(--fm); font-size: 10.5px; color: #6E6A60; }
201
+ .nb-header-crumb-sep { color: #4A473C; }
202
+ .nb-header-crumb-last { color: var(--nb-dimmer); }
203
+ .nb-header-file {
204
+ font-family: var(--fm); font-size: 14.5px; font-weight: 600; color: var(--nb-paper);
205
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
206
+ }
207
+ .nb-header-saved { font-family: var(--fm); font-size: 10.5px; color: #6E6A60; }
208
+ .nb-header-actions { display: flex; align-items: center; gap: 10px; }
209
+
210
+ /* A02 · toolbar */
211
+ .nb-toolbar {
212
+ display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
213
+ padding: 9px 22px; background: var(--nb-sub-paper);
214
+ border-bottom: 1px solid var(--nb-border);
215
+ }
216
+ .nb-toolbar-btn {
217
+ background: #FFFFFF; border: 1px solid #D8D2C4; border-radius: 6px;
218
+ padding: 6px 11px; font-family: var(--fm); font-size: 11.5px; color: var(--nb-muted);
219
+ transition: border-color 0.15s ease, color 0.15s ease;
220
+ }
221
+ .nb-toolbar-btn:hover { border-color: var(--nb-ink); color: var(--nb-ink); }
222
+ .nb-toolbar-divider { width: 1px; height: 20px; background: var(--nb-border); margin: 0 6px; }
223
+ .nb-toolbar-spacer { flex: 1; }
224
+ .nb-toolbar-count { font-family: var(--fm); font-size: 11px; color: var(--nb-dimmer); }
225
+
226
+ /* A03 · kernel pill */
227
+ .nb-kernel {
228
+ display: inline-flex; align-items: center; gap: 7px;
229
+ background: var(--nb-panel-raise); border: 1px solid #302D22; border-radius: 999px;
230
+ padding: 6px 13px 6px 11px; font-family: var(--fm); font-size: 11.5px; color: var(--nb-border);
231
+ }
232
+ .nb-kernel-dot { width: 7px; height: 7px; border-radius: 999px; }
233
+ .nb-kernel--idle .nb-kernel-dot { background: #7BD07B; }
234
+ .nb-kernel--busy .nb-kernel-dot {
235
+ background: var(--nb-yellow);
236
+ animation: nb-pulse 1.4s ease-in-out infinite;
237
+ }
238
+ .nb-kernel--queued .nb-kernel-dot { background: var(--nb-yellow); }
239
+ .nb-kernel--dead .nb-kernel-dot { background: var(--nb-orange); }
240
+ .nb-kernel--none .nb-kernel-dot { background: #6E6A60; }
241
+
242
+ /* Buttons shared by chrome */
243
+ .nb-btn-ghost {
244
+ background: transparent; border: 1px solid #302D22; border-radius: 7px;
245
+ padding: 7px 13px; font-family: var(--fm); font-size: 11.5px; font-weight: 500;
246
+ color: var(--nb-border); transition: background 0.15s ease, color 0.15s ease;
247
+ }
248
+ .nb-btn-ghost:hover { background: var(--nb-panel-raise); color: #FFFFFF; }
249
+ .nb-btn-primary {
250
+ background: var(--nb-yellow); border: none; border-radius: 7px;
251
+ padding: 8px 15px; font-family: var(--fm); font-size: 11.5px; font-weight: 600;
252
+ color: var(--nb-ink); transition: background 0.15s ease;
253
+ }
254
+ .nb-btn-primary:hover { background: #FFD44A; }
255
+
256
+ /* A04 · outline rail */
257
+ .nb-outline {
258
+ flex: none; width: 216px; align-self: stretch; position: sticky; top: 0;
259
+ background: var(--nb-sub-paper); border-right: 1px solid var(--nb-border);
260
+ padding: 22px 18px 30px;
261
+ }
262
+ .nb-outline-label {
263
+ font-family: var(--fm); font-size: 10px; letter-spacing: 0.16em;
264
+ text-transform: uppercase; color: #B0A996;
265
+ }
266
+ .nb-outline-link {
267
+ display: block; font-family: var(--fm); font-size: 12px; padding: 5px 8px;
268
+ border-radius: 5px; color: var(--nb-muted); text-decoration: none;
269
+ transition: background 0.15s ease, color 0.15s ease;
270
+ }
271
+ .nb-outline-link:hover { background: var(--nb-surface); color: var(--nb-ink); }
272
+ .nb-outline-link--active { color: var(--nb-ink); font-weight: 600; background: var(--nb-surface); }
273
+ .nb-outline-link[data-depth="0"] { padding-left: 8px; }
274
+ .nb-outline-link[data-depth="1"] { padding-left: 20px; }
275
+ .nb-outline-link[data-depth="2"] { padding-left: 32px; }
276
+ .nb-outline-link[data-depth="3"] { padding-left: 44px; }
277
+ .nb-minimap-row { display: flex; gap: 3px; margin-top: 3px; align-items: flex-end; }
278
+ .nb-minimap-stripe { width: 3px; border-radius: 2px; }
279
+ .nb-minimap-bar { flex: 1; border-radius: 2px; }
280
+
281
+ /* A05 · repro footer */
282
+ .nb-footer {
283
+ display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px;
284
+ padding: 14px 22px; background: var(--nb-sub-paper); border-top: 1px solid var(--nb-border);
285
+ }
286
+ .nb-footer-facts { font-family: var(--fm); font-size: 11px; color: var(--nb-dim); }
287
+ .nb-footer-mid { color: var(--nb-hairline); margin: 0 8px; }
288
+ .nb-footer-link {
289
+ font-family: var(--fm);
290
+ font-size: 11px;
291
+ color: var(--nb-cobalt);
292
+ text-decoration: none;
293
+ }
294
+
295
+ /* B06 · gutter prompt */
296
+ .nb-prompt { font-family: var(--fm); font-size: 11.5px; line-height: 1; padding-top: 12px; }
297
+ .nb-prompt--in { color: var(--nb-cobalt); }
298
+ .nb-prompt--running { color: var(--nb-orange); animation: nb-pulse 1.4s ease-in-out infinite; }
299
+ .nb-prompt--idle { color: #B0A996; }
300
+ .nb-prompt--out { color: var(--nb-orange); }
301
+ .nb-prompt--stream { color: #B0A996; }
302
+ .nb-prompt--err { color: var(--nb-rust); }
303
+ .nb-prompt--wgt { color: #B0A996; }
304
+ .nb-prompt--md, .nb-prompt--raw { color: var(--nb-hairline); }
305
+ .nb-prompt--md { padding-top: 6px; }
306
+ .nb-prompt--raw { padding-top: 12px; }
307
+
308
+ /* B07 · cell states — box-shadow only, never border (avoids layout shift) */
309
+ .nb-panel.is-selected { box-shadow: 0 0 0 2px var(--nb-cobalt); }
310
+ .nb-panel.is-running { box-shadow: 0 0 0 2px var(--nb-orange); }
311
+ .nb-panel.is-error { box-shadow: 0 0 0 1px #6B2E14; }
312
+ .nb-cell.is-editing .nb-gutter { box-shadow: inset 2px 0 0 var(--nb-cobalt); }
313
+
314
+ /* B08 · hover toolbar (panel header) */
315
+ .nb-panel-head {
316
+ display: flex; justify-content: space-between; align-items: center;
317
+ padding: 8px 16px; border-bottom: 1px solid var(--nb-panel-raise);
318
+ opacity: 0; transition: opacity 0.15s ease;
319
+ }
320
+ .nb-cell:hover .nb-panel-head, .nb-cell:focus-within .nb-panel-head { opacity: 1; }
321
+ .nb-panel-lang {
322
+ font-family: var(--fm); font-size: 10px; text-transform: uppercase;
323
+ letter-spacing: 0.1em; color: #6E6A60;
324
+ }
325
+ .nb-panel-actions { display: flex; gap: 6px; }
326
+ .nb-panel-btn {
327
+ background: transparent; border: 1px solid var(--nb-panel-edge); border-radius: 4px;
328
+ padding: 3px 8px; font-family: var(--fm); font-size: 10px; color: var(--nb-dimmer);
329
+ transition: color 0.15s ease, border-color 0.15s ease;
330
+ }
331
+ .nb-panel-btn:hover { color: var(--nb-paper); border-color: #4A473C; }
332
+ .nb-panel-btn--interrupt { color: var(--nb-orange); border-color: #4A2A1C; }
333
+ .nb-panel-btn--interrupt:hover { background: #2A1610; }
334
+
335
+ /* B09 · collapse affordances */
336
+ .nb-collapse {
337
+ display: flex; align-items: center; gap: 8px; width: 100%;
338
+ background: var(--nb-row-rule); border: 1px dashed #D8D2C4; border-radius: 8px;
339
+ padding: 9px 14px; font-family: var(--fm); font-size: 11.5px; color: var(--nb-faint);
340
+ transition: border-color 0.15s ease, color 0.15s ease;
341
+ }
342
+ .nb-collapse:hover { border-color: var(--nb-ink); color: var(--nb-ink); }
343
+ .nb-collapse-caret { font-size: 9px; }
344
+ .nb-collapse-spacer { flex: 1; }
345
+ .nb-collapse-show { color: #B0A996; }
346
+
347
+ /* B10 · cell tags */
348
+ .nb-tag { font-family: var(--fm); font-size: 10px; border-radius: 4px; padding: 2px 7px; }
349
+ .nb-tag--cached { color: #B9E08C; background: #1E2A18; }
350
+ .nb-tag--slow { color: var(--nb-yellow); background: #2E2612; }
351
+ .nb-tag--skip { color: var(--nb-dimmer); background: var(--nb-panel-raise); }
352
+ .nb-tag--hide-input { color: var(--nb-ink); background: var(--nb-yellow); font-weight: 600; }
353
+ .nb-activity {
354
+ display: inline-flex; align-items: center; gap: 5px; margin: 0 8px 8px 0;
355
+ border-radius: 999px; padding: 3px 8px; color: var(--nb-cobalt); background: #EDF3FF;
356
+ font-family: var(--fm); font-size: 10px; font-weight: 600;
357
+ }
358
+ .nb-panel-head > .nb-activity { margin: 0 8px; }
359
+ .nb-activity--executing { color: var(--nb-orange); background: #FFF2EA; }
360
+ .nb-activity-caret {
361
+ width: 2px; height: 12px; background: currentColor; animation: nb-pulse 1s step-end infinite;
362
+ }
363
+
364
+ /* B11 · execution meta */
365
+ .nb-exec-meta {
366
+ margin-top: 8px; font-family: var(--fm); font-size: 10.5px; color: #B0A996;
367
+ }
368
+ .nb-exec-mid { color: var(--nb-border); margin: 0 8px; }
369
+ .nb-exec-ooo {
370
+ font-family: var(--fm); font-size: 10px; color: var(--nb-rust);
371
+ background: var(--nb-err-bg); border-radius: 4px; padding: 2px 7px; margin-left: 8px;
372
+ }
373
+
374
+ /* MR01 · portable all-column inspector */
375
+ .mr-columns {
376
+ overflow: hidden; background: #FFFFFF; border: 1px solid var(--nb-border);
377
+ border-radius: 12px;
378
+ }
379
+ .mr-columns-head {
380
+ min-height: 78px; display: flex; align-items: center; justify-content: space-between;
381
+ gap: 20px; padding: 15px 18px; border-bottom: 1px solid var(--nb-border);
382
+ }
383
+ .mr-columns-head > div { display: flex; min-width: 0; flex-direction: column; gap: 7px; }
384
+ .mr-columns-head span, .mr-col-label {
385
+ color: var(--nb-dim); font-family: var(--fm); font-size: 10px; font-weight: 600;
386
+ letter-spacing: 0.09em; text-transform: uppercase;
387
+ }
388
+ .mr-columns-head > div strong { font-family: var(--fm); font-size: 18px; font-weight: 600; }
389
+ .mr-columns-head label { display: flex; align-items: center; gap: 10px; }
390
+ .mr-columns-head select {
391
+ min-width: 190px; height: 40px; padding: 0 36px 0 12px; color: var(--nb-ink);
392
+ background: var(--nb-sub-paper); border: 1px solid var(--nb-hairline); border-radius: 8px;
393
+ font-family: var(--fm); font-size: 12.5px;
394
+ }
395
+ .mr-col-facts { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
396
+ .mr-col-fact {
397
+ min-height: 104px; display: flex; justify-content: center; flex-direction: column; gap: 8px;
398
+ padding: 17px 16px; border-left: 1px solid var(--nb-border);
399
+ }
400
+ .mr-col-fact:first-child { border-left: 0; }
401
+ .mr-col-fact strong {
402
+ overflow: hidden; color: var(--nb-ink); font-family: var(--fm); font-size: 19px;
403
+ font-weight: 500; line-height: 1.15; text-overflow: ellipsis; white-space: nowrap;
404
+ }
405
+ .mr-col-fact small { color: var(--nb-muted); font-size: 11.5px; line-height: 1.3; }
406
+ .mr-col-chart { padding: 20px 20px 8px; border-top: 1px solid var(--nb-border); }
407
+ .mr-col-chart header { display: flex; align-items: baseline; gap: 10px; }
408
+ .mr-col-chart header strong { font-size: 15px; font-weight: 600; }
409
+ .mr-col-chart header span { color: var(--nb-muted); font-size: 11.5px; }
410
+ .mr-col-chart svg { display: block; width: 100%; height: auto; margin-top: 6px; overflow: hidden; }
411
+ .mr-col-chart svg rect { fill: var(--nb-cobalt); stroke: none; }
412
+ .mr-col-chart svg line { stroke: var(--nb-hairline); stroke-width: 1; }
413
+ .mr-col-chart svg text { fill: var(--nb-muted); stroke: none; font: 11px var(--fm); }
414
+ .mr-col-chart svg .mr-col-bar-value { fill: var(--nb-body); font-weight: 600; }
415
+ .mr-col-chart-data {
416
+ position: absolute; display: block; width: 1px; max-width: 1px; height: 1px;
417
+ padding: 0; margin: -1px; overflow: hidden; contain: strict;
418
+ clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; border: 0;
419
+ }
420
+ .mr-col-chart--empty { padding-bottom: 20px; }
421
+ .mr-col-empty {
422
+ margin-top: 14px; padding: 20px; color: var(--nb-muted); background: var(--nb-sub-paper);
423
+ border-radius: 8px; font-size: 13px;
424
+ }
425
+ .mr-col-lineage {
426
+ min-height: 50px; display: flex; align-items: center; gap: 28px; padding: 0 18px;
427
+ color: var(--nb-muted); background: var(--nb-sub-paper); border-top: 1px solid var(--nb-border);
428
+ font-size: 11.5px;
429
+ }
430
+ .mr-col-lineage strong { color: var(--nb-body); font-family: var(--fm); font-weight: 500; }
431
+ .mr-columns-empty {
432
+ padding: 18px; color: var(--nb-muted); border: 1px solid var(--nb-border); border-radius: 10px;
433
+ }
434
+ @media (max-width: 900px) {
435
+ .mr-col-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
436
+ .mr-col-fact { border-top: 1px solid var(--nb-border); }
437
+ .mr-columns-head { align-items: flex-start; flex-direction: column; }
438
+ .mr-columns-head label, .mr-columns-head select { width: 100%; }
439
+ .mr-col-lineage { align-items: flex-start; flex-direction: column; gap: 6px; padding: 14px 18px; }
440
+ }
441
+
442
+ /* C12 · code input — six-color syntax theme is section-2, pinned to this component */
443
+ .nb-panel { border-radius: 10px; overflow: hidden; }
444
+ .nb-code { background: var(--nb-panel); border-radius: 10px; }
445
+ .nb-code--welded { border-radius: 10px 10px 0 0; }
446
+ .nb-code pre {
447
+ margin: 0; padding: 15px 18px; font-family: var(--fm); font-size: 13px; line-height: 1.75;
448
+ color: #CFC9BB; overflow-x: auto;
449
+ }
450
+ .nb-code--head pre { padding: 16px 18px; }
451
+ .nb-code[tabindex]:focus-visible { outline: 2px solid var(--nb-yellow); outline-offset: 2px; }
452
+ .nb-lineno {
453
+ color: #6E6A60;
454
+ text-align: right;
455
+ padding-right: 14px;
456
+ border-right: 1px solid #232118;
457
+ }
458
+ .nb-tok-base { color: #CFC9BB; }
459
+ .nb-tok-kw { color: #6E97FF; }
460
+ .nb-tok-str { color: #FFC613; }
461
+ .nb-tok-fn { color: #FF8A5B; }
462
+ .nb-tok-num { color: #B9E08C; }
463
+ .nb-tok-com { color: #6E6A60; }
464
+
465
+ /* C13 · markdown */
466
+ .nb-md { color: var(--nb-body); }
467
+ .nb-md h1 {
468
+ font-size: 34px;
469
+ font-weight: 700;
470
+ line-height: 1.1;
471
+ letter-spacing: -0.025em;
472
+ color: var(--nb-ink);
473
+ margin: 0 0 14px;
474
+ }
475
+ .nb-md h2 {
476
+ font-size: 25px;
477
+ font-weight: 600;
478
+ line-height: 1.15;
479
+ letter-spacing: -0.02em;
480
+ color: var(--nb-ink);
481
+ margin: 0 0 12px;
482
+ }
483
+ .nb-md h3 {
484
+ font-size: 19px;
485
+ font-weight: 600;
486
+ line-height: 1.25;
487
+ letter-spacing: -0.01em;
488
+ color: var(--nb-ink);
489
+ margin: 0 0 12px;
490
+ }
491
+ .nb-md h4 {
492
+ font-size: 16px;
493
+ font-weight: 600;
494
+ line-height: 1.3;
495
+ color: var(--nb-ink);
496
+ margin: 0 0 12px;
497
+ }
498
+ .nb-md p {
499
+ color: var(--nb-body);
500
+ margin: 0 0 16px;
501
+ max-width: 62ch;
502
+ text-wrap: pretty;
503
+ line-height: 1.68;
504
+ }
505
+ .nb-md ul, .nb-md ol {
506
+ padding-left: 22px;
507
+ display: flex;
508
+ flex-direction: column;
509
+ gap: 7px;
510
+ margin: 0 0 16px;
511
+ max-width: 60ch;
512
+ line-height: 1.6;
513
+ }
514
+ .nb-md code {
515
+ font-family: var(--fm);
516
+ font-size: 13.5px;
517
+ color: var(--nb-ink);
518
+ background: var(--nb-row-rule);
519
+ border: 1px solid #E7E2D5;
520
+ border-radius: 4px;
521
+ padding: 1.5px 5px;
522
+ }
523
+ .nb-md blockquote {
524
+ padding: 2px 0 2px 20px;
525
+ border-left: 3px solid var(--nb-yellow);
526
+ color: var(--nb-muted);
527
+ font-style: italic;
528
+ font-size: 16px;
529
+ line-height: 1.66;
530
+ max-width: 58ch;
531
+ margin: 0 0 16px;
532
+ }
533
+ .nb-md blockquote footer {
534
+ font-family: var(--fm);
535
+ font-size: 11.5px;
536
+ color: var(--nb-dimmer);
537
+ margin-top: 9px;
538
+ font-style: normal;
539
+ }
540
+ .nb-md-table {
541
+ border: 1px solid var(--nb-border);
542
+ border-radius: 10px;
543
+ overflow: hidden;
544
+ border-collapse: separate;
545
+ border-spacing: 0;
546
+ width: 100%;
547
+ margin: 0 0 16px;
548
+ }
549
+ .nb-md-table thead th {
550
+ background: var(--nb-sub-paper);
551
+ font-family: var(--fm);
552
+ font-size: 10px;
553
+ text-transform: uppercase;
554
+ letter-spacing: 0.1em;
555
+ color: var(--nb-dim);
556
+ font-weight: 600;
557
+ padding: 10px 16px;
558
+ text-align: left;
559
+ }
560
+ .nb-md-table tbody td {
561
+ font-size: 14px;
562
+ color: var(--nb-ink);
563
+ padding: 10px 16px;
564
+ border-bottom: 1px solid var(--nb-row-rule);
565
+ }
566
+ .nb-md-table tbody tr:last-child td { border-bottom: none; }
567
+ .nb-md-table td.nb-num {
568
+ text-align: right;
569
+ font-family: var(--fm);
570
+ font-variant-numeric: tabular-nums;
571
+ }
572
+ .nb-md hr { border: none; border-top: 1px solid var(--nb-border); margin: 0 0 20px; }
573
+ .nb-md img { max-width: 100%; border-radius: 10px; border: 1px solid var(--nb-border); }
574
+ .nb-md a { color: var(--nb-cobalt); text-decoration: none; }
575
+ .nb-md a:hover { color: #1E48B8; }
576
+
577
+ /* C14 · math (v1 deviation: TeX source in the display well) */
578
+ .nb-math {
579
+ background: var(--nb-sub-paper); border: 1px solid var(--nb-border); border-radius: 10px;
580
+ padding: 20px 24px; text-align: center; margin: 0 0 18px; overflow-x: auto; white-space: nowrap;
581
+ }
582
+ .nb-math-label {
583
+ display: block; font-family: var(--fm); font-size: 10px; text-transform: uppercase;
584
+ letter-spacing: 0.12em; color: #C3BCA9; text-align: left; margin-bottom: 8px;
585
+ }
586
+
587
+ /* C15 · raw cell */
588
+ .nb-raw {
589
+ background: var(--nb-sub-paper);
590
+ border: 1px solid var(--nb-surface);
591
+ border-radius: 10px;
592
+ padding: 14px var(--nb-inset-x);
593
+ }
594
+ .nb-raw-label {
595
+ font-family: var(--fm);
596
+ font-size: 10px;
597
+ text-transform: uppercase;
598
+ letter-spacing: 0.12em;
599
+ color: #C3BCA9;
600
+ }
601
+ .nb-raw pre {
602
+ margin: 8px 0 0;
603
+ font-family: var(--fm);
604
+ font-size: 12.5px;
605
+ line-height: 1.7;
606
+ color: var(--nb-dimmer);
607
+ white-space: pre-wrap;
608
+ }
609
+
610
+ /* D · output wells (shared base) */
611
+ .nb-well {
612
+ background: var(--nb-sub-paper);
613
+ border: 1px solid var(--nb-border);
614
+ border-radius: 10px;
615
+ padding: var(--nb-inset-y) var(--nb-inset-x);
616
+ }
617
+ .nb-well--welded { border-top: none; border-radius: 0 0 10px 10px; margin-top: 0; }
618
+ .nb-out-label {
619
+ font-family: var(--fm);
620
+ font-size: 10px;
621
+ text-transform: uppercase;
622
+ letter-spacing: 0.12em;
623
+ color: #B0A996;
624
+ margin-bottom: 8px;
625
+ }
626
+
627
+ /* D16 · stdout */
628
+ .nb-stdout pre {
629
+ margin: 0;
630
+ font-family: var(--fm);
631
+ font-size: 12.5px;
632
+ line-height: 1.7;
633
+ color: var(--nb-body);
634
+ white-space: pre-wrap;
635
+ }
636
+ /* D17 · stderr / warnings */
637
+ .nb-stderr { padding-top: 11px; border-top: 1px dashed var(--nb-border); }
638
+ .nb-stderr .nb-out-label { color: #C98A6A; }
639
+ .nb-stderr pre {
640
+ margin: 0;
641
+ font-family: var(--fm);
642
+ font-size: 12.5px;
643
+ line-height: 1.7;
644
+ color: var(--nb-rust);
645
+ white-space: pre-wrap;
646
+ }
647
+ .nb-sgr-bold { font-weight: 600; }
648
+ /* D18 · execute_result plain text */
649
+ .nb-result-plain {
650
+ margin: 0;
651
+ padding: 2px 0;
652
+ font-family: var(--fm);
653
+ font-size: 12.5px;
654
+ line-height: 1.7;
655
+ color: var(--nb-body);
656
+ white-space: pre-wrap;
657
+ }
658
+ /* D19 · DataFrame */
659
+ .nb-df {
660
+ border: 1px solid var(--nb-border);
661
+ border-radius: 10px;
662
+ overflow: hidden;
663
+ background: #FFFFFF;
664
+ }
665
+ .nb-df-scroll { overflow-x: auto; }
666
+ .nb-df table {
667
+ width: 100%;
668
+ border-collapse: separate;
669
+ border-spacing: 0;
670
+ font-family: var(--fm);
671
+ font-size: 12.5px;
672
+ }
673
+ .nb-df th {
674
+ background: var(--nb-sub-paper);
675
+ font-size: 10px;
676
+ text-transform: uppercase;
677
+ letter-spacing: 0.1em;
678
+ font-weight: 600;
679
+ color: var(--nb-dim);
680
+ padding: 10px var(--nb-inset-x);
681
+ border-bottom: 1px solid var(--nb-border);
682
+ white-space: nowrap;
683
+ text-align: left;
684
+ }
685
+ .nb-df td {
686
+ padding: 9px var(--nb-inset-x);
687
+ border-bottom: 1px solid var(--nb-row-rule);
688
+ color: var(--nb-ink);
689
+ }
690
+ .nb-df tr:last-child td { border-bottom: none; }
691
+ .nb-df td.nb-df-idx { color: #B0A996; }
692
+ .nb-df td.nb-df-str { white-space: nowrap; }
693
+ .nb-df td.nb-df-num { text-align: right; font-variant-numeric: tabular-nums; }
694
+ .nb-df-pos { color: var(--nb-cobalt); }
695
+ .nb-df-neg { color: var(--nb-rust); }
696
+ .nb-df-zero { color: var(--nb-dimmer); }
697
+ .nb-status {
698
+ display: inline-flex;
699
+ align-items: center;
700
+ gap: 6px;
701
+ color: var(--nb-body);
702
+ font-weight: 600;
703
+ white-space: nowrap;
704
+ }
705
+ .nb-status::before {
706
+ content: "";
707
+ width: 6px;
708
+ height: 6px;
709
+ flex: 0 0 6px;
710
+ border-radius: 50%;
711
+ background: var(--nb-dim);
712
+ }
713
+ .nb-status--pass::before { background: var(--nb-success); }
714
+ .nb-status--fail::before { background: var(--nb-rust); }
715
+ .nb-status--pending::before,
716
+ .nb-status--warning::before,
717
+ .nb-status--running::before { background: var(--nb-orange); }
718
+ .nb-df-ellipsis { text-align: center; color: var(--nb-hairline); }
719
+ .nb-df-caption {
720
+ background: var(--nb-sub-paper);
721
+ border-top: 1px solid var(--nb-border);
722
+ padding: 9px var(--nb-inset-x);
723
+ font-family: var(--fm);
724
+ font-size: 11px;
725
+ color: var(--nb-dim);
726
+ }
727
+
728
+ /* D20 · figure */
729
+ .nb-fig {
730
+ border: 1px solid var(--nb-border);
731
+ border-radius: 10px;
732
+ background: #FFFFFF;
733
+ padding: 20px 22px 16px;
734
+ }
735
+ .nb-fig-title { font-size: 14.5px; font-weight: 600; color: var(--nb-ink); }
736
+ .nb-fig-sub {
737
+ font-family: var(--fm);
738
+ font-size: 10.5px;
739
+ color: var(--nb-dimmer);
740
+ margin-bottom: 16px;
741
+ }
742
+ .nb-fig img { width: 100%; height: auto; display: block; }
743
+ .nb-fig-legend {
744
+ margin-top: 14px;
745
+ padding-top: 13px;
746
+ border-top: 1px solid var(--nb-row-rule);
747
+ display: flex;
748
+ gap: 20px;
749
+ flex-wrap: wrap;
750
+ }
751
+ .nb-fig-legend span { font-family: var(--fm); font-size: 11px; color: var(--nb-muted); }
752
+
753
+ /* D21 · rich HTML */
754
+ .nb-rich {
755
+ border: 1px solid var(--nb-border);
756
+ border-radius: 10px;
757
+ overflow: hidden;
758
+ }
759
+ .nb-rich-head {
760
+ display: flex;
761
+ gap: 8px;
762
+ align-items: center;
763
+ background: var(--nb-sub-paper);
764
+ border-bottom: 1px solid var(--nb-border);
765
+ padding: 9px var(--nb-inset-x);
766
+ }
767
+ .nb-rich-mime {
768
+ font-family: var(--fm);
769
+ font-size: 10px;
770
+ text-transform: uppercase;
771
+ color: #B0A996;
772
+ }
773
+ .nb-rich-cls { font-family: var(--fm); font-size: 10px; color: var(--nb-dim); }
774
+ .nb-rich-body { padding: var(--nb-inset-y) var(--nb-inset-x); }
775
+
776
+ /* D22 · JSON viewer */
777
+ .nb-json {
778
+ border: 1px solid var(--nb-border);
779
+ border-radius: 10px;
780
+ overflow: hidden;
781
+ }
782
+ .nb-json-head {
783
+ display: flex;
784
+ gap: 8px;
785
+ align-items: center;
786
+ background: var(--nb-sub-paper);
787
+ border-bottom: 1px solid var(--nb-border);
788
+ padding: 9px var(--nb-inset-x);
789
+ }
790
+ .nb-json-body {
791
+ padding: 14px var(--nb-inset-x);
792
+ font-family: var(--fm);
793
+ font-size: 12.5px;
794
+ line-height: 1.85;
795
+ }
796
+ .nb-json-caret { color: #B0A996; }
797
+ .nb-json-key { color: var(--nb-cobalt); }
798
+ .nb-json-str { color: var(--nb-rust); }
799
+ .nb-json-num { color: var(--nb-ink); }
800
+ .nb-json-punct { color: #B0A996; }
801
+
802
+ /* D23 · traceback */
803
+ .nb-tb {
804
+ border: 1px solid var(--nb-border);
805
+ background: var(--nb-paper);
806
+ border-radius: 10px;
807
+ overflow: hidden;
808
+ }
809
+ .nb-tb-head {
810
+ display: flex;
811
+ justify-content: space-between;
812
+ align-items: center;
813
+ background: var(--nb-sub-paper);
814
+ border-bottom: 1px solid var(--nb-border);
815
+ padding: 10px var(--nb-inset-x);
816
+ }
817
+ .nb-tb-name { font-family: var(--fm); font-size: 12px; font-weight: 700; color: var(--nb-ink); }
818
+ .nb-tb-label { font-family: var(--fm); font-size: 10.5px; color: var(--nb-rust); }
819
+ .nb-tb-body {
820
+ margin: 0;
821
+ padding: 14px var(--nb-inset-x);
822
+ font-family: var(--fm);
823
+ font-size: 12.5px;
824
+ line-height: 1.8;
825
+ color: var(--nb-body);
826
+ overflow-x: auto;
827
+ }
828
+ .nb-tb-loc { color: var(--nb-rust); }
829
+ .nb-tb-arrow { color: #B0A996; }
830
+ .nb-tb-final { color: var(--nb-rust); font-weight: 600; }
831
+
832
+ /* D24 · progress */
833
+ .nb-progress { display: flex; align-items: center; gap: 10px; }
834
+ .nb-progress-label {
835
+ font-family: var(--fm);
836
+ font-size: 11.5px;
837
+ color: var(--nb-muted);
838
+ min-width: 62px;
839
+ }
840
+ .nb-progress-track {
841
+ flex: 1;
842
+ height: 9px;
843
+ background: var(--nb-surface);
844
+ border-radius: 999px;
845
+ overflow: hidden;
846
+ }
847
+ .nb-progress-fill { height: 100%; background: var(--nb-cobalt); }
848
+ .nb-progress-fill--indeterminate { width: 30%; background: var(--nb-yellow); }
849
+ .nb-progress-stat {
850
+ font-family: var(--fm);
851
+ font-size: 11.5px;
852
+ color: var(--nb-ink);
853
+ font-variant-numeric: tabular-nums;
854
+ text-align: right;
855
+ }
856
+ .nb-scrolled {
857
+ border: 1px solid var(--nb-border);
858
+ border-radius: 8px;
859
+ background: var(--nb-sub-paper);
860
+ max-height: 96px;
861
+ overflow-y: auto;
862
+ }
863
+ .nb-scrolled pre {
864
+ margin: 0;
865
+ padding: 11px 14px;
866
+ font-family: var(--fm);
867
+ font-size: 12px;
868
+ line-height: 1.75;
869
+ color: var(--nb-faint);
870
+ }
871
+ .nb-scrolled-note { font-family: var(--fm); font-size: 10.5px; color: #B0A996; margin-top: 6px; }
872
+
873
+ /* E25 · widgets */
874
+ .nb-widget {
875
+ border: 1px solid var(--nb-border);
876
+ border-radius: 10px;
877
+ overflow: hidden;
878
+ }
879
+ .nb-widget-controls {
880
+ padding: 18px var(--nb-inset-x);
881
+ display: flex;
882
+ flex-direction: column;
883
+ gap: var(--nb-section-gap);
884
+ }
885
+ .nb-widget-row { display: flex; gap: 14px; align-items: center; }
886
+ .nb-widget-label {
887
+ font-family: var(--fm);
888
+ font-size: 12px;
889
+ color: var(--nb-muted);
890
+ min-width: 74px;
891
+ text-align: right;
892
+ }
893
+ .nb-slider-track { width: 100%; height: 4px; background: var(--nb-border); border-radius: 999px; }
894
+ .nb-slider-fill { height: 4px; background: var(--nb-cobalt); border-radius: 999px; }
895
+ .nb-slider-thumb {
896
+ width: 16px;
897
+ height: 16px;
898
+ border-radius: 999px;
899
+ background: #FFFFFF;
900
+ border: 2px solid var(--nb-cobalt);
901
+ }
902
+ .nb-widget-value {
903
+ font-family: var(--fm);
904
+ font-size: 12px;
905
+ color: var(--nb-ink);
906
+ font-variant-numeric: tabular-nums;
907
+ }
908
+ .nb-toggle {
909
+ display: inline-flex;
910
+ border: 1px solid #D8D2C4;
911
+ border-radius: 7px;
912
+ overflow: hidden;
913
+ }
914
+ .nb-toggle-seg {
915
+ padding: 6px 14px;
916
+ font-family: var(--fm);
917
+ font-size: 12px;
918
+ color: var(--nb-muted);
919
+ background: #FFFFFF;
920
+ }
921
+ .nb-toggle-seg.is-active { color: #FFFFFF; background: var(--nb-ink); }
922
+ .nb-widget-btn {
923
+ background: var(--nb-yellow);
924
+ border: none;
925
+ border-radius: 7px;
926
+ padding: 7px 15px;
927
+ font-family: var(--fm);
928
+ font-size: 12px;
929
+ font-weight: 600;
930
+ color: var(--nb-ink);
931
+ }
932
+ .nb-checkbox { width: 16px; height: 16px; border: 1px solid #D8D2C4; border-radius: 4px; }
933
+ .nb-checkbox.is-checked { background: var(--nb-cobalt); }
934
+ .nb-widget.is-frozen .nb-widget-controls { opacity: 0.62; pointer-events: none; }
935
+
936
+ /* E26 · stale-output banner */
937
+ .nb-stale {
938
+ display: flex;
939
+ align-items: center;
940
+ gap: 9px;
941
+ background: var(--nb-surface);
942
+ border-bottom: 1px solid var(--nb-border);
943
+ padding: 9px var(--nb-inset-x);
944
+ }
945
+ .nb-stale-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--nb-dimmer); }
946
+ .nb-stale-msg { font-family: var(--fm); font-size: 11px; color: var(--nb-faint); }
947
+ .nb-stale-spacer { flex: 1; }
948
+ .nb-stale-action { font-family: var(--fm); font-size: 11px; color: var(--nb-cobalt); }
949
+
950
+ /* F27 · provenance callout */
951
+ .nb-prov { background: var(--nb-ink); border-radius: 12px; padding: 20px 22px; }
952
+ .nb-prov-head { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
953
+ .nb-prov-title {
954
+ font-family: var(--fm);
955
+ font-size: 10.5px;
956
+ text-transform: uppercase;
957
+ letter-spacing: 0.16em;
958
+ font-weight: 600;
959
+ color: var(--nb-yellow);
960
+ }
961
+ .nb-prov-grid {
962
+ display: grid;
963
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
964
+ gap: 16px 24px;
965
+ }
966
+ .nb-prov-key {
967
+ font-family: var(--fm);
968
+ font-size: 10px;
969
+ text-transform: uppercase;
970
+ letter-spacing: 0.12em;
971
+ color: #6E6A60;
972
+ }
973
+ .nb-prov-val { font-family: var(--fm); font-size: 12.5px; color: var(--nb-paper); }
974
+ .nb-prov-sub { color: var(--nb-dimmer); }
975
+
976
+ /* F28 · leakage warning */
977
+ .nb-leak {
978
+ background: var(--nb-warn-bg);
979
+ border: 1px solid var(--nb-warn-border);
980
+ border-radius: 10px;
981
+ padding: 15px 18px;
982
+ margin-top: 10px;
983
+ }
984
+ .nb-leak-head { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
985
+ .nb-leak-badge {
986
+ width: 16px;
987
+ height: 16px;
988
+ border-radius: 4px;
989
+ background: var(--nb-orange);
990
+ color: #FFFFFF;
991
+ font-family: var(--fm);
992
+ font-size: 11px;
993
+ font-weight: 700;
994
+ display: inline-flex;
995
+ align-items: center;
996
+ justify-content: center;
997
+ }
998
+ .nb-leak-title {
999
+ font-family: var(--fm);
1000
+ font-size: 10.5px;
1001
+ text-transform: uppercase;
1002
+ letter-spacing: 0.14em;
1003
+ font-weight: 600;
1004
+ color: var(--nb-warn-title);
1005
+ }
1006
+ .nb-leak-body { font-size: 14.5px; line-height: 1.6; color: var(--nb-warn-ink); max-width: 66ch; }
1007
+ .nb-leak-body code {
1008
+ font-family: var(--fm);
1009
+ font-size: 13px;
1010
+ background: #F7E8CC;
1011
+ border-radius: 4px;
1012
+ padding: 1px 5px;
1013
+ }
1014
+
1015
+ /* F29 · entity chips */
1016
+ .nb-chip {
1017
+ display: inline-flex;
1018
+ align-items: center;
1019
+ gap: 5px;
1020
+ vertical-align: 1px;
1021
+ font-family: var(--fm);
1022
+ font-size: 12.5px;
1023
+ color: var(--nb-ink);
1024
+ background: var(--nb-surface);
1025
+ border: 1px solid var(--nb-border);
1026
+ border-radius: 5px;
1027
+ padding: 1px 7px;
1028
+ }
1029
+ .nb-chip-dot { width: 5px; height: 5px; border-radius: 999px; }
1030
+ .nb-chip--station .nb-chip-dot { background: var(--nb-cobalt); }
1031
+ .nb-chip--dataset .nb-chip-dot { background: var(--nb-yellow); }
1032
+ .nb-chip--run .nb-chip-dot { background: var(--nb-orange); }
1033
+ .nb-chip--source .nb-chip-dot { background: var(--nb-faint); }
1034
+
1035
+ /* Unknown mimetype well · spec section 4 */
1036
+ .nb-unsupported {
1037
+ background: var(--nb-sub-paper);
1038
+ border: 1px solid var(--nb-border);
1039
+ border-radius: 10px;
1040
+ padding: var(--nb-inset-y) var(--nb-inset-x);
1041
+ margin-top: 10px;
1042
+ font-family: var(--fm);
1043
+ font-size: 11px;
1044
+ color: var(--nb-dimmer);
1045
+ }
1046
+
1047
+ /* Scaffold pending well — visible integration seam until a component lands */
1048
+ .nb-pending {
1049
+ background: var(--nb-sub-paper);
1050
+ border: 1px dashed #D8D2C4;
1051
+ border-radius: 8px;
1052
+ padding: 9px 14px;
1053
+ margin-top: 10px;
1054
+ font-family: var(--fm);
1055
+ font-size: 11px;
1056
+ color: var(--nb-faint);
1057
+ }
1058
+
1059
+ /* Accessibility · spec section 5 */
1060
+ .nb-shell :focus-visible { outline: 2px solid var(--nb-cobalt); outline-offset: 2px; }
1061
+ .nb-header :focus-visible, .nb-code:focus-visible, .nb-panel :focus-visible {
1062
+ outline-color: var(--nb-yellow);
1063
+ }
1064
+ """.strip()
1065
+
1066
+ # --alias: components reference var(--fm) as a shorthand for the mono stack; declared once.
1067
+ _FONT_ALIAS = f".nb-shell{{--fm:{FONT_MONO};--fs:{FONT_SANS};}}"
1068
+
1069
+ # Integration layer: the backing rules for classes and css-vars the component modules emit but that
1070
+ # the base block above does not define. Every rule here is additive — it resolves a hook a
1071
+ # component already emits and overrides no earlier selector — and each carries the component id it
1072
+ # serves, so a class can be traced back to its emitter.
1073
+ _INTEGRATION_CSS = """
1074
+ /* Styler cobalt gradient ramp · D21 remaps background-color hexes onto these four vars */
1075
+ .nb-shell {
1076
+ --nb-styler-g0: #F5F8FE; --nb-styler-g1: #EAF0FD;
1077
+ --nb-styler-g2: #DEE8FB; --nb-styler-g3: #CBDBF9;
1078
+ }
1079
+ /* C12/D · weld the first stdout well flush to the code panel (document sets nb-code--welded on
1080
+ the panel; the well's own markup is untouched, so the seam is closed purely by adjacency) */
1081
+ .nb-code--welded + .nb-well { border-top: none; border-radius: 0 0 10px 10px; margin-top: 0; }
1082
+ /* B08 · panel-head sub-parts (frame emits both) */
1083
+ .nb-panel-head-left { display: flex; align-items: center; gap: 8px; }
1084
+ .nb-panel-head--static { opacity: 1; }
1085
+ /* A01 · header two-line block — min-width:0 lets .nb-header-file ellipsis clip */
1086
+ .nb-header-block { display: flex; flex-direction: column; min-width: 0; }
1087
+ /* A02 · Run button rest accent (connected toolbar only) */
1088
+ .nb-toolbar-btn--run { display: inline-flex; align-items: center; gap: 6px; color: var(--nb-ink); }
1089
+ /* A04 · minimap stripe/bar type tints + length-bucket heights (was inline; now class-driven) */
1090
+ .nb-minimap-stripe--md { background: var(--nb-ink); }
1091
+ .nb-minimap-stripe--code { background: var(--nb-cobalt); }
1092
+ .nb-minimap-stripe--err { background: var(--nb-orange); }
1093
+ .nb-minimap-stripe--raw { background: var(--nb-hairline); }
1094
+ .nb-minimap-bar--md { background: var(--nb-surface); }
1095
+ .nb-minimap-bar--code { background: var(--nb-minimap-code); }
1096
+ .nb-minimap-bar--err { background: var(--nb-minimap-err); }
1097
+ .nb-minimap-bar--raw { background: var(--nb-row-rule); }
1098
+ .nb-minimap-h-short { height: 13px; }
1099
+ .nb-minimap-h-medium { height: 22px; }
1100
+ .nb-minimap-h-long { height: 30px; }
1101
+ /* A04 · a small top gap before the second outline label when a heading tree precedes it */
1102
+ .nb-outline-label--cells { margin-top: 20px; }
1103
+ /* C12 · opt-in line-number rail (off by default; user-select:none keeps it out of copy) */
1104
+ .nb-code-lines { display: flex; align-items: stretch; }
1105
+ .nb-code-lines > pre[tabindex] { flex: 1; min-width: 0; }
1106
+ .nb-lineno {
1107
+ font-family: var(--fm); font-size: 12px; line-height: 1.75; margin: 0;
1108
+ user-select: none; -webkit-user-select: none; white-space: pre;
1109
+ }
1110
+ /* C13 · fenced code (paper-ground panel) and image alt-caption fallback */
1111
+ .nb-md-fence {
1112
+ background: var(--nb-sub-paper); border: 1px solid var(--nb-border); border-radius: 8px;
1113
+ padding: 12px 14px; margin: 0 0 16px; overflow-x: auto;
1114
+ font-family: var(--fm); font-size: 12.5px; line-height: 1.7; color: var(--nb-body);
1115
+ white-space: pre;
1116
+ }
1117
+ .nb-md-caption {
1118
+ display: block; font-family: var(--fm); font-size: 11px; color: var(--nb-dimmer);
1119
+ margin: 0 0 16px;
1120
+ }
1121
+ /* D19 · wide-frame index freeze (>15 data columns scroll with a sticky index) */
1122
+ .nb-df--wide td.nb-df-idx { position: sticky; left: 0; background: #FFFFFF; }
1123
+ .nb-df--wide thead th:first-child { position: sticky; left: 0; background: var(--nb-sub-paper); }
1124
+ /* D23 · traceback source mini-theme (keyword / string / comment) */
1125
+ .nb-tb-kw { color: #B85C2E; }
1126
+ .nb-tb-str { color: #8A5A16; }
1127
+ .nb-tb-com { color: #C08A5A; }
1128
+ /* E25 · checked-checkbox tick upgraded to pure white (wins over the SVG presentation attr) */
1129
+ .nb-checkbox.is-checked svg { stroke: #FFFFFF; }
1130
+ .nb-stage-observation{
1131
+ overflow:hidden;border:1px solid var(--nb-border);border-radius:10px;background:#fff
1132
+ }
1133
+ .nb-stage-observation>header{
1134
+ display:flex;flex-wrap:wrap;gap:var(--nb-stack-gap);align-items:baseline;
1135
+ padding:var(--nb-inset-y) var(--nb-inset-x);background:var(--nb-sub-paper)
1136
+ }
1137
+ .nb-stage-observation>header span,.nb-stage-observation footer{
1138
+ color:var(--nb-dimmer);font:11px/1.4 var(--fm)
1139
+ }
1140
+ .nb-stage-observation>header strong,.nb-stage-observation>header small{
1141
+ min-width:0;overflow-wrap:anywhere
1142
+ }
1143
+ .nb-stage-observation>header small{
1144
+ margin-left:auto;color:var(--nb-dimmer);font:10px/1.4 var(--fm)
1145
+ }
1146
+ .nb-stage-observation dl{display:flex;flex-wrap:wrap;column-gap:24px;row-gap:var(--nb-inset-y);
1147
+ margin:0;padding:var(--nb-inset-y) var(--nb-inset-x)}
1148
+ .nb-stage-observation dl div{display:grid;gap:3px}
1149
+ .nb-stage-observation dt{color:var(--nb-dimmer);font-size:11px}
1150
+ .nb-stage-observation dd{margin:0;font:600 13px/1.3 var(--fm)}
1151
+ .nb-stage-table{
1152
+ overflow:auto;border-top:1px solid var(--nb-border);border-bottom:1px solid var(--nb-border)
1153
+ }
1154
+ .nb-stage-table table{width:100%;border-collapse:collapse}
1155
+ .nb-stage-table th,.nb-stage-table td{
1156
+ padding:9px var(--nb-inset-x);border-right:1px solid var(--nb-border);
1157
+ text-align:left;white-space:nowrap
1158
+ }
1159
+ .nb-stage-table th{position:sticky;top:0;background:var(--nb-sub-paper);font-size:11px}
1160
+ .nb-stage-table td{font:12px/1.4 var(--fm)}
1161
+ .nb-stage-observation footer,.nb-stage-policy{
1162
+ display:block;margin:0;padding:9px var(--nb-inset-x)
1163
+ }
1164
+ .nb-stage-evidence{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
1165
+ border-top:1px solid var(--nb-border)}
1166
+ .nb-stage-evidence>section,.nb-stage-window{min-width:0;padding:var(--nb-section-gap);
1167
+ border-right:1px solid var(--nb-border);border-bottom:1px solid var(--nb-border)}
1168
+ .nb-stage-window summary{cursor:pointer;color:var(--nb-body);font-size:12px;font-weight:600}
1169
+ .nb-stage-window p{margin:var(--nb-stack-gap) 0 var(--nb-inset-y);color:var(--nb-muted);
1170
+ font-size:12px;overflow-wrap:anywhere}
1171
+ .nb-stage-window .nb-stage-table{margin-top:var(--nb-stack-gap)}
1172
+ .nb-stage-evidence h4{margin:0 0 var(--nb-stack-gap);color:var(--nb-dim);
1173
+ font:600 10px/1.4 var(--fm);
1174
+ letter-spacing:.1em;text-transform:uppercase}
1175
+ .nb-stage-schema,.nb-stage-findings,.nb-stage-lineage{
1176
+ display:grid;gap:var(--nb-stack-gap);margin:0;padding:0;list-style:none
1177
+ }
1178
+ .nb-stage-schema li,.nb-stage-lineage li{display:grid;
1179
+ grid-template-columns:minmax(90px,.7fr) minmax(0,1fr);gap:4px 10px;font-size:12px}
1180
+ .nb-stage-schema span,.nb-stage-lineage span,.nb-stage-lineage small{overflow-wrap:anywhere;
1181
+ color:var(--nb-muted);font:11px/1.4 var(--fm)}
1182
+ .nb-stage-lineage small{grid-column:2}.nb-stage-findings li{display:grid;
1183
+ grid-template-columns:auto minmax(0,1fr) auto;gap:8px;font-size:12px}
1184
+ .nb-stage-findings .is-warning strong,.nb-stage-findings .is-error strong{color:var(--nb-rust)}
1185
+ .nb-stage-findings small{color:var(--nb-dimmer)}.nb-stage-audit{grid-column:1/-1}
1186
+ .nb-stage-audit p{margin:3px 0;color:var(--nb-muted);font-size:12px}
1187
+ .nb-stage-audit code{display:block;overflow:hidden;color:var(--nb-dimmer);
1188
+ font:10px/1.4 var(--fm);text-overflow:ellipsis}
1189
+ .nb-stage-operation{grid-column:1/-1;background:var(--nb-sub-paper)}
1190
+ .nb-stage-operation p{margin:0 0 6px;color:var(--nb-muted);font-size:12px}
1191
+ .nb-stage-operation code{display:block;overflow-wrap:anywhere;font:11px/1.45 var(--fm)}
1192
+ .nb-source-observation{
1193
+ overflow:hidden;border:1px solid var(--nb-border);border-radius:10px;background:#fff
1194
+ }
1195
+ .nb-source-observation>header{
1196
+ display:flex;flex-wrap:wrap;gap:var(--nb-stack-gap);align-items:baseline;
1197
+ padding:var(--nb-inset-y) var(--nb-inset-x);background:var(--nb-sub-paper)
1198
+ }
1199
+ .nb-source-observation>header span,.nb-source-observation>header small{
1200
+ color:var(--nb-dimmer);font:11px/1.4 var(--fm)
1201
+ }
1202
+ .nb-source-observation>header strong,.nb-source-observation>header small{
1203
+ min-width:0;overflow-wrap:anywhere
1204
+ }
1205
+ .nb-source-observation>header small{margin-left:auto}
1206
+ .nb-source-observation dl{display:flex;flex-wrap:wrap;column-gap:24px;
1207
+ row-gap:var(--nb-inset-y);margin:0;padding:var(--nb-inset-y) var(--nb-inset-x)}
1208
+ .nb-source-observation dl div{display:grid;gap:3px}
1209
+ .nb-source-observation dt{color:var(--nb-dimmer);font-size:11px}
1210
+ .nb-source-observation dd{margin:0;font:600 13px/1.3 var(--fm)}
1211
+ .nb-source-columns{
1212
+ display:flex;flex-wrap:wrap;gap:var(--nb-stack-gap);margin:0;
1213
+ padding:0 var(--nb-inset-x) var(--nb-inset-y);list-style:none
1214
+ }
1215
+ .nb-source-columns code{
1216
+ padding:3px 6px;background:var(--nb-sub-paper);border-radius:4px;font:11px/1.4 var(--fm)
1217
+ }
1218
+ .nb-source-observation footer{
1219
+ display:block;padding:9px var(--nb-inset-x);border-top:1px solid var(--nb-border)
1220
+ }
1221
+ .nb-source-observation footer code{color:var(--nb-dimmer);font:10px/1.4 var(--fm)}
1222
+ @container (max-width:699px){
1223
+ .nb-stage-evidence{grid-template-columns:minmax(0,1fr)}
1224
+ .nb-stage-audit{grid-column:auto}
1225
+ .nb-stage-observation>header small,.nb-source-observation>header small{
1226
+ width:100%;margin-left:0
1227
+ }
1228
+ .nb-stage-findings li{grid-template-columns:minmax(96px,auto) minmax(0,1fr)}
1229
+ .nb-stage-findings small{grid-column:2}
1230
+ }
1231
+ """.strip()
1232
+
1233
+ # Container-query breakpoints.
1234
+ _BREAKPOINTS = """
1235
+ @container (max-width: 1099px) { .nb-outline { display: none; } }
1236
+ @container (max-width: 799px) {
1237
+ .nb-cell { grid-template-columns: 44px minmax(0, 1fr); }
1238
+ .nb-io { margin-left: -44px; grid-template-columns: 44px minmax(0, 1fr); }
1239
+ }
1240
+ @container (max-width: 559px) {
1241
+ .nb-cell { grid-template-columns: minmax(0, 1fr); }
1242
+ .nb-gutter { grid-column: 1; display: flex; gap: 10px; }
1243
+ .nb-content { grid-column: 1; }
1244
+ .nb-io { margin-left: 0; grid-template-columns: minmax(0, 1fr); }
1245
+ .nb-io-gutter, .nb-io-body { grid-column: 1; }
1246
+ .nb-code, .nb-panel { border-radius: 0; }
1247
+ }
1248
+ """.strip()
1249
+
1250
+ # Print.
1251
+ _PRINT = """
1252
+ @media print {
1253
+ .nb-shell { border: none; box-shadow: none; }
1254
+ .nb-outline, .nb-toolbar { display: none; }
1255
+ .nb-code { background: var(--nb-panel); }
1256
+ .nb-cell { break-inside: avoid; }
1257
+ }
1258
+ """.strip()
1259
+
1260
+ # Reduced motion.
1261
+ _REDUCED_MOTION = """
1262
+ @media (prefers-reduced-motion: reduce) {
1263
+ .nb-kernel--busy .nb-kernel-dot, .nb-prompt--running { animation: none; }
1264
+ .nb-shell *, .nb-shell *::before, .nb-shell *::after { animation: none !important; }
1265
+ }
1266
+ """.strip()
1267
+
1268
+
1269
+ def build_css(mode: str = "static") -> str:
1270
+ """Emit the whole stylesheet for ``mode`` — the renderer's only source of CSS.
1271
+
1272
+ ``static`` and ``embed`` hide the chrome they cannot drive (toolbar always; header,
1273
+ outline, and footer additionally in ``embed``); ``connected`` shows everything. Keyframes,
1274
+ container-query breakpoints, print rules, and the reduced-motion gate are always present so a
1275
+ printed or motion-averse render degrades without a second pass. Raises on an unknown mode
1276
+ rather than silently shipping unstyled output.
1277
+ """
1278
+ if mode not in VALID_MODES:
1279
+ raise ValueError(f"unknown render mode: {mode!r} (expected one of {VALID_MODES})")
1280
+
1281
+ parts = [
1282
+ _root_vars(),
1283
+ _FONT_ALIAS,
1284
+ KEYFRAMES,
1285
+ _BASE_CSS,
1286
+ _INTEGRATION_CSS,
1287
+ _BREAKPOINTS,
1288
+ _PRINT,
1289
+ _REDUCED_MOTION,
1290
+ ]
1291
+ if mode in ("static", "embed"):
1292
+ parts.append(".nb-toolbar { display: none; }")
1293
+ if mode == "embed":
1294
+ parts.append(".nb-header, .nb-outline, .nb-footer { display: none; }")
1295
+ return "\n".join(parts)