@mj-biz-apps/contracts-ng 0.2.0 → 0.3.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 (38) hide show
  1. package/dist/lib/form-panels/contract-form.panels.d.ts +77 -0
  2. package/dist/lib/form-panels/contract-form.panels.d.ts.map +1 -0
  3. package/dist/lib/form-panels/contract-form.panels.js +955 -0
  4. package/dist/lib/form-panels/contract-form.panels.js.map +1 -0
  5. package/dist/lib/form-panels/contract-form.policy.d.ts +5 -0
  6. package/dist/lib/form-panels/contract-form.policy.d.ts.map +1 -0
  7. package/dist/lib/form-panels/contract-form.policy.js +33 -0
  8. package/dist/lib/form-panels/contract-form.policy.js.map +1 -0
  9. package/dist/lib/form-panels/contract.panels.d.ts +7 -1
  10. package/dist/lib/form-panels/contract.panels.d.ts.map +1 -1
  11. package/dist/lib/form-panels/contract.panels.js +395 -236
  12. package/dist/lib/form-panels/contract.panels.js.map +1 -1
  13. package/dist/lib/form-panels/organization.panels.d.ts +4 -13
  14. package/dist/lib/form-panels/organization.panels.d.ts.map +1 -1
  15. package/dist/lib/form-panels/organization.panels.js +54 -62
  16. package/dist/lib/form-panels/organization.panels.js.map +1 -1
  17. package/dist/lib/form-panels/person.panels.d.ts +14 -0
  18. package/dist/lib/form-panels/person.panels.d.ts.map +1 -0
  19. package/dist/lib/form-panels/person.panels.js +108 -0
  20. package/dist/lib/form-panels/person.panels.js.map +1 -0
  21. package/dist/lib/form-panels/supersede.panel.d.ts +11 -2
  22. package/dist/lib/form-panels/supersede.panel.d.ts.map +1 -1
  23. package/dist/lib/form-panels/supersede.panel.js +44 -13
  24. package/dist/lib/form-panels/supersede.panel.js.map +1 -1
  25. package/dist/lib/pages/contracts-dashboard.page.d.ts +37 -17
  26. package/dist/lib/pages/contracts-dashboard.page.d.ts.map +1 -1
  27. package/dist/lib/pages/contracts-dashboard.page.js +365 -63
  28. package/dist/lib/pages/contracts-dashboard.page.js.map +1 -1
  29. package/dist/lib/sections/section-shell.component.js +2 -2
  30. package/dist/public-api.d.ts +3 -1
  31. package/dist/public-api.d.ts.map +1 -1
  32. package/dist/public-api.js +15 -4
  33. package/dist/public-api.js.map +1 -1
  34. package/package.json +2 -3
  35. package/dist/lib/form-panels/record-files.panel.d.ts +0 -151
  36. package/dist/lib/form-panels/record-files.panel.d.ts.map +0 -1
  37. package/dist/lib/form-panels/record-files.panel.js +0 -1046
  38. package/dist/lib/form-panels/record-files.panel.js.map +0 -1
@@ -110,7 +110,7 @@ export class MJCSectionShellComponent {
110
110
  MJPageBodyComponent,
111
111
  MJLeftNavComponent,
112
112
  MJLeftNavContentComponent,
113
- MJPageBodyInteriorComponent], styles: ["/**\n * contracts-kit.css \u2014 ported from design-docs/ui-design/mockups-v2/tokens.css.\n *\n * \u26A0 SEMANTIC TOKENS ONLY. MJ's design-token rule is explicit: *\"NEVER use primitive tokens\n * (`--mj-color-neutral-*`, `--mj-color-brand-*`) in component CSS. Primitives don't adapt to dark\n * mode.\"* An earlier version of this file used twelve of them, because the mockup did \u2014 and in a\n * standalone mockup page that is harmless, since there is no dark mode to adapt to. Ported into a real\n * component stylesheet it means every tinted surface, chip and clause box keeps its LIGHT colour when\n * the app is themed dark. That is the theming break, and it is invisible until someone switches theme.\n *\n * The mapping applied: neutral-50 \u2192 bg-surface-sunken, neutral-100 \u2192 border-subtle, neutral-300 \u2192\n * border-strong, success/error/warning-50 \u2192 status-*-bg, success/error-700 \u2192 status-*-text, brand-50 \u2192\n * status-info-bg, brand-100 \u2192 status-info-border, brand-700/900 \u2192 status-info-text. `#fff` on a brand\n * fill \u2192 `--mj-brand-on-primary`.\n *\n * THE MOCKUPS ARE THE SPEC, and this file exists to keep them so. An earlier version of this kit was\n * written from MEMORY of them, and it was wrong in a way that is invisible in source and obvious on\n * screen: it used token names that do not exist. `--mj-font-size-sm`, `--mj-text-tertiary`,\n * `--mj-color-warning-text`, `--mj-color-success-border` and four others are not MJ tokens (the real\n * names are `--mj-text-sm`, `--mj-status-warning-text`, `--mj-status-success`, \u2026). Every one of those\n * resolved to NOTHING \u2014 so font sizes fell back to browser defaults and the state chips rendered with\n * no colour at all. That is most of what \"looks bad\" was.\n *\n * So: class names and rules below are the mockup's, verbatim where possible, and **every token used\n * here has been checked to exist in MJ's `_tokens.scss`.** If you add a rule, check the token first \u2014\n * a missing custom property fails silently, which is the worst failure mode CSS has.\n *\n * SHIPPED VIA THE SECTION SHELL (`styleUrls` + `ViewEncapsulation.None`). `ngc` only compiles what a\n * component references, so a stylesheet nothing references is built into dist and never loaded.\n * `None` is required, not lazy: these classes are used by DESCENDANT components.\n *\n * Prefix note: the mockup used bare class names (`.panel`, `.chip`) because it was a standalone page.\n * Here everything is `mjc-` prefixed \u2014 bare `.panel` inside a real Explorer would collide with MJ's own\n * chrome, and `ViewEncapsulation.None` means these rules are global.\n */\n\n/* \u2500\u2500 Page frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-page {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-5);\n}\n\n/* A grid page needs a DEFINITE height: mj-explorer-entity-data-grid is height:100% outside a related\n panel, and 100% of an auto-height parent is zero \u2014 the grid renders no rows while its toolbar still\n reports the count. MJ's own source documents that symptom. `min-height: 0` on the fill slot is\n mandatory: a flex child defaults to min-height:auto and refuses to shrink, so without it the grid\n pushes the page taller instead of scrolling inside itself. */\n.mjc-page--grid { height: 100%; min-height: 0; }\n.mjc-grid-fill { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n\n/* Intro prose. Constrained measure \u2014 text stops being readable much past this \u2014 and it is a real\n block with real spacing, not a bare text node floating between cards. */\n.mjc-page__intro {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n line-height: 1.55;\n margin: 0;\n max-width: 78ch;\n}\n\n/* \u2500\u2500 Panel body helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Our panels are real `<mj-collapsible-panel>`s, so MJ paints the frame, the header and the spacing.\n These classes style only what goes INSIDE one. */\n\n.mjc-body { padding: var(--mj-space-4); }\n.mjc-body--flush { padding: 0; } /* a table fills the panel edge to edge */\n.mjc-body > * + * { margin-top: var(--mj-space-3); } /* nothing ever touches its neighbour */\n\n.mjc-note {\n margin: 0;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n line-height: 1.55;\n}\n\n/* A note under a flush table needs its own padding and a rule above it, or it reads as a table row. */\n.mjc-note--footer {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* \u2500\u2500 Hero (mockup 1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-hero {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-4) var(--mj-space-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mjc-hero__identity { display: flex; align-items: center; gap: var(--mj-space-4); min-width: 0; }\n\n.mjc-hero__avatar {\n flex: none;\n width: 52px; height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex; align-items: center; justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xl, 1.375rem);\n}\n\n.mjc-hero__copy { min-width: 0; flex: 1; }\n\n.mjc-hero__title-row {\n display: flex; align-items: center; flex-wrap: wrap;\n gap: var(--mj-space-2) var(--mj-space-3);\n}\n\n.mjc-hero__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n line-height: 1.25;\n /* Long contract descriptions must not push the chips off the card. */\n overflow-wrap: anywhere;\n}\n\n.mjc-hero__meta {\n display: flex; flex-wrap: wrap;\n gap: var(--mj-space-3);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n margin-top: var(--mj-space-2);\n}\n\n/* auto-fit so five stats sit in a row on a wide screen and reflow on a laptop, rather than\n overflowing the card \u2014 which is what a fixed five-column grid did. */\n.mjc-hero__stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));\n gap: var(--mj-space-3);\n}\n\n.mjc-stat {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n min-width: 0;\n}\n.mjc-stat__label {\n display: block; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-stat__value {\n display: block; font-size: var(--mj-text-base); font-weight: 700; margin-top: 2px;\n overflow-wrap: anywhere;\n}\n.mjc-stat__sub { display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted); }\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-chip {\n display: inline-flex; align-items: center; gap: 4px;\n font-size: var(--mj-text-xs); font-weight: 600;\n padding: 2px 9px; border-radius: 999px;\n border: 1px solid transparent; white-space: nowrap;\n}\n.mjc-chip--ok { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); border-color: var(--mj-status-success); }\n.mjc-chip--warn { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); border-color: var(--mj-status-warning); }\n.mjc-chip--error { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); border-color: var(--mj-status-error); }\n.mjc-chip--info { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); border-color: var(--mj-status-info-border); }\n.mjc-chip--muted { background: var(--mj-border-subtle); color: var(--mj-text-secondary); border-color: var(--mj-border-default); }\n\n/* \u2500\u2500 Buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-btn {\n display: inline-flex; align-items: center; gap: 6px;\n font-size: var(--mj-text-sm); font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n.mjc-btn:disabled { opacity: .5; cursor: default; }\n.mjc-btn--primary { background: var(--mj-brand-primary); border-color: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mjc-btn--flat { background: transparent; border-color: transparent; color: var(--mj-brand-primary); }\n.mjc-btn--sm { padding: 3px 9px; font-size: var(--mj-text-xs); }\n.mjc-btn--danger { color: var(--mj-status-error-text); border-color: transparent; background: transparent; }\n\n/* \u2500\u2500 Field grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-fields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-field > label {\n display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: .04em; margin-bottom: 3px;\n}\n.mjc-field .mjc-val {\n padding: 6px 9px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n min-height: 31px;\n overflow-wrap: anywhere;\n}\n.mjc-field .mjc-val--ro { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.mjc-hint { color: var(--mj-text-muted); font-size: var(--mj-text-xs); margin-top: 3px; }\n\n/* \u2500\u2500 Tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The mockup renders modifications, documents and lineage as TABLES, not stacked cards. With three\n or more rows a table is scannable and a stack is a wall. */\n\ntable.mjc-grid { width: 100%; border-collapse: collapse; }\ntable.mjc-grid th {\n text-align: left; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700;\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1.5px solid var(--mj-border-default);\n}\ntable.mjc-grid td {\n padding: var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-subtle);\n vertical-align: top;\n}\ntable.mjc-grid tr:last-child td { border-bottom: 0; }\ntable.mjc-grid tbody tr:hover td { background: var(--mj-bg-surface-sunken); }\n.mjc-row--click { cursor: pointer; }\n\n.mjc-muted { color: var(--mj-text-muted); }\n.mjc-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 The clause pair (mockups 1 and 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The standard clause and what this contract says instead, read side by side. This is the app's\n central idea rendered, so it gets real styling rather than two paragraphs. */\n\n.mjc-pair {\n display: grid; grid-template-columns: 1fr; gap: var(--mj-space-3);\n margin-top: var(--mj-space-2);\n}\n/* Side by side only when there is room \u2014 two 40ch columns on a laptop is worse than one readable one. */\n@media (min-width: 1100px) { .mjc-pair { grid-template-columns: 1fr 1fr; } }\n\n.mjc-pair__tag {\n display: block; font-size: var(--mj-text-xs); font-weight: 700;\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.mjc-pair__tag--mod { color: var(--mj-status-warning-text); }\n\n.mjc-clause {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-left: 2px solid var(--mj-border-strong);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n margin: 0;\n /* Clause text carries its own line breaks, and 9.1 is a single 1,100-character sentence in caps \u2014\n both must wrap inside the box rather than escaping it. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.mjc-clause--mod {\n border-left-color: var(--mj-status-warning);\n background: var(--mj-status-warning-bg);\n color: var(--mj-text-primary);\n}\n\n.mjc-toggle {\n font-size: var(--mj-text-xs); color: var(--mj-brand-primary);\n font-weight: 600; margin-top: 4px; background: none; border: 0; padding: 0; cursor: pointer;\n}\n\n/* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-flag {\n background: var(--mj-status-warning-bg);\n border-left: 3px solid var(--mj-status-warning);\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-xs);\n color: var(--mj-status-warning-text);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n line-height: 1.55;\n}\n\n/* \u2500\u2500 Invalid input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* A required field the user has emptied. Border + ring only \u2014 no background change, because these\n are prose textareas and tinting the reading surface makes the text itself harder to read, which\n is the opposite of helpful when the point is \"write something here\". Tokens only, per the\n design-token gate. */\n.mjc-invalid {\n border-color: var(--mj-status-error) !important;\n box-shadow: 0 0 0 2px var(--mj-status-error-bg);\n outline: none;\n}\n\n/* \u2500\u2500 Filter pills (watchlist) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-pills { display: flex; flex-wrap: wrap; gap: var(--mj-space-2); align-items: center; }\n\n.mjc-pill {\n appearance: none; cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-radius: 999px;\n padding: 3px var(--mj-space-3);\n font-size: var(--mj-text-sm);\n line-height: 1.6;\n display: inline-flex; align-items: center; gap: var(--mj-space-2);\n}\n.mjc-pill:hover { border-color: var(--mj-brand-primary); color: var(--mj-text-primary); }\n.mjc-pill:disabled { opacity: .5; cursor: default; }\n.mjc-pill--active {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-brand-primary);\n color: var(--mj-status-info-text);\n font-weight: 700;\n}\n.mjc-pill__count { font-variant-numeric: tabular-nums; opacity: .85; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A sentence in a bordered box, never a bare line of text in whitespace. */\n\n.mjc-empty {\n display: flex; align-items: center; gap: var(--mj-space-2); justify-content: center;\n padding: var(--mj-space-6);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n text-align: center;\n}\n"], encapsulation: 2 });
113
+ MJPageBodyInteriorComponent], styles: ["/**\n * contracts-kit.css \u2014 ported from design-docs/ui-design/mockups-v2/tokens.css.\n *\n * \u26A0 SEMANTIC TOKENS ONLY. MJ's design-token rule is explicit: *\"NEVER use primitive tokens\n * (`--mj-color-neutral-*`, `--mj-color-brand-*`) in component CSS. Primitives don't adapt to dark\n * mode.\"* An earlier version of this file used twelve of them, because the mockup did \u2014 and in a\n * standalone mockup page that is harmless, since there is no dark mode to adapt to. Ported into a real\n * component stylesheet it means every tinted surface, chip and clause box keeps its LIGHT colour when\n * the app is themed dark. That is the theming break, and it is invisible until someone switches theme.\n *\n * The mapping applied: neutral-50 \u2192 bg-surface-sunken, neutral-100 \u2192 border-subtle, neutral-300 \u2192\n * border-strong, success/error/warning-50 \u2192 status-*-bg, success/error-700 \u2192 status-*-text, brand-50 \u2192\n * status-info-bg, brand-100 \u2192 status-info-border, brand-700/900 \u2192 status-info-text. `#fff` on a brand\n * fill \u2192 `--mj-brand-on-primary`.\n *\n * THE MOCKUPS ARE THE SPEC, and this file exists to keep them so. An earlier version of this kit was\n * written from MEMORY of them, and it was wrong in a way that is invisible in source and obvious on\n * screen: it used token names that do not exist. `--mj-font-size-sm`, `--mj-text-tertiary`,\n * `--mj-color-warning-text`, `--mj-color-success-border` and four others are not MJ tokens (the real\n * names are `--mj-text-sm`, `--mj-status-warning-text`, `--mj-status-success`, \u2026). Every one of those\n * resolved to NOTHING \u2014 so font sizes fell back to browser defaults and the state chips rendered with\n * no colour at all. That is most of what \"looks bad\" was.\n *\n * So: class names and rules below are the mockup's, verbatim where possible, and **every token used\n * here has been checked to exist in MJ's `_tokens.scss`.** If you add a rule, check the token first \u2014\n * a missing custom property fails silently, which is the worst failure mode CSS has.\n *\n * SHIPPED VIA THE SECTION SHELL (`styleUrls` + `ViewEncapsulation.None`). `ngc` only compiles what a\n * component references, so a stylesheet nothing references is built into dist and never loaded.\n * `None` is required, not lazy: these classes are used by DESCENDANT components.\n *\n * Prefix note: the mockup used bare class names (`.panel`, `.chip`) because it was a standalone page.\n * Here everything is `mjc-` prefixed \u2014 bare `.panel` inside a real Explorer would collide with MJ's own\n * chrome, and `ViewEncapsulation.None` means these rules are global.\n */\n\n/* \u2500\u2500 Page frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-page {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-5);\n}\n\n/* A grid page needs a DEFINITE height: mj-explorer-entity-data-grid is height:100% outside a related\n panel, and 100% of an auto-height parent is zero \u2014 the grid renders no rows while its toolbar still\n reports the count. MJ's own source documents that symptom. `min-height: 0` on the fill slot is\n mandatory: a flex child defaults to min-height:auto and refuses to shrink, so without it the grid\n pushes the page taller instead of scrolling inside itself. */\n.mjc-page--grid { height: 100%; min-height: 0; }\n.mjc-grid-fill { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n\n/* Intro prose. Constrained measure \u2014 text stops being readable much past this \u2014 and it is a real\n block with real spacing, not a bare text node floating between cards. */\n.mjc-page__intro {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n line-height: 1.55;\n margin: 0;\n max-width: 78ch;\n}\n\n/* \u2500\u2500 Panel body helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Our panels are real `<mj-collapsible-panel>`s, so MJ paints the frame, the header and the spacing.\n These classes style only what goes INSIDE one. */\n\n.mjc-body { padding: var(--mj-space-4); }\n.mjc-body--flush { padding: 0; } /* a table fills the panel edge to edge */\n.mjc-body > * + * { margin-top: var(--mj-space-3); } /* nothing ever touches its neighbour */\n\n.mjc-note {\n margin: 0;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n line-height: 1.55;\n}\n\n/* A note under a flush table needs its own padding and a rule above it, or it reads as a table row. */\n.mjc-note--footer {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* \u2500\u2500 Hero (mockup 1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-hero {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-4) var(--mj-space-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mjc-hero__identity { display: flex; align-items: center; gap: var(--mj-space-4); min-width: 0; }\n\n.mjc-hero__avatar {\n flex: none;\n width: 52px; height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex; align-items: center; justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xl, 1.375rem);\n}\n\n.mjc-hero__copy { min-width: 0; flex: 1; }\n\n.mjc-hero__title-row {\n display: flex; align-items: center; flex-wrap: wrap;\n gap: var(--mj-space-2) var(--mj-space-3);\n}\n\n.mjc-hero__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n line-height: 1.25;\n /* Long contract descriptions must not push the chips off the card. */\n overflow-wrap: anywhere;\n}\n\n.mjc-hero__meta {\n display: flex; flex-wrap: wrap;\n gap: var(--mj-space-3);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n margin-top: var(--mj-space-2);\n}\n\n/* auto-fit so five stats sit in a row on a wide screen and reflow on a laptop, rather than\n overflowing the card \u2014 which is what a fixed five-column grid did. */\n.mjc-hero__stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));\n gap: var(--mj-space-3);\n}\n\n.mjc-stat {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n min-width: 0;\n}\n.mjc-stat__label {\n display: block; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-stat__value {\n display: block; font-size: var(--mj-text-base); font-weight: 700; margin-top: 2px;\n overflow-wrap: anywhere;\n}\n.mjc-stat__sub { display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted); }\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-chip {\n display: inline-flex; align-items: center; gap: 4px;\n font-size: var(--mj-text-xs); font-weight: 600;\n padding: 2px 9px; border-radius: 999px;\n border: 1px solid transparent; white-space: nowrap;\n}\n.mjc-chip--ok { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); border-color: var(--mj-status-success); }\n.mjc-chip--warn { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); border-color: var(--mj-status-warning); }\n.mjc-chip--error { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); border-color: var(--mj-status-error); }\n.mjc-chip--info { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); border-color: var(--mj-status-info-border); }\n.mjc-chip--muted { background: var(--mj-border-subtle); color: var(--mj-text-secondary); border-color: var(--mj-border-default); }\n\n/* \u2500\u2500 Buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-btn {\n display: inline-flex; align-items: center; gap: 6px;\n font-size: var(--mj-text-sm); font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n.mjc-btn:disabled { opacity: .5; cursor: default; }\n.mjc-btn--primary { background: var(--mj-brand-primary); border-color: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mjc-btn--flat { background: transparent; border-color: transparent; color: var(--mj-brand-primary); }\n.mjc-btn--sm { padding: 3px 9px; font-size: var(--mj-text-xs); }\n.mjc-btn--danger { color: var(--mj-status-error-text); border-color: transparent; background: transparent; }\n\n/* \u2500\u2500 Field grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-fields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-field > label {\n display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: .04em; margin-bottom: 3px;\n}\n.mjc-field .mjc-val {\n padding: 6px 9px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n min-height: 31px;\n overflow-wrap: anywhere;\n}\n.mjc-field .mjc-val--ro { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.mjc-hint { color: var(--mj-text-muted); font-size: var(--mj-text-xs); margin-top: 3px; }\n\n/* \u2500\u2500 Tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The mockup renders modifications, documents and lineage as TABLES, not stacked cards. With three\n or more rows a table is scannable and a stack is a wall. */\n\ntable.mjc-grid { width: 100%; border-collapse: collapse; }\ntable.mjc-grid th {\n text-align: left; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700;\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1.5px solid var(--mj-border-default);\n}\ntable.mjc-grid td {\n padding: var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-subtle);\n vertical-align: top;\n}\ntable.mjc-grid tr:last-child td { border-bottom: 0; }\ntable.mjc-grid tbody tr:hover td { background: var(--mj-bg-surface-sunken); }\n.mjc-row--click { cursor: pointer; }\n\n.mjc-muted { color: var(--mj-text-muted); }\n.mjc-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 The clause pair (mockups 1 and 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The standard clause and what this contract says instead, read side by side. This is the app's\n central idea rendered, so it gets real styling rather than two paragraphs. */\n\n.mjc-pair {\n display: grid; grid-template-columns: 1fr; gap: var(--mj-space-3);\n margin-top: var(--mj-space-2);\n}\n/* Side by side only when there is room \u2014 two 40ch columns on a laptop is worse than one readable one. */\n@media (min-width: 1100px) { .mjc-pair { grid-template-columns: 1fr 1fr; } }\n\n.mjc-pair__tag {\n display: block; font-size: var(--mj-text-xs); font-weight: 700;\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.mjc-pair__tag--mod { color: var(--mj-status-warning-text); }\n\n.mjc-clause {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-left: 2px solid var(--mj-border-strong);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n margin: 0;\n /* Clause text carries its own line breaks, and 9.1 is a single 1,100-character sentence in caps \u2014\n both must wrap inside the box rather than escaping it. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.mjc-clause--mod {\n border-left-color: var(--mj-status-warning);\n background: var(--mj-status-warning-bg);\n color: var(--mj-text-primary);\n}\n\n.mjc-toggle {\n font-size: var(--mj-text-xs); color: var(--mj-brand-primary);\n font-weight: 600; margin-top: 4px; background: none; border: 0; padding: 0; cursor: pointer;\n}\n\n/* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-flag {\n background: var(--mj-status-warning-bg);\n border-left: 3px solid var(--mj-status-warning);\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-xs);\n color: var(--mj-status-warning-text);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n line-height: 1.55;\n}\n\n/* \u2500\u2500 Invalid input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* A required field the user has emptied. Border + ring only \u2014 no background change, because these\n are prose textareas and tinting the reading surface makes the text itself harder to read, which\n is the opposite of helpful when the point is \"write something here\". Tokens only, per the\n design-token gate. */\n.mjc-invalid {\n border-color: var(--mj-status-error) !important;\n box-shadow: 0 0 0 2px var(--mj-status-error-bg);\n outline: none;\n}\n\n/* \u2500\u2500 Filter pills (watchlist) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-pills { display: flex; flex-wrap: wrap; gap: var(--mj-space-2); align-items: center; }\n\n.mjc-pill {\n appearance: none; cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-radius: 999px;\n padding: 3px var(--mj-space-3);\n font-size: var(--mj-text-sm);\n line-height: 1.6;\n display: inline-flex; align-items: center; gap: var(--mj-space-2);\n}\n.mjc-pill:hover { border-color: var(--mj-brand-primary); color: var(--mj-text-primary); }\n.mjc-pill:disabled { opacity: .5; cursor: default; }\n.mjc-pill--active {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-brand-primary);\n color: var(--mj-status-info-text);\n font-weight: 700;\n}\n.mjc-pill__count { font-variant-numeric: tabular-nums; opacity: .85; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 Dashboard command center \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-kpis {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));\n gap: var(--mj-space-3);\n}\n.mjc-kpi {\n appearance: none;\n font: inherit;\n text-align: left;\n color: inherit;\n cursor: pointer;\n padding: var(--mj-space-3) var(--mj-space-4);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n}\n.mjc-kpi:hover { border-color: var(--mj-brand-primary); }\n.mjc-kpi:disabled { opacity: .6; cursor: default; }\n.mjc-kpi--alert .mjc-kpi__v { color: var(--mj-status-error-text); }\n.mjc-kpi__l {\n font-size: var(--mj-text-xs);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-kpi__v {\n font-size: var(--mj-text-xl, 1.35rem);\n font-weight: 700;\n margin: 4px 0 2px;\n font-variant-numeric: tabular-nums;\n}\n.mjc-kpi__f {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n line-height: 1.35;\n}\n\n.mjc-dash-split {\n display: grid;\n grid-template-columns: 1.15fr .85fr;\n gap: var(--mj-space-3);\n}\n@media (max-width: 900px) { .mjc-dash-split { grid-template-columns: 1fr; } }\n\n.mjc-dash-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n}\n.mjc-dash-card__h {\n display: flex;\n justify-content: space-between;\n gap: var(--mj-space-2);\n align-items: baseline;\n padding: var(--mj-space-3) var(--mj-space-4);\n border-bottom: 1px solid var(--mj-border-subtle);\n font-weight: 700;\n}\n.mjc-dash-card__h span {\n font-weight: 500;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.mjc-barlist { display: flex; flex-direction: column; gap: var(--mj-space-2); padding: var(--mj-space-3) var(--mj-space-4); }\n.mjc-barrow {\n display: grid;\n grid-template-columns: 7.5rem 1fr auto;\n gap: var(--mj-space-2);\n align-items: center;\n font-size: var(--mj-text-sm);\n}\n.mjc-track {\n height: 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 99px;\n overflow: hidden;\n}\n.mjc-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 99px;\n}\n.mjc-num { font-variant-numeric: tabular-nums; font-weight: 700; }\n\n.mjc-funnel {\n display: flex;\n gap: var(--mj-space-2);\n align-items: flex-end;\n height: 10rem;\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-funnel__col {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n}\n.mjc-funnel__bar {\n width: 100%;\n min-height: 8px;\n border-radius: 8px 8px 2px 2px;\n background: var(--mj-brand-primary);\n}\n.mjc-funnel__n { font-weight: 700; }\n.mjc-funnel__lab {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.mjc-buckets {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: var(--mj-space-2);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n@media (max-width: 700px) { .mjc-buckets { grid-template-columns: 1fr 1fr; } }\n.mjc-bucket {\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n}\n\n.mjc-viewer-host {\n min-height: 420px;\n height: 480px;\n display: flex;\n flex-direction: column;\n}\n.mjc-viewer-host mj-entity-viewer {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 350px;\n width: 100%;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A sentence in a bordered box, never a bare line of text in whitespace. */\n\n.mjc-empty {\n display: flex; align-items: center; gap: var(--mj-space-2); justify-content: center;\n padding: var(--mj-space-6);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n text-align: center;\n}\n"], encapsulation: 2 });
114
114
  }
115
115
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCSectionShellComponent, [{
116
116
  type: Component,
@@ -146,7 +146,7 @@ export class MJCSectionShellComponent {
146
146
  </mj-left-nav-content>
147
147
  </mj-page-body>
148
148
  </mj-page-layout>
149
- `, styles: ["/**\n * contracts-kit.css \u2014 ported from design-docs/ui-design/mockups-v2/tokens.css.\n *\n * \u26A0 SEMANTIC TOKENS ONLY. MJ's design-token rule is explicit: *\"NEVER use primitive tokens\n * (`--mj-color-neutral-*`, `--mj-color-brand-*`) in component CSS. Primitives don't adapt to dark\n * mode.\"* An earlier version of this file used twelve of them, because the mockup did \u2014 and in a\n * standalone mockup page that is harmless, since there is no dark mode to adapt to. Ported into a real\n * component stylesheet it means every tinted surface, chip and clause box keeps its LIGHT colour when\n * the app is themed dark. That is the theming break, and it is invisible until someone switches theme.\n *\n * The mapping applied: neutral-50 \u2192 bg-surface-sunken, neutral-100 \u2192 border-subtle, neutral-300 \u2192\n * border-strong, success/error/warning-50 \u2192 status-*-bg, success/error-700 \u2192 status-*-text, brand-50 \u2192\n * status-info-bg, brand-100 \u2192 status-info-border, brand-700/900 \u2192 status-info-text. `#fff` on a brand\n * fill \u2192 `--mj-brand-on-primary`.\n *\n * THE MOCKUPS ARE THE SPEC, and this file exists to keep them so. An earlier version of this kit was\n * written from MEMORY of them, and it was wrong in a way that is invisible in source and obvious on\n * screen: it used token names that do not exist. `--mj-font-size-sm`, `--mj-text-tertiary`,\n * `--mj-color-warning-text`, `--mj-color-success-border` and four others are not MJ tokens (the real\n * names are `--mj-text-sm`, `--mj-status-warning-text`, `--mj-status-success`, \u2026). Every one of those\n * resolved to NOTHING \u2014 so font sizes fell back to browser defaults and the state chips rendered with\n * no colour at all. That is most of what \"looks bad\" was.\n *\n * So: class names and rules below are the mockup's, verbatim where possible, and **every token used\n * here has been checked to exist in MJ's `_tokens.scss`.** If you add a rule, check the token first \u2014\n * a missing custom property fails silently, which is the worst failure mode CSS has.\n *\n * SHIPPED VIA THE SECTION SHELL (`styleUrls` + `ViewEncapsulation.None`). `ngc` only compiles what a\n * component references, so a stylesheet nothing references is built into dist and never loaded.\n * `None` is required, not lazy: these classes are used by DESCENDANT components.\n *\n * Prefix note: the mockup used bare class names (`.panel`, `.chip`) because it was a standalone page.\n * Here everything is `mjc-` prefixed \u2014 bare `.panel` inside a real Explorer would collide with MJ's own\n * chrome, and `ViewEncapsulation.None` means these rules are global.\n */\n\n/* \u2500\u2500 Page frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-page {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-5);\n}\n\n/* A grid page needs a DEFINITE height: mj-explorer-entity-data-grid is height:100% outside a related\n panel, and 100% of an auto-height parent is zero \u2014 the grid renders no rows while its toolbar still\n reports the count. MJ's own source documents that symptom. `min-height: 0` on the fill slot is\n mandatory: a flex child defaults to min-height:auto and refuses to shrink, so without it the grid\n pushes the page taller instead of scrolling inside itself. */\n.mjc-page--grid { height: 100%; min-height: 0; }\n.mjc-grid-fill { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n\n/* Intro prose. Constrained measure \u2014 text stops being readable much past this \u2014 and it is a real\n block with real spacing, not a bare text node floating between cards. */\n.mjc-page__intro {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n line-height: 1.55;\n margin: 0;\n max-width: 78ch;\n}\n\n/* \u2500\u2500 Panel body helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Our panels are real `<mj-collapsible-panel>`s, so MJ paints the frame, the header and the spacing.\n These classes style only what goes INSIDE one. */\n\n.mjc-body { padding: var(--mj-space-4); }\n.mjc-body--flush { padding: 0; } /* a table fills the panel edge to edge */\n.mjc-body > * + * { margin-top: var(--mj-space-3); } /* nothing ever touches its neighbour */\n\n.mjc-note {\n margin: 0;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n line-height: 1.55;\n}\n\n/* A note under a flush table needs its own padding and a rule above it, or it reads as a table row. */\n.mjc-note--footer {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* \u2500\u2500 Hero (mockup 1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-hero {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-4) var(--mj-space-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mjc-hero__identity { display: flex; align-items: center; gap: var(--mj-space-4); min-width: 0; }\n\n.mjc-hero__avatar {\n flex: none;\n width: 52px; height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex; align-items: center; justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xl, 1.375rem);\n}\n\n.mjc-hero__copy { min-width: 0; flex: 1; }\n\n.mjc-hero__title-row {\n display: flex; align-items: center; flex-wrap: wrap;\n gap: var(--mj-space-2) var(--mj-space-3);\n}\n\n.mjc-hero__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n line-height: 1.25;\n /* Long contract descriptions must not push the chips off the card. */\n overflow-wrap: anywhere;\n}\n\n.mjc-hero__meta {\n display: flex; flex-wrap: wrap;\n gap: var(--mj-space-3);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n margin-top: var(--mj-space-2);\n}\n\n/* auto-fit so five stats sit in a row on a wide screen and reflow on a laptop, rather than\n overflowing the card \u2014 which is what a fixed five-column grid did. */\n.mjc-hero__stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));\n gap: var(--mj-space-3);\n}\n\n.mjc-stat {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n min-width: 0;\n}\n.mjc-stat__label {\n display: block; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-stat__value {\n display: block; font-size: var(--mj-text-base); font-weight: 700; margin-top: 2px;\n overflow-wrap: anywhere;\n}\n.mjc-stat__sub { display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted); }\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-chip {\n display: inline-flex; align-items: center; gap: 4px;\n font-size: var(--mj-text-xs); font-weight: 600;\n padding: 2px 9px; border-radius: 999px;\n border: 1px solid transparent; white-space: nowrap;\n}\n.mjc-chip--ok { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); border-color: var(--mj-status-success); }\n.mjc-chip--warn { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); border-color: var(--mj-status-warning); }\n.mjc-chip--error { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); border-color: var(--mj-status-error); }\n.mjc-chip--info { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); border-color: var(--mj-status-info-border); }\n.mjc-chip--muted { background: var(--mj-border-subtle); color: var(--mj-text-secondary); border-color: var(--mj-border-default); }\n\n/* \u2500\u2500 Buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-btn {\n display: inline-flex; align-items: center; gap: 6px;\n font-size: var(--mj-text-sm); font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n.mjc-btn:disabled { opacity: .5; cursor: default; }\n.mjc-btn--primary { background: var(--mj-brand-primary); border-color: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mjc-btn--flat { background: transparent; border-color: transparent; color: var(--mj-brand-primary); }\n.mjc-btn--sm { padding: 3px 9px; font-size: var(--mj-text-xs); }\n.mjc-btn--danger { color: var(--mj-status-error-text); border-color: transparent; background: transparent; }\n\n/* \u2500\u2500 Field grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-fields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-field > label {\n display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: .04em; margin-bottom: 3px;\n}\n.mjc-field .mjc-val {\n padding: 6px 9px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n min-height: 31px;\n overflow-wrap: anywhere;\n}\n.mjc-field .mjc-val--ro { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.mjc-hint { color: var(--mj-text-muted); font-size: var(--mj-text-xs); margin-top: 3px; }\n\n/* \u2500\u2500 Tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The mockup renders modifications, documents and lineage as TABLES, not stacked cards. With three\n or more rows a table is scannable and a stack is a wall. */\n\ntable.mjc-grid { width: 100%; border-collapse: collapse; }\ntable.mjc-grid th {\n text-align: left; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700;\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1.5px solid var(--mj-border-default);\n}\ntable.mjc-grid td {\n padding: var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-subtle);\n vertical-align: top;\n}\ntable.mjc-grid tr:last-child td { border-bottom: 0; }\ntable.mjc-grid tbody tr:hover td { background: var(--mj-bg-surface-sunken); }\n.mjc-row--click { cursor: pointer; }\n\n.mjc-muted { color: var(--mj-text-muted); }\n.mjc-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 The clause pair (mockups 1 and 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The standard clause and what this contract says instead, read side by side. This is the app's\n central idea rendered, so it gets real styling rather than two paragraphs. */\n\n.mjc-pair {\n display: grid; grid-template-columns: 1fr; gap: var(--mj-space-3);\n margin-top: var(--mj-space-2);\n}\n/* Side by side only when there is room \u2014 two 40ch columns on a laptop is worse than one readable one. */\n@media (min-width: 1100px) { .mjc-pair { grid-template-columns: 1fr 1fr; } }\n\n.mjc-pair__tag {\n display: block; font-size: var(--mj-text-xs); font-weight: 700;\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.mjc-pair__tag--mod { color: var(--mj-status-warning-text); }\n\n.mjc-clause {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-left: 2px solid var(--mj-border-strong);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n margin: 0;\n /* Clause text carries its own line breaks, and 9.1 is a single 1,100-character sentence in caps \u2014\n both must wrap inside the box rather than escaping it. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.mjc-clause--mod {\n border-left-color: var(--mj-status-warning);\n background: var(--mj-status-warning-bg);\n color: var(--mj-text-primary);\n}\n\n.mjc-toggle {\n font-size: var(--mj-text-xs); color: var(--mj-brand-primary);\n font-weight: 600; margin-top: 4px; background: none; border: 0; padding: 0; cursor: pointer;\n}\n\n/* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-flag {\n background: var(--mj-status-warning-bg);\n border-left: 3px solid var(--mj-status-warning);\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-xs);\n color: var(--mj-status-warning-text);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n line-height: 1.55;\n}\n\n/* \u2500\u2500 Invalid input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* A required field the user has emptied. Border + ring only \u2014 no background change, because these\n are prose textareas and tinting the reading surface makes the text itself harder to read, which\n is the opposite of helpful when the point is \"write something here\". Tokens only, per the\n design-token gate. */\n.mjc-invalid {\n border-color: var(--mj-status-error) !important;\n box-shadow: 0 0 0 2px var(--mj-status-error-bg);\n outline: none;\n}\n\n/* \u2500\u2500 Filter pills (watchlist) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-pills { display: flex; flex-wrap: wrap; gap: var(--mj-space-2); align-items: center; }\n\n.mjc-pill {\n appearance: none; cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-radius: 999px;\n padding: 3px var(--mj-space-3);\n font-size: var(--mj-text-sm);\n line-height: 1.6;\n display: inline-flex; align-items: center; gap: var(--mj-space-2);\n}\n.mjc-pill:hover { border-color: var(--mj-brand-primary); color: var(--mj-text-primary); }\n.mjc-pill:disabled { opacity: .5; cursor: default; }\n.mjc-pill--active {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-brand-primary);\n color: var(--mj-status-info-text);\n font-weight: 700;\n}\n.mjc-pill__count { font-variant-numeric: tabular-nums; opacity: .85; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A sentence in a bordered box, never a bare line of text in whitespace. */\n\n.mjc-empty {\n display: flex; align-items: center; gap: var(--mj-space-2); justify-content: center;\n padding: var(--mj-space-6);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n text-align: center;\n}\n"] }]
149
+ `, styles: ["/**\n * contracts-kit.css \u2014 ported from design-docs/ui-design/mockups-v2/tokens.css.\n *\n * \u26A0 SEMANTIC TOKENS ONLY. MJ's design-token rule is explicit: *\"NEVER use primitive tokens\n * (`--mj-color-neutral-*`, `--mj-color-brand-*`) in component CSS. Primitives don't adapt to dark\n * mode.\"* An earlier version of this file used twelve of them, because the mockup did \u2014 and in a\n * standalone mockup page that is harmless, since there is no dark mode to adapt to. Ported into a real\n * component stylesheet it means every tinted surface, chip and clause box keeps its LIGHT colour when\n * the app is themed dark. That is the theming break, and it is invisible until someone switches theme.\n *\n * The mapping applied: neutral-50 \u2192 bg-surface-sunken, neutral-100 \u2192 border-subtle, neutral-300 \u2192\n * border-strong, success/error/warning-50 \u2192 status-*-bg, success/error-700 \u2192 status-*-text, brand-50 \u2192\n * status-info-bg, brand-100 \u2192 status-info-border, brand-700/900 \u2192 status-info-text. `#fff` on a brand\n * fill \u2192 `--mj-brand-on-primary`.\n *\n * THE MOCKUPS ARE THE SPEC, and this file exists to keep them so. An earlier version of this kit was\n * written from MEMORY of them, and it was wrong in a way that is invisible in source and obvious on\n * screen: it used token names that do not exist. `--mj-font-size-sm`, `--mj-text-tertiary`,\n * `--mj-color-warning-text`, `--mj-color-success-border` and four others are not MJ tokens (the real\n * names are `--mj-text-sm`, `--mj-status-warning-text`, `--mj-status-success`, \u2026). Every one of those\n * resolved to NOTHING \u2014 so font sizes fell back to browser defaults and the state chips rendered with\n * no colour at all. That is most of what \"looks bad\" was.\n *\n * So: class names and rules below are the mockup's, verbatim where possible, and **every token used\n * here has been checked to exist in MJ's `_tokens.scss`.** If you add a rule, check the token first \u2014\n * a missing custom property fails silently, which is the worst failure mode CSS has.\n *\n * SHIPPED VIA THE SECTION SHELL (`styleUrls` + `ViewEncapsulation.None`). `ngc` only compiles what a\n * component references, so a stylesheet nothing references is built into dist and never loaded.\n * `None` is required, not lazy: these classes are used by DESCENDANT components.\n *\n * Prefix note: the mockup used bare class names (`.panel`, `.chip`) because it was a standalone page.\n * Here everything is `mjc-` prefixed \u2014 bare `.panel` inside a real Explorer would collide with MJ's own\n * chrome, and `ViewEncapsulation.None` means these rules are global.\n */\n\n/* \u2500\u2500 Page frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-page {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-5);\n}\n\n/* A grid page needs a DEFINITE height: mj-explorer-entity-data-grid is height:100% outside a related\n panel, and 100% of an auto-height parent is zero \u2014 the grid renders no rows while its toolbar still\n reports the count. MJ's own source documents that symptom. `min-height: 0` on the fill slot is\n mandatory: a flex child defaults to min-height:auto and refuses to shrink, so without it the grid\n pushes the page taller instead of scrolling inside itself. */\n.mjc-page--grid { height: 100%; min-height: 0; }\n.mjc-grid-fill { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n\n/* Intro prose. Constrained measure \u2014 text stops being readable much past this \u2014 and it is a real\n block with real spacing, not a bare text node floating between cards. */\n.mjc-page__intro {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n line-height: 1.55;\n margin: 0;\n max-width: 78ch;\n}\n\n/* \u2500\u2500 Panel body helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Our panels are real `<mj-collapsible-panel>`s, so MJ paints the frame, the header and the spacing.\n These classes style only what goes INSIDE one. */\n\n.mjc-body { padding: var(--mj-space-4); }\n.mjc-body--flush { padding: 0; } /* a table fills the panel edge to edge */\n.mjc-body > * + * { margin-top: var(--mj-space-3); } /* nothing ever touches its neighbour */\n\n.mjc-note {\n margin: 0;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n line-height: 1.55;\n}\n\n/* A note under a flush table needs its own padding and a rule above it, or it reads as a table row. */\n.mjc-note--footer {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* \u2500\u2500 Hero (mockup 1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-hero {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4);\n padding: var(--mj-space-4) var(--mj-space-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mjc-hero__identity { display: flex; align-items: center; gap: var(--mj-space-4); min-width: 0; }\n\n.mjc-hero__avatar {\n flex: none;\n width: 52px; height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex; align-items: center; justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xl, 1.375rem);\n}\n\n.mjc-hero__copy { min-width: 0; flex: 1; }\n\n.mjc-hero__title-row {\n display: flex; align-items: center; flex-wrap: wrap;\n gap: var(--mj-space-2) var(--mj-space-3);\n}\n\n.mjc-hero__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n line-height: 1.25;\n /* Long contract descriptions must not push the chips off the card. */\n overflow-wrap: anywhere;\n}\n\n.mjc-hero__meta {\n display: flex; flex-wrap: wrap;\n gap: var(--mj-space-3);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n margin-top: var(--mj-space-2);\n}\n\n/* auto-fit so five stats sit in a row on a wide screen and reflow on a laptop, rather than\n overflowing the card \u2014 which is what a fixed five-column grid did. */\n.mjc-hero__stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));\n gap: var(--mj-space-3);\n}\n\n.mjc-stat {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n min-width: 0;\n}\n.mjc-stat__label {\n display: block; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-stat__value {\n display: block; font-size: var(--mj-text-base); font-weight: 700; margin-top: 2px;\n overflow-wrap: anywhere;\n}\n.mjc-stat__sub { display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted); }\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-chip {\n display: inline-flex; align-items: center; gap: 4px;\n font-size: var(--mj-text-xs); font-weight: 600;\n padding: 2px 9px; border-radius: 999px;\n border: 1px solid transparent; white-space: nowrap;\n}\n.mjc-chip--ok { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); border-color: var(--mj-status-success); }\n.mjc-chip--warn { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); border-color: var(--mj-status-warning); }\n.mjc-chip--error { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); border-color: var(--mj-status-error); }\n.mjc-chip--info { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); border-color: var(--mj-status-info-border); }\n.mjc-chip--muted { background: var(--mj-border-subtle); color: var(--mj-text-secondary); border-color: var(--mj-border-default); }\n\n/* \u2500\u2500 Buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-btn {\n display: inline-flex; align-items: center; gap: 6px;\n font-size: var(--mj-text-sm); font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n.mjc-btn:disabled { opacity: .5; cursor: default; }\n.mjc-btn--primary { background: var(--mj-brand-primary); border-color: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mjc-btn--flat { background: transparent; border-color: transparent; color: var(--mj-brand-primary); }\n.mjc-btn--sm { padding: 3px 9px; font-size: var(--mj-text-xs); }\n.mjc-btn--danger { color: var(--mj-status-error-text); border-color: transparent; background: transparent; }\n\n/* \u2500\u2500 Field grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-fields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-field > label {\n display: block; font-size: var(--mj-text-xs); color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: .04em; margin-bottom: 3px;\n}\n.mjc-field .mjc-val {\n padding: 6px 9px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n min-height: 31px;\n overflow-wrap: anywhere;\n}\n.mjc-field .mjc-val--ro { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.mjc-hint { color: var(--mj-text-muted); font-size: var(--mj-text-xs); margin-top: 3px; }\n\n/* \u2500\u2500 Tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The mockup renders modifications, documents and lineage as TABLES, not stacked cards. With three\n or more rows a table is scannable and a stack is a wall. */\n\ntable.mjc-grid { width: 100%; border-collapse: collapse; }\ntable.mjc-grid th {\n text-align: left; font-size: var(--mj-text-xs);\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700;\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1.5px solid var(--mj-border-default);\n}\ntable.mjc-grid td {\n padding: var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-subtle);\n vertical-align: top;\n}\ntable.mjc-grid tr:last-child td { border-bottom: 0; }\ntable.mjc-grid tbody tr:hover td { background: var(--mj-bg-surface-sunken); }\n.mjc-row--click { cursor: pointer; }\n\n.mjc-muted { color: var(--mj-text-muted); }\n.mjc-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 The clause pair (mockups 1 and 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The standard clause and what this contract says instead, read side by side. This is the app's\n central idea rendered, so it gets real styling rather than two paragraphs. */\n\n.mjc-pair {\n display: grid; grid-template-columns: 1fr; gap: var(--mj-space-3);\n margin-top: var(--mj-space-2);\n}\n/* Side by side only when there is room \u2014 two 40ch columns on a laptop is worse than one readable one. */\n@media (min-width: 1100px) { .mjc-pair { grid-template-columns: 1fr 1fr; } }\n\n.mjc-pair__tag {\n display: block; font-size: var(--mj-text-xs); font-weight: 700;\n text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.mjc-pair__tag--mod { color: var(--mj-status-warning-text); }\n\n.mjc-clause {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-left: 2px solid var(--mj-border-strong);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n margin: 0;\n /* Clause text carries its own line breaks, and 9.1 is a single 1,100-character sentence in caps \u2014\n both must wrap inside the box rather than escaping it. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.mjc-clause--mod {\n border-left-color: var(--mj-status-warning);\n background: var(--mj-status-warning-bg);\n color: var(--mj-text-primary);\n}\n\n.mjc-toggle {\n font-size: var(--mj-text-xs); color: var(--mj-brand-primary);\n font-weight: 600; margin-top: 4px; background: none; border: 0; padding: 0; cursor: pointer;\n}\n\n/* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-flag {\n background: var(--mj-status-warning-bg);\n border-left: 3px solid var(--mj-status-warning);\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-xs);\n color: var(--mj-status-warning-text);\n border-radius: 0 var(--mj-radius-sm) var(--mj-radius-sm) 0;\n line-height: 1.55;\n}\n\n/* \u2500\u2500 Invalid input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* A required field the user has emptied. Border + ring only \u2014 no background change, because these\n are prose textareas and tinting the reading surface makes the text itself harder to read, which\n is the opposite of helpful when the point is \"write something here\". Tokens only, per the\n design-token gate. */\n.mjc-invalid {\n border-color: var(--mj-status-error) !important;\n box-shadow: 0 0 0 2px var(--mj-status-error-bg);\n outline: none;\n}\n\n/* \u2500\u2500 Filter pills (watchlist) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-pills { display: flex; flex-wrap: wrap; gap: var(--mj-space-2); align-items: center; }\n\n.mjc-pill {\n appearance: none; cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-radius: 999px;\n padding: 3px var(--mj-space-3);\n font-size: var(--mj-text-sm);\n line-height: 1.6;\n display: inline-flex; align-items: center; gap: var(--mj-space-2);\n}\n.mjc-pill:hover { border-color: var(--mj-brand-primary); color: var(--mj-text-primary); }\n.mjc-pill:disabled { opacity: .5; cursor: default; }\n.mjc-pill--active {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-brand-primary);\n color: var(--mj-status-info-text);\n font-weight: 700;\n}\n.mjc-pill__count { font-variant-numeric: tabular-nums; opacity: .85; font-size: var(--mj-text-xs); }\n\n/* \u2500\u2500 Dashboard command center \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mjc-kpis {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));\n gap: var(--mj-space-3);\n}\n.mjc-kpi {\n appearance: none;\n font: inherit;\n text-align: left;\n color: inherit;\n cursor: pointer;\n padding: var(--mj-space-3) var(--mj-space-4);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n}\n.mjc-kpi:hover { border-color: var(--mj-brand-primary); }\n.mjc-kpi:disabled { opacity: .6; cursor: default; }\n.mjc-kpi--alert .mjc-kpi__v { color: var(--mj-status-error-text); }\n.mjc-kpi__l {\n font-size: var(--mj-text-xs);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: .04em;\n color: var(--mj-text-muted);\n}\n.mjc-kpi__v {\n font-size: var(--mj-text-xl, 1.35rem);\n font-weight: 700;\n margin: 4px 0 2px;\n font-variant-numeric: tabular-nums;\n}\n.mjc-kpi__f {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n line-height: 1.35;\n}\n\n.mjc-dash-split {\n display: grid;\n grid-template-columns: 1.15fr .85fr;\n gap: var(--mj-space-3);\n}\n@media (max-width: 900px) { .mjc-dash-split { grid-template-columns: 1fr; } }\n\n.mjc-dash-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n}\n.mjc-dash-card__h {\n display: flex;\n justify-content: space-between;\n gap: var(--mj-space-2);\n align-items: baseline;\n padding: var(--mj-space-3) var(--mj-space-4);\n border-bottom: 1px solid var(--mj-border-subtle);\n font-weight: 700;\n}\n.mjc-dash-card__h span {\n font-weight: 500;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.mjc-barlist { display: flex; flex-direction: column; gap: var(--mj-space-2); padding: var(--mj-space-3) var(--mj-space-4); }\n.mjc-barrow {\n display: grid;\n grid-template-columns: 7.5rem 1fr auto;\n gap: var(--mj-space-2);\n align-items: center;\n font-size: var(--mj-text-sm);\n}\n.mjc-track {\n height: 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 99px;\n overflow: hidden;\n}\n.mjc-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 99px;\n}\n.mjc-num { font-variant-numeric: tabular-nums; font-weight: 700; }\n\n.mjc-funnel {\n display: flex;\n gap: var(--mj-space-2);\n align-items: flex-end;\n height: 10rem;\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n.mjc-funnel__col {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n}\n.mjc-funnel__bar {\n width: 100%;\n min-height: 8px;\n border-radius: 8px 8px 2px 2px;\n background: var(--mj-brand-primary);\n}\n.mjc-funnel__n { font-weight: 700; }\n.mjc-funnel__lab {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.mjc-buckets {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: var(--mj-space-2);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n@media (max-width: 700px) { .mjc-buckets { grid-template-columns: 1fr 1fr; } }\n.mjc-bucket {\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: var(--mj-space-3);\n}\n\n.mjc-viewer-host {\n min-height: 420px;\n height: 480px;\n display: flex;\n flex-direction: column;\n}\n.mjc-viewer-host mj-entity-viewer {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 350px;\n width: 100%;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A sentence in a bordered box, never a bare line of text in whitespace. */\n\n.mjc-empty {\n display: flex; align-items: center; gap: var(--mj-space-2); justify-content: center;\n padding: var(--mj-space-6);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n text-align: center;\n}\n"] }]
150
150
  }], null, { Title: [{
151
151
  type: Input
152
152
  }], Icon: [{
@@ -31,10 +31,12 @@ export { MJCSectionBaseComponent, ContractsSectionResource, ContractsTemplatesSe
31
31
  export { MJCSectionShellComponent } from './lib/sections/section-shell.component';
32
32
  export * from './lib/sections/section-nav.model';
33
33
  export * from './lib/data/entity-names';
34
- export { RecordFilesPanelBase, ContractFilesPanel, ContractTemplateFilesPanel } from './lib/form-panels/record-files.panel';
35
34
  export { MJCContractHeroPanel, MJCContractDatesPanel, MJCContractRenewalPanel, MJCContractLineagePanel, } from './lib/form-panels/contract.panels';
36
35
  export { MJCContractSupersedePanel } from './lib/form-panels/supersede.panel';
36
+ export { ContractFormPolicy } from './lib/form-panels/contract-form.policy';
37
+ export { MJCContractOverviewPanel, MJCContractAgreementPanel, MJCContractPartiesPanel, MJCContractNotesPanel, MJCContractProvenanceFieldsPanel, MJCContractLifecyclePanel, MJCContractModificationsPanel, } from './lib/form-panels/contract-form.panels';
37
38
  export { MJCOrganizationAgreementsPanel } from './lib/form-panels/organization.panels';
39
+ export { MJCPersonAgreementsPanel } from './lib/form-panels/person.panels';
38
40
  export * from './lib/pages/contract-grid.page';
39
41
  export { MJCModificationsPageComponent } from './lib/pages/modifications.page';
40
42
  export { MJCContractsDashboardPageComponent } from './lib/pages/contracts-dashboard.page';
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,iCAAiC,CAAC;AACzC,OAAO,wCAAwC,CAAC;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,+FAA+F,CAAC;AACxJ,OAAO,EAAE,+CAA+C,EAAE,MAAM,+GAA+G,CAAC;AAChL,OAAO,EAAE,2DAA2D,EAAE,MAAM,uIAAuI,CAAC;AACpN,OAAO,EAAE,wDAAwD,EAAE,MAAM,iIAAiI,CAAC;AAC3M,OAAO,EAAE,mDAAmD,EAAE,MAAM,uHAAuH,CAAC;AAC5L,OAAO,EAAE,2CAA2C,EAAE,MAAM,uGAAuG,CAAC;AAapK,OAAO,EACH,uBAAuB,EACvB,wBAAwB,EACxB,iCAAiC,EACjC,qCAAqC,GACxC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AAiBxC,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5H,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AAuBvF,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,iCAAiC,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC9G,OAAO,EACH,6BAA6B,EAC7B,6BAA6B,GAChC,MAAM,gCAAgC,CAAC;AAExC,wBAAgB,4BAA4B,IAAI,IAAI,CAqBnD"}
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,iCAAiC,CAAC;AACzC,OAAO,wCAAwC,CAAC;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,+FAA+F,CAAC;AACxJ,OAAO,EAAE,+CAA+C,EAAE,MAAM,+GAA+G,CAAC;AAChL,OAAO,EAAE,2DAA2D,EAAE,MAAM,uIAAuI,CAAC;AACpN,OAAO,EAAE,wDAAwD,EAAE,MAAM,iIAAiI,CAAC;AAC3M,OAAO,EAAE,mDAAmD,EAAE,MAAM,uHAAuH,CAAC;AAC5L,OAAO,EAAE,2CAA2C,EAAE,MAAM,uGAAuG,CAAC;AAapK,OAAO,EACH,uBAAuB,EACvB,wBAAwB,EACxB,iCAAiC,EACjC,qCAAqC,GACxC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AA2BxC,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACH,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,gCAAgC,EAChC,yBAAyB,EACzB,6BAA6B,GAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAuB3E,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,iCAAiC,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC9G,OAAO,EACH,6BAA6B,EAC7B,6BAA6B,GAChC,MAAM,gCAAgC,CAAC;AAExC,wBAAgB,4BAA4B,IAAI,IAAI,CA4BnD"}
@@ -49,14 +49,18 @@ export * from './lib/data/entity-names';
49
49
  * them. Every one of these mounts itself: the slot host discovers registrations, so nothing here is
50
50
  * referenced by a template. That is exactly why the anchors at the bottom are load-bearing.
51
51
  * ========================================================================== */
52
- import { ContractFilesPanel, ContractTemplateFilesPanel } from './lib/form-panels/record-files.panel';
53
52
  import { MJCContractDatesPanel, MJCContractHeroPanel, MJCContractLineagePanel, MJCContractRenewalPanel, } from './lib/form-panels/contract.panels';
54
53
  import { MJCContractSupersedePanel } from './lib/form-panels/supersede.panel';
54
+ import { ContractFormPolicy } from './lib/form-panels/contract-form.policy';
55
+ import { MJCContractAgreementPanel, MJCContractLifecyclePanel, MJCContractModificationsPanel, MJCContractNotesPanel, MJCContractOverviewPanel, MJCContractPartiesPanel, MJCContractProvenanceFieldsPanel, } from './lib/form-panels/contract-form.panels';
55
56
  import { MJCOrganizationAgreementsPanel } from './lib/form-panels/organization.panels';
56
- export { RecordFilesPanelBase, ContractFilesPanel, ContractTemplateFilesPanel } from './lib/form-panels/record-files.panel';
57
+ import { MJCPersonAgreementsPanel } from './lib/form-panels/person.panels';
57
58
  export { MJCContractHeroPanel, MJCContractDatesPanel, MJCContractRenewalPanel, MJCContractLineagePanel, } from './lib/form-panels/contract.panels';
58
59
  export { MJCContractSupersedePanel } from './lib/form-panels/supersede.panel';
60
+ export { ContractFormPolicy } from './lib/form-panels/contract-form.policy';
61
+ export { MJCContractOverviewPanel, MJCContractAgreementPanel, MJCContractPartiesPanel, MJCContractNotesPanel, MJCContractProvenanceFieldsPanel, MJCContractLifecyclePanel, MJCContractModificationsPanel, } from './lib/form-panels/contract-form.panels';
59
62
  export { MJCOrganizationAgreementsPanel } from './lib/form-panels/organization.panels';
63
+ export { MJCPersonAgreementsPanel } from './lib/form-panels/person.panels';
60
64
  /* ============================================================================
61
65
  * THE ONE SHARED CUSTOM COMPONENT (D-22) — the modification editor, rendered inline by the contract's
62
66
  * Modifications panel. It is NOT a form replacement: the modification's own form is the GENERATED one.
@@ -93,13 +97,20 @@ export function LoadMjBizappsContractsClient() {
93
97
  void ContractsTemplatesSectionResource;
94
98
  void ContractsConfigurationSectionResource;
95
99
  // Panels — none of these is referenced by any template, so they exist only because of this.
96
- void ContractFilesPanel;
97
- void ContractTemplateFilesPanel;
98
100
  void MJCContractHeroPanel;
101
+ void ContractFormPolicy;
102
+ void MJCContractOverviewPanel;
103
+ void MJCContractAgreementPanel;
104
+ void MJCContractPartiesPanel;
105
+ void MJCContractNotesPanel;
106
+ void MJCContractProvenanceFieldsPanel;
107
+ void MJCContractLifecyclePanel;
108
+ void MJCContractModificationsPanel;
99
109
  void MJCContractDatesPanel;
100
110
  void MJCContractRenewalPanel;
101
111
  void MJCContractLineagePanel;
102
112
  void MJCContractSupersedePanel;
103
113
  void MJCOrganizationAgreementsPanel;
114
+ void MJCPersonAgreementsPanel;
104
115
  }
105
116
  //# sourceMappingURL=public-api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;gFAIgF;AAChF,OAAO,iCAAiC,CAAC;AACzC,OAAO,wCAAwC,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,+FAA+F,CAAC;AACxJ,OAAO,EAAE,+CAA+C,EAAE,MAAM,+GAA+G,CAAC;AAChL,OAAO,EAAE,2DAA2D,EAAE,MAAM,uIAAuI,CAAC;AACpN,OAAO,EAAE,wDAAwD,EAAE,MAAM,iIAAiI,CAAC;AAC3M,OAAO,EAAE,mDAAmD,EAAE,MAAM,uHAAuH,CAAC;AAC5L,OAAO,EAAE,2CAA2C,EAAE,MAAM,uGAAuG,CAAC;AAEpK;;;;;gFAKgF;AAChF,OAAO,EACH,qCAAqC,EACrC,wBAAwB,EACxB,iCAAiC,GACpC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACH,uBAAuB,EACvB,wBAAwB,EACxB,iCAAiC,EACjC,qCAAqC,GACxC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AAExC;;;;gFAIgF;AAChF,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AACtG,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5H,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AAEvF;;;;;;;;;;;;;;;;;gFAiBgF;AAEhF;kEACkE;AAClE,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,iCAAiC,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC9G,OAAO,EACH,6BAA6B,EAC7B,6BAA6B,GAChC,MAAM,gCAAgC,CAAC;AAExC,MAAM,UAAU,4BAA4B;IACxC,qFAAqF;IACrF,oGAAoG;IACpG,kGAAkG;IAClG,6FAA6F;IAC7F,KAAK,oBAAoB,CAAC;IAE1B,gCAAgC;IAChC,KAAK,wBAAwB,CAAC;IAC9B,KAAK,iCAAiC,CAAC;IACvC,KAAK,qCAAqC,CAAC;IAE3C,4FAA4F;IAC5F,KAAK,kBAAkB,CAAC;IACxB,KAAK,0BAA0B,CAAC;IAChC,KAAK,oBAAoB,CAAC;IAC1B,KAAK,qBAAqB,CAAC;IAC3B,KAAK,uBAAuB,CAAC;IAC7B,KAAK,uBAAuB,CAAC;IAC7B,KAAK,yBAAyB,CAAC;IAC/B,KAAK,8BAA8B,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;gFAIgF;AAChF,OAAO,iCAAiC,CAAC;AACzC,OAAO,wCAAwC,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,+FAA+F,CAAC;AACxJ,OAAO,EAAE,+CAA+C,EAAE,MAAM,+GAA+G,CAAC;AAChL,OAAO,EAAE,2DAA2D,EAAE,MAAM,uIAAuI,CAAC;AACpN,OAAO,EAAE,wDAAwD,EAAE,MAAM,iIAAiI,CAAC;AAC3M,OAAO,EAAE,mDAAmD,EAAE,MAAM,uHAAuH,CAAC;AAC5L,OAAO,EAAE,2CAA2C,EAAE,MAAM,uGAAuG,CAAC;AAEpK;;;;;gFAKgF;AAChF,OAAO,EACH,qCAAqC,EACrC,wBAAwB,EACxB,iCAAiC,GACpC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACH,uBAAuB,EACvB,wBAAwB,EACxB,iCAAiC,EACjC,qCAAqC,GACxC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AAExC;;;;gFAIgF;AAChF,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACH,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,gCAAgC,GACnC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACH,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,gCAAgC,EAChC,yBAAyB,EACzB,6BAA6B,GAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E;;;;;;;;;;;;;;;;;gFAiBgF;AAEhF;kEACkE;AAClE,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,iCAAiC,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC9G,OAAO,EACH,6BAA6B,EAC7B,6BAA6B,GAChC,MAAM,gCAAgC,CAAC;AAExC,MAAM,UAAU,4BAA4B;IACxC,qFAAqF;IACrF,oGAAoG;IACpG,kGAAkG;IAClG,6FAA6F;IAC7F,KAAK,oBAAoB,CAAC;IAE1B,gCAAgC;IAChC,KAAK,wBAAwB,CAAC;IAC9B,KAAK,iCAAiC,CAAC;IACvC,KAAK,qCAAqC,CAAC;IAE3C,4FAA4F;IAC5F,KAAK,oBAAoB,CAAC;IAC1B,KAAK,kBAAkB,CAAC;IACxB,KAAK,wBAAwB,CAAC;IAC9B,KAAK,yBAAyB,CAAC;IAC/B,KAAK,uBAAuB,CAAC;IAC7B,KAAK,qBAAqB,CAAC;IAC3B,KAAK,gCAAgC,CAAC;IACtC,KAAK,yBAAyB,CAAC;IAC/B,KAAK,6BAA6B,CAAC;IACnC,KAAK,qBAAqB,CAAC;IAC3B,KAAK,uBAAuB,CAAC;IAC7B,KAAK,uBAAuB,CAAC;IAC7B,KAAK,yBAAyB,CAAC;IAC/B,KAAK,8BAA8B,CAAC;IACpC,KAAK,wBAAwB,CAAC;AAClC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mjdevManaged": "MJDEV-MANAGED: mjdev owns parts of this file — the \"packages/dev-apps/*\" workspaces glob, any dev-linked open-app dependencies (e.g. \"@mj-biz-apps/*\"), and the Angular \"overrides\" pin set. Do not hand-edit those; the tool wires and reverts them. They are left visible in git status, but the git-tree guard blocks committing them. See .mjdev-docs/MANAGED-FILES.md; revert with `mjdev git:stage-clean <slug> package.json`.",
3
3
  "name": "@mj-biz-apps/contracts-ng",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "type": "module",
6
6
  "description": "Client bootstrap package - Angular components loaded by MJExplorer via the generated open-app bootstrap import. TODO(template): rename.",
7
7
  "main": "dist/public-api.js",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "license": "BUSL-1.1",
14
14
  "dependencies": {
15
- "@mj-biz-apps/contracts-entities": "^0.2.0"
15
+ "@mj-biz-apps/contracts-entities": "^0.3.0"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "@angular/common": ">=21.0.0 <22.0.0",
@@ -24,7 +24,6 @@
24
24
  "@memberjunction/graphql-dataprovider": "^6.1.0-edge.4",
25
25
  "@memberjunction/ng-base-forms": "^6.1.0-edge.4",
26
26
  "@memberjunction/ng-entity-viewer": "^6.1.0-edge.4",
27
- "@memberjunction/ng-file-storage": "^6.1.0-edge.4",
28
27
  "@memberjunction/ng-hierarchy-tree": "^6.1.0-edge.4",
29
28
  "@memberjunction/ng-link-directives": "^6.1.0-edge.4",
30
29
  "@memberjunction/ng-shared": "^6.1.0-edge.4",
@@ -1,151 +0,0 @@
1
- /**
2
- * @fileoverview `Documents` — the record-scoped file panel MJ does not have yet.
3
- *
4
- * CARRIED FORWARD FROM V1 (plan §6.5). The rebuild deleted every other hand-written component in
5
- * this package; this one survived because the gap it fills is MJ's, not v1's, and it never knew
6
- * anything about the billing schema. Only its registrations changed — see the bottom of the file.
7
- *
8
- * THE GAP THIS FILLS. MJ models record↔file linking properly: `__mj.FileEntityRecordLink` is a
9
- * polymorphic `EntityID` + `RecordID` pair, so any record can carry any number of files. What it
10
- * does NOT ship is a way to SEE them on a record. `@memberjunction/ng-file-storage` has
11
- * `mj-file-browser`, `mj-files-grid` and `mj-files-file-upload`, but all three are **category**
12
- * scoped; nothing in the MJ Angular tree queries `FileEntityRecordLink` at runtime (the only
13
- * references are the generated CRUD forms for the link entity itself). So "the files on THIS
14
- * record" had no UI at all.
15
- *
16
- * WHY IT IS A PANEL AND NOT A TAB. `BaseFormPanel` is MJ's own extension point: a panel registers
17
- * for an entity + slot and the form mounts it automatically, with no edit to the form and nothing
18
- * for CodeGen to overwrite. That means this panel works identically on every GENERATED form it
19
- * registers for — and it keeps working when they are regenerated, which is the whole reason v2
20
- * stopped replacing forms and started contributing panels to them (plan §6.4).
21
- *
22
- * BUILT DONATION-SHAPED, ON PURPOSE. Nothing below knows what a contract is. The logic reads
23
- * `Record.EntityInfo.ID` and `Record.PrimaryKey`, so it is already entity-agnostic — the only
24
- * contracts-specific thing in the file is *which entities it registers for*, isolated into the
25
- * one-line subclasses at the bottom. To donate this to MJ base, move the base class and
26
- * re-register it once with `entity: '*'` (PANELS.md's wildcard); the only new requirement then is
27
- * self-hiding on forms that have no files, which `HasFiles` already answers.
28
- *
29
- * WHY NOT WILDCARD HERE AND NOW: a wildcard panel must render nothing on the ~99% of forms it does
30
- * not apply to, but a panel that hides when empty can never accept the FIRST file. Registering
31
- * explicitly for the two entities that carry paper keeps the attach affordance available while
32
- * staying honest about clutter. That tension is the real design question to settle before donating.
33
- *
34
- * @module @mj-biz-apps/contracts-ng
35
- */
36
- import { OnInit } from '@angular/core';
37
- import { BaseFormPanel } from '@memberjunction/ng-base-forms';
38
- import * as i0 from "@angular/core";
39
- /** One linked file, flattened from the link + the file it points at. */
40
- interface LinkedFile {
41
- LinkID: string;
42
- FileID: string;
43
- Name: string;
44
- Provider: string | null;
45
- Status: string | null;
46
- CreatedAt: string | null;
47
- /** The path/key inside the provider — what a pre-auth download URL is minted from. */
48
- ProviderKey: string | null;
49
- /** The storage ACCOUNT, which is what the download API takes (not the provider type). */
50
- AccountID: string | null;
51
- }
52
- /**
53
- * All of the behaviour. Deliberately knows nothing about contracts — see the file header.
54
- */
55
- export declare class RecordFilesPanelBase extends BaseFormPanel implements OnInit {
56
- private readonly cdr;
57
- private readonly fileOpen;
58
- Files: LinkedFile[];
59
- IsLoading: boolean;
60
- /** The storage account every action runs against, or null when the instance has none. */
61
- DefaultAccountID: string | null;
62
- /** Path typed into the register box. */
63
- RegisterPath: string;
64
- /** True while an action is in flight, so the buttons cannot be double-fired. */
65
- Busy: boolean;
66
- /** The last action failure, shown in the panel rather than a toast that scrolls away. */
67
- ActionError: string | null;
68
- /**
69
- * Whether this user may DOWNLOAD, as opposed to merely see that documents exist (D-9).
70
- *
71
- * ⚠ THE OBVIOUS IMPLEMENTATION IS VACUOUS, and this was written that way first. Reading the HOST
72
- * RECORD's `CanRead` asks "may they see this contract" — but everyone looking at the panel can
73
- * already see the contract, so the gate returns true for every viewer and the restriction can
74
- * never bind. D-9 exists precisely to separate two populations (leadership/finance/legal may
75
- * download; everyone else sees the record), and gating on record visibility collapses them into
76
- * one. Caught on review of PR #9.
77
- *
78
- * So the gate is the **`MJ: Files` entity's** read permission — a surface genuinely DISTINCT from
79
- * record visibility. An administrator grants Files read to the three D-9 roles and to nobody else,
80
- * and the check never mentions contracts, so the panel stays entity-agnostic for donation to MJ.
81
- *
82
- * `GetUserPermisions` is the platform's own allow/deny aggregation across the user's roles, so this
83
- * cannot drift from what the instance actually grants. FALSE on any doubt: a hidden Open button is
84
- * a nuisance, a leaked executed contract is not.
85
- */
86
- get CanDownload(): boolean;
87
- /**
88
- * The signing provider's own URL, when the host record carries one — the always-works fallback.
89
- *
90
- * Read generically (`SigningProviderURL`) rather than by typing this panel to ContractEntity,
91
- * because the panel is deliberately entity-agnostic and intended for donation to MJ. A host entity
92
- * without the field simply has no fallback link.
93
- */
94
- get SigningProviderURL(): string | null;
95
- get HasFiles(): boolean;
96
- ngOnInit(): Promise<void>;
97
- /**
98
- * Two reads: the links for this record, then the files they name. It is deliberately two rather
99
- * than one join — `RunView` is the app's only sanctioned read path (§11.1), and the second read
100
- * is skipped entirely when a record has no links, which is the common case.
101
- */
102
- private load;
103
- /**
104
- * Resolve the instance's storage account once.
105
- *
106
- * A `File` row names a PROVIDER (the type — "SharePoint"); the download and upload APIs take an
107
- * ACCOUNT (a configured instance of one). Nothing on the link or the file gives us the account, so
108
- * it is looked up here. When there is none, every affordance that needs storage is HIDDEN rather
109
- * than shown-and-failing: an Open button that always errors is worse than no button.
110
- */
111
- private resolveAccount;
112
- /**
113
- * REGISTER an object that is already in storage (§6.5) — the flow this app actually needs.
114
- *
115
- * MJ's own `CreateFile` mutation assumes an UPLOAD: it creates the row `Pending` and hands back a
116
- * pre-auth URL for the browser to push bytes to. Our executed PDFs are already in SharePoint,
117
- * delivered by PandaDoc → HubSpot → SharePoint, a route MJ knows nothing about. So there is nothing
118
- * to upload — the work is to create the `MJ: Files` row with the right `ProviderKey` and link it.
119
- *
120
- * Done entirely through the ENTITY layer, no GraphQL: two saves, and the second is skipped if the
121
- * first fails, so a half-registered document (a file row nothing points at) cannot result. It
122
- * verifies the object EXISTS first — registering a path that is not there produces a record that
123
- * lies, and a document nobody can open is exactly what this panel exists to prevent.
124
- */
125
- RegisterExisting(): Promise<void>;
126
- /** The provider (type) behind the resolved account — a File row references the provider, not the account. */
127
- private resolveProviderID;
128
- /**
129
- * Open a document via a time-limited pre-auth URL.
130
- *
131
- * Delegated to MJ's own `FileOpenService`, which mints the URL over GraphQL and is provider-agnostic
132
- * — the same call opens a SharePoint object, an S3 object or a Box object. Its `Provider` is set from
133
- * the host form's (D-25), which the service's own docs prescribe for multi-provider clients.
134
- *
135
- * The URL is pre-authenticated and time-limited, so the bytes never proxy through MJAPI and the link
136
- * cannot be shared indefinitely.
137
- */
138
- Open(f: LinkedFile): Promise<void>;
139
- static ɵfac: i0.ɵɵFactoryDeclaration<RecordFilesPanelBase, never>;
140
- static ɵcmp: i0.ɵɵComponentDeclaration<RecordFilesPanelBase, "mjc-record-files-panel", never, {}, {}, never, never, true, never>;
141
- }
142
- export declare class ContractFilesPanel extends RecordFilesPanelBase {
143
- static ɵfac: i0.ɵɵFactoryDeclaration<ContractFilesPanel, never>;
144
- static ɵcmp: i0.ɵɵComponentDeclaration<ContractFilesPanel, "mjc-contract-files-panel", never, {}, {}, never, never, true, never>;
145
- }
146
- export declare class ContractTemplateFilesPanel extends RecordFilesPanelBase {
147
- static ɵfac: i0.ɵɵFactoryDeclaration<ContractTemplateFilesPanel, never>;
148
- static ɵcmp: i0.ɵɵComponentDeclaration<ContractTemplateFilesPanel, "mjc-template-files-panel", never, {}, {}, never, never, true, never>;
149
- }
150
- export {};
151
- //# sourceMappingURL=record-files.panel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"record-files.panel.d.ts","sourceRoot":"","sources":["../../../src/lib/form-panels/record-files.panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAgC,MAAM,EAAU,MAAM,eAAe,CAAC;AAI7E,OAAO,EAAE,aAAa,EAAmB,MAAM,+BAA+B,CAAC;;AAM/E,wEAAwE;AACxE,UAAU,UAAU;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,sFAAsF;IACtF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yFAAyF;IACzF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAsHD;;GAEG;AACH,qBAOa,oBAAqB,SAAQ,aAAc,YAAW,MAAM;IACrE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAE7C,KAAK,EAAE,UAAU,EAAE,CAAM;IACzB,SAAS,UAAQ;IAExB,yFAAyF;IAClF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE9C,wCAAwC;IACjC,YAAY,SAAM;IAEzB,gFAAgF;IACzE,IAAI,UAAS;IAEpB,yFAAyF;IAClF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEzC;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAW,WAAW,IAAI,OAAO,CAahC;IAED;;;;;;OAMG;IACH,IAAW,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAO7C;IAED,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAEY,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtC;;;;OAIG;YACW,IAAI;IAgFlB;;;;;;;OAOG;YACW,cAAc;IAgB5B;;;;;;;;;;;;OAYG;IACU,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgE9C,6GAA6G;YAC/F,iBAAiB;IAe/B;;;;;;;;;OASG;IACU,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;yCAlStC,oBAAoB;2CAApB,oBAAoB;CAoThC;AAQD,qBAuBa,kBAAmB,SAAQ,oBAAoB;yCAA/C,kBAAkB;2CAAlB,kBAAkB;CAAgC;AAE/D,qBA6Ba,0BAA2B,SAAQ,oBAAoB;yCAAvD,0BAA0B;2CAA1B,0BAA0B;CAAgC"}