@rubytech/create-maxy-code 0.1.60 → 0.1.62

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 (163) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  3. package/payload/platform/plugins/brochures/skills/property-brochure/SKILL.md +26 -3
  4. package/payload/platform/plugins/brochures/skills/property-brochure/references/registers.md +1 -1
  5. package/payload/platform/plugins/docs/references/admin-session.md +2 -2
  6. package/payload/platform/plugins/docs/references/internals.md +1 -1
  7. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  8. package/payload/platform/plugins/epc/.claude-plugin/plugin.json +17 -0
  9. package/payload/platform/plugins/epc/PLUGIN.md +85 -0
  10. package/payload/platform/plugins/epc/mcp/dist/index.d.ts +2 -0
  11. package/payload/platform/plugins/epc/mcp/dist/index.d.ts.map +1 -0
  12. package/payload/platform/plugins/epc/mcp/dist/index.js +117 -0
  13. package/payload/platform/plugins/epc/mcp/dist/index.js.map +1 -0
  14. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.d.ts +3 -0
  15. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.d.ts.map +1 -0
  16. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.js +72 -0
  17. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.js.map +1 -0
  18. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.d.ts +60 -0
  19. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.d.ts.map +1 -0
  20. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.js +181 -0
  21. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.js.map +1 -0
  22. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.d.ts +3 -0
  23. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.d.ts.map +1 -0
  24. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.js +49 -0
  25. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.js.map +1 -0
  26. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.d.ts +15 -0
  27. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.d.ts.map +1 -0
  28. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.js +130 -0
  29. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.js.map +1 -0
  30. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.d.ts +5 -0
  31. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.d.ts.map +1 -0
  32. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.js +38 -0
  33. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.js.map +1 -0
  34. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.d.ts +4 -0
  35. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  36. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.js +9 -0
  37. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.js.map +1 -0
  38. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.d.ts +4 -0
  39. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.d.ts.map +1 -0
  40. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.js +10 -0
  41. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.js.map +1 -0
  42. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.d.ts +5 -0
  43. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.d.ts.map +1 -0
  44. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.js +36 -0
  45. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.js.map +1 -0
  46. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.d.ts +10 -0
  47. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.d.ts.map +1 -0
  48. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.js +30 -0
  49. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.js.map +1 -0
  50. package/payload/platform/plugins/epc/mcp/package-lock.json +2566 -0
  51. package/payload/platform/plugins/epc/mcp/package.json +21 -0
  52. package/payload/platform/plugins/epc/mcp/src/__tests__/epc-api.test.ts +251 -0
  53. package/payload/platform/plugins/epc/mcp/src/__tests__/key-roundtrip.test.ts +113 -0
  54. package/payload/platform/plugins/epc/mcp/src/__tests__/lookup.test.ts +181 -0
  55. package/payload/platform/plugins/epc/mcp/src/__tests__/schema-parity.test.ts +54 -0
  56. package/payload/platform/plugins/epc/mcp/src/index.ts +156 -0
  57. package/payload/platform/plugins/epc/mcp/src/lib/crypto.ts +79 -0
  58. package/payload/platform/plugins/epc/mcp/src/lib/epc-api.ts +241 -0
  59. package/payload/platform/plugins/epc/mcp/src/lib/file-crypto.ts +55 -0
  60. package/payload/platform/plugins/epc/mcp/src/lib/key-store.ts +172 -0
  61. package/payload/platform/plugins/epc/mcp/src/lib/neo4j.ts +47 -0
  62. package/payload/platform/plugins/epc/mcp/src/tools/key-deregister.ts +9 -0
  63. package/payload/platform/plugins/epc/mcp/src/tools/key-list.ts +10 -0
  64. package/payload/platform/plugins/epc/mcp/src/tools/key-register.ts +44 -0
  65. package/payload/platform/plugins/epc/mcp/src/tools/lookup.ts +43 -0
  66. package/payload/platform/plugins/epc/mcp/tsconfig.json +20 -0
  67. package/payload/platform/plugins/epc/mcp/vitest.config.ts +8 -0
  68. package/payload/platform/plugins/preval/.claude-plugin/plugin.json +1 -1
  69. package/payload/platform/plugins/preval/PLUGIN.md +25 -17
  70. package/payload/platform/plugins/preval/skills/property-preval/SKILL.md +107 -39
  71. package/payload/platform/plugins/preval/skills/property-preval/references/render.py +449 -84
  72. package/payload/platform/plugins/preval/skills/property-preval/references/template-inputs.schema.json +126 -80
  73. package/payload/platform/plugins/preval/skills/property-preval/references/template.html +183 -124
  74. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  75. package/payload/platform/services/claude-session-manager/dist/http-server.js +6 -1
  76. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  77. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +7 -0
  78. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  79. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -0
  80. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  81. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  82. package/payload/platform/templates/agents/admin/SOUL.md +1 -1
  83. package/payload/premium-plugins/real-agent/BUNDLE.md +4 -2
  84. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  85. package/payload/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json +5 -0
  86. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/SKILL.md +26 -3
  87. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/references/registers.md +1 -1
  88. package/payload/premium-plugins/real-agent/plugins/epc/.claude-plugin/plugin.json +17 -0
  89. package/payload/premium-plugins/real-agent/plugins/epc/PLUGIN.md +85 -0
  90. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/index.d.ts +2 -0
  91. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/index.d.ts.map +1 -0
  92. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/index.js +117 -0
  93. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/index.js.map +1 -0
  94. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/crypto.d.ts +3 -0
  95. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/crypto.d.ts.map +1 -0
  96. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/crypto.js +72 -0
  97. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/crypto.js.map +1 -0
  98. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/epc-api.d.ts +60 -0
  99. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/epc-api.d.ts.map +1 -0
  100. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/epc-api.js +181 -0
  101. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/epc-api.js.map +1 -0
  102. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/file-crypto.d.ts +3 -0
  103. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/file-crypto.d.ts.map +1 -0
  104. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/file-crypto.js +49 -0
  105. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/file-crypto.js.map +1 -0
  106. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/key-store.d.ts +15 -0
  107. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/key-store.d.ts.map +1 -0
  108. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/key-store.js +130 -0
  109. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/key-store.js.map +1 -0
  110. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/neo4j.d.ts +5 -0
  111. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/neo4j.d.ts.map +1 -0
  112. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/neo4j.js +38 -0
  113. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/lib/neo4j.js.map +1 -0
  114. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-deregister.d.ts +4 -0
  115. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  116. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-deregister.js +9 -0
  117. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-deregister.js.map +1 -0
  118. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-list.d.ts +4 -0
  119. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-list.d.ts.map +1 -0
  120. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-list.js +10 -0
  121. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-list.js.map +1 -0
  122. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-register.d.ts +5 -0
  123. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-register.d.ts.map +1 -0
  124. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-register.js +36 -0
  125. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/key-register.js.map +1 -0
  126. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/lookup.d.ts +10 -0
  127. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/lookup.d.ts.map +1 -0
  128. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/lookup.js +30 -0
  129. package/payload/premium-plugins/real-agent/plugins/epc/mcp/dist/tools/lookup.js.map +1 -0
  130. package/payload/premium-plugins/real-agent/plugins/epc/mcp/package-lock.json +2566 -0
  131. package/payload/premium-plugins/real-agent/plugins/epc/mcp/package.json +21 -0
  132. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/epc-api.test.ts +251 -0
  133. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/key-roundtrip.test.ts +113 -0
  134. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/lookup.test.ts +181 -0
  135. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/schema-parity.test.ts +54 -0
  136. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/index.ts +156 -0
  137. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/crypto.ts +79 -0
  138. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/epc-api.ts +241 -0
  139. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/file-crypto.ts +55 -0
  140. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/key-store.ts +172 -0
  141. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/neo4j.ts +47 -0
  142. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-deregister.ts +9 -0
  143. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-list.ts +10 -0
  144. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-register.ts +44 -0
  145. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/lookup.ts +43 -0
  146. package/payload/premium-plugins/real-agent/plugins/epc/mcp/tsconfig.json +20 -0
  147. package/payload/premium-plugins/real-agent/plugins/epc/mcp/vitest.config.ts +8 -0
  148. package/payload/premium-plugins/real-agent/plugins/preval/.claude-plugin/plugin.json +1 -1
  149. package/payload/premium-plugins/real-agent/plugins/preval/PLUGIN.md +25 -17
  150. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/SKILL.md +107 -39
  151. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/render.py +449 -84
  152. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/template-inputs.schema.json +126 -80
  153. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/template.html +183 -124
  154. package/payload/server/public/assets/{admin-Bp-BjBCX.js → admin-DhN3G8W7.js} +1 -1
  155. package/payload/server/public/assets/{data-BGUAGVkV.js → data-B2ZVXOcE.js} +1 -1
  156. package/payload/server/public/assets/{graph-MvYxZOBF.js → graph-BAMGPHrK.js} +1 -1
  157. package/payload/server/public/assets/{graph-labels-D865qb3K.js → graph-labels-D9eBbvxo.js} +1 -1
  158. package/payload/server/public/assets/{page-C2b1nlOc.js → page-CV27Al6Z.js} +1 -1
  159. package/payload/server/public/assets/{page--hOVRrgN.js → page-DjdVMWCz.js} +1 -1
  160. package/payload/server/public/data.html +3 -3
  161. package/payload/server/public/graph.html +3 -3
  162. package/payload/server/public/index.html +4 -4
  163. package/payload/server/server.js +3 -16
@@ -2,22 +2,22 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Pre-valuation · <!-- REPLACE: address --> · <!-- REPLACE: generated --></title>
5
+ <title>Pre-valuation · <!-- REPLACE: address --> · <!-- REPLACE: generated --> · <!-- REPLACE: brand_name --></title>
6
6
  <meta name="viewport" content="width=device-width,initial-scale=1">
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500;1,600&family=Lora:ital,wght@0,400;0,500;0,600;1,400&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
10
10
  <style>
11
11
  :root{
12
- --teal-900:#064444;
13
- --teal-950:#042D2D;
14
- --gold-500:#B8945F;
12
+ --teal-900:<!-- REPLACE: brand_primary -->;
13
+ --teal-950:<!-- REPLACE: brand_primary_dark -->;
14
+ --gold-500:<!-- REPLACE: brand_accent -->;
15
15
  --paper-0:#FFFFFF;
16
- --paper-25:#FAF7F2;
16
+ --paper-25:<!-- REPLACE: brand_paper -->;
17
17
  --paper-50:#FBF8F8;
18
- --paper-75:#F2EDE3;
18
+ --paper-75:<!-- REPLACE: brand_paper_banded -->;
19
19
  --slate-500:#56605F; --slate-600:#6E6E6E;
20
- --rule-300:#E3DCCE;
20
+ --rule-300:<!-- REPLACE: brand_rule -->;
21
21
 
22
22
  --text-default:var(--teal-900);
23
23
  --text-muted:var(--slate-600);
@@ -35,218 +35,277 @@
35
35
  }
36
36
  *{box-sizing:border-box;margin:0;padding:0}
37
37
  html,body{background:var(--rule-300);font-family:var(--body);color:var(--text-default);font-weight:400;-webkit-font-smoothing:antialiased}
38
+ a{color:inherit;text-decoration:none}
38
39
  .page{width:210mm;min-height:297mm;height:297mm;margin:8mm auto;background:var(--surface-page);position:relative;overflow:hidden;padding:18mm 16mm;page-break-after:always}
39
40
  .page.dark{background:var(--surface-deep);color:var(--text-on-dark)}
41
+ .page.dark .muted{color:#B7C8C8}
40
42
  @page{size:A4 portrait;margin:0}
41
43
  @media print{html,body{background:transparent} .page{margin:0;box-shadow:none;page-break-after:always}}
42
44
 
43
45
  h1,h2,h3,h4{font-family:var(--display);font-weight:500;line-height:1.15;color:inherit}
44
- h1{font-family:var(--display);font-style:italic;font-weight:400;font-size:38pt;letter-spacing:-.6pt;line-height:1.05}
45
- h2{font-size:24pt;font-style:italic;font-weight:400;margin-bottom:5mm;letter-spacing:-.3pt}
46
+ h1{font-size:48pt;letter-spacing:-1pt;font-style:italic;font-weight:400}
47
+ h2{font-size:26pt;font-style:italic;font-weight:400;margin-bottom:6mm;letter-spacing:-.3pt}
46
48
  h3{font-size:14pt;font-weight:500}
47
49
  h4{font-family:var(--sans);font-size:8.5pt;font-weight:600;letter-spacing:2.2pt;text-transform:uppercase;color:var(--text-accent)}
48
50
  p{font-size:11pt;line-height:1.65;color:inherit;font-family:var(--body)}
49
51
  .muted{color:var(--text-muted);font-size:9.5pt;line-height:1.55;font-family:var(--body)}
50
52
  .eyebrow{font-family:var(--sans);font-weight:600;font-size:9pt;letter-spacing:3pt;text-transform:uppercase;color:var(--text-accent)}
53
+ .dropcap::first-letter{font-family:var(--display);font-weight:400;font-style:italic;font-size:5em;line-height:.82;float:left;margin:.05em .12em -.08em 0;color:var(--teal-900);letter-spacing:-.04em}
51
54
 
52
- .cover-frame{position:absolute;inset:0;padding:24mm 18mm;display:flex;flex-direction:column;justify-content:space-between;z-index:1;background:linear-gradient(180deg,var(--teal-900) 0%,var(--teal-950) 100%);color:var(--text-on-dark)}
53
- .cover-eyebrow{font-family:var(--sans);font-weight:600;font-size:9pt;letter-spacing:3.5pt;text-transform:uppercase;color:var(--gold-500)}
54
- .cover-rule{height:1px;background:var(--gold-500);width:30mm}
55
- .pc-chip{display:inline-flex;align-items:center;padding:2.5mm 6mm;border:1px solid var(--gold-500);border-radius:50px;color:var(--gold-500);font-family:var(--sans);font-weight:600;font-size:10pt;letter-spacing:2.5pt}
56
- .cover-meta{display:grid;grid-template-columns:repeat(3,1fr);gap:8mm;border-top:1px solid rgba(255,255,255,.22);padding-top:8mm}
55
+ /* --- COVER --- */
56
+ .cover-bg{position:absolute;inset:0;background:url(<!-- REPLACE: subject_hero_path -->) center/cover no-repeat}
57
+ .cover-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(6,68,68,.55) 0%,rgba(6,68,68,.78) 55%,rgba(4,45,45,.94) 100%)}
58
+ .cover-frame{position:absolute;inset:0;padding:18mm 16mm;display:flex;flex-direction:column;justify-content:space-between;z-index:1}
59
+ .cover-hero h1{color:var(--text-on-dark);max-width:170mm}
60
+ .cover-hero .lede{color:var(--gold-500);font-family:var(--display);font-style:italic;font-weight:400;font-size:16pt;letter-spacing:.2pt;margin-top:6mm}
61
+ .cover-meta{display:grid;grid-template-columns:repeat(4,1fr);gap:8mm;border-top:1px solid rgba(255,255,255,.22);padding-top:8mm}
57
62
  .cover-meta dt{font-family:var(--sans);font-weight:600;font-size:8pt;letter-spacing:2pt;text-transform:uppercase;color:var(--gold-500);margin-bottom:3mm}
58
63
  .cover-meta dd{font-family:var(--display);font-style:italic;font-weight:500;font-size:14pt;color:var(--text-on-dark)}
64
+ .cover-rule{height:1px;background:var(--gold-500);width:30mm}
65
+ .pc-chip{display:inline-flex;align-items:center;padding:2.5mm 6mm;border:1px solid var(--gold-500);border-radius:50px;color:var(--gold-500);font-family:var(--sans);font-weight:600;font-size:10pt;letter-spacing:2.5pt}
59
66
 
60
- .doc-head{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:6mm;border-bottom:1px solid var(--rule-300);margin-bottom:7mm}
61
- .doc-head .wm{font-family:var(--display);font-style:normal;font-weight:600;font-size:18pt;color:var(--teal-900);letter-spacing:-.4pt}
62
- .doc-head .breadcrumb{font-family:var(--sans);font-weight:500;font-size:8pt;letter-spacing:2pt;text-transform:uppercase;color:var(--text-muted);text-align:right}
67
+ /* --- BODY HEAD/FOOT --- */
68
+ .doc-head{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:6mm;border-bottom:1px solid var(--rule-300);margin-bottom:8mm}
69
+ .doc-head .breadcrumb{font-family:var(--sans);font-weight:500;font-size:8pt;letter-spacing:2pt;text-transform:uppercase;color:var(--text-muted)}
70
+ .doc-foot{position:absolute;bottom:9mm;left:16mm;right:16mm;display:flex;justify-content:space-between;font-family:var(--sans);font-weight:500;font-size:8pt;letter-spacing:1.5pt;text-transform:uppercase;color:var(--text-muted)}
71
+ .page.dark .doc-foot{color:#7FA0A0}
63
72
 
64
- .kpis-4{display:grid;grid-template-columns:repeat(4,1fr);gap:4mm;margin-bottom:6mm}
73
+ /* --- KPI TILES --- */
74
+ .kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:4mm;margin-bottom:6mm}
75
+ .kpis.three{grid-template-columns:repeat(3,1fr)}
76
+ .kpis.cube{grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(2,1fr);gap:4mm;margin-bottom:0;height:100%}
77
+ .kpis.cube .kpi{padding:5mm;display:flex;flex-direction:column;justify-content:space-between}
65
78
  .kpi{background:var(--surface-card);border-radius:var(--radius-lg);padding:5mm;border:1px solid var(--rule-300);position:relative;overflow:hidden}
66
- .kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:1.4mm;background:var(--gold-500)}
79
+ .kpi.subject::before{content:"";position:absolute;left:0;top:0;bottom:0;width:1.4mm;background:var(--gold-500)}
67
80
  .kpi .label{font-family:var(--sans);font-weight:600;font-size:7pt;letter-spacing:1.7pt;text-transform:uppercase;color:var(--text-muted);margin-bottom:2mm}
68
81
  .kpi .value{font-family:var(--display);font-style:italic;font-weight:500;font-size:20pt;color:var(--text-default);line-height:1;letter-spacing:-.3pt}
69
82
  .kpi .sub{font-size:8pt;color:var(--text-muted);margin-top:2mm;font-family:var(--body);font-style:italic}
83
+ .kpi.gold{background:var(--teal-900);color:var(--text-on-dark);border:none}
84
+ .kpi.gold .label{color:var(--gold-500)}
85
+ .kpi.gold .value{color:var(--text-on-dark);font-size:22pt}
86
+ .kpi.gold .sub{color:#B7C8C8}
70
87
 
71
- .two-col{display:grid;grid-template-columns:1fr 1fr;gap:6mm;align-items:start}
88
+ /* --- LAYOUTS --- */
89
+ .two-col{display:grid;grid-template-columns:1.1fr .9fr;gap:8mm;align-items:start}
72
90
  .panel{background:var(--surface-card);border-radius:var(--radius-lg);padding:5.5mm;border:1px solid var(--rule-300)}
73
91
  .panel.banded{background:var(--surface-banded)}
74
92
  .panel h4{margin-bottom:3mm}
75
93
 
94
+ /* --- VALUATION PANEL --- */
95
+ .val-panel{background:var(--surface-banded);border-radius:var(--radius-lg);padding:7mm;border:1px solid var(--rule-300)}
96
+ .val-row{display:grid;grid-template-columns:1fr auto;align-items:baseline;gap:4mm;padding:3mm 0;border-bottom:1px dashed var(--rule-300)}
97
+ .val-row:last-child{border-bottom:none}
98
+ .val-row .lbl{font-family:var(--sans);font-weight:500;font-size:9pt;letter-spacing:.4pt;color:var(--text-default)}
99
+ .val-row .lbl small{display:block;font-family:var(--body);font-style:italic;font-weight:400;color:var(--text-muted);font-size:8pt;letter-spacing:0;text-transform:none;margin-top:.8mm}
100
+ .val-row .num{font-family:var(--display);font-style:italic;font-weight:500;font-size:18pt;color:var(--text-default);letter-spacing:-.3pt}
101
+ .val-row.headline .num{font-size:22pt;color:var(--teal-900)}
102
+ .val-row.adj .num{font-size:14pt;color:var(--text-muted)}
103
+ .val-row.adj .num.pos{color:#2E7D63}
104
+ .val-row.adj .num.neg{color:#B0463E}
105
+ .val-final{margin-top:5mm;padding:5mm 6mm;background:var(--teal-900);color:var(--text-on-dark);border-radius:var(--radius-lg);display:flex;justify-content:space-between;align-items:baseline;gap:4mm}
106
+ .val-final .lbl{font-family:var(--sans);font-weight:600;font-size:8pt;letter-spacing:2pt;text-transform:uppercase;color:var(--gold-500)}
107
+ .val-final .num{font-family:var(--display);font-style:italic;font-weight:500;font-size:26pt;color:var(--text-on-dark);letter-spacing:-.4pt}
108
+
109
+ /* --- TABLES --- */
76
110
  table.cmp{width:100%;border-collapse:collapse;font-size:10pt;font-family:var(--body)}
77
- table.cmp th,table.cmp td{padding:2.2mm 2mm;text-align:left;border-bottom:1px solid var(--rule-300)}
111
+ table.cmp th,table.cmp td{padding:2.4mm 2mm;text-align:left;border-bottom:1px solid var(--rule-300)}
78
112
  table.cmp th{font-family:var(--sans);font-weight:600;font-size:7.5pt;letter-spacing:1.8pt;text-transform:uppercase;color:var(--text-muted)}
79
- table.cmp td.num{font-family:var(--display);font-style:italic;font-weight:500;text-align:right;font-size:11pt}
113
+ table.cmp td.num{font-family:var(--display);font-style:italic;font-weight:500;text-align:right;font-size:11.5pt}
80
114
  table.cmp tr:last-child td{border-bottom:none}
81
115
 
82
- .ask-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm}
83
- .ask-tile{background:var(--surface-card);border:1px solid var(--rule-300);border-radius:var(--radius-md);padding:3mm}
84
- .ask-tile .addr{font-family:var(--display);font-style:italic;font-weight:500;font-size:11pt;color:var(--text-default);line-height:1.15}
85
- .ask-tile .price{font-family:var(--display);font-style:italic;font-weight:500;font-size:13pt;color:var(--teal-900);margin-top:1.5mm}
86
- .ask-tile .meta{font-family:var(--sans);font-weight:500;font-size:6.5pt;letter-spacing:.5pt;color:var(--text-muted);margin-top:1.5mm;text-transform:uppercase}
116
+ /* --- ASKING TILES (FULL WIDTH) --- */
117
+ .ask-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4mm}
118
+ .ask-tile{background:var(--surface-card);border:1px solid var(--rule-300);border-radius:var(--radius-md);padding:4mm}
119
+ .ask-tile .addr{font-family:var(--display);font-style:italic;font-weight:500;font-size:12pt;color:var(--text-default);line-height:1.2}
120
+ .ask-tile .price{font-family:var(--display);font-style:italic;font-weight:500;font-size:16pt;color:var(--teal-900);margin-top:2mm;letter-spacing:-.2pt}
121
+ .ask-tile .meta{font-family:var(--sans);font-weight:500;font-size:7pt;letter-spacing:.6pt;color:var(--text-muted);margin-top:2mm;text-transform:uppercase}
87
122
 
88
- .dist{display:flex;flex-direction:column;gap:2.5mm;margin-top:2mm}
123
+ /* --- DIST BARS --- */
124
+ .dist{display:flex;flex-direction:column;gap:3mm;margin-top:2mm}
89
125
  .dist-row{display:grid;grid-template-columns:40mm 1fr 14mm;align-items:center;gap:3mm}
90
- .dist-row .name{font-size:9.5pt;color:var(--text-default);font-family:var(--body)}
91
- .dist-row .pct{font-family:var(--display);font-style:italic;font-weight:500;font-size:11pt;color:var(--text-default);text-align:right}
92
- .bar{height:4mm;background:var(--paper-75);border-radius:var(--radius-md);overflow:hidden}
126
+ .dist-row .name{font-size:10pt;color:var(--text-default);font-family:var(--body)}
127
+ .dist-row .pct{font-family:var(--display);font-style:italic;font-weight:500;font-size:12pt;color:var(--text-default);text-align:right}
128
+ .bar{height:5mm;background:var(--paper-75);border-radius:var(--radius-md);overflow:hidden}
93
129
  .bar > span{display:block;height:100%;background:var(--teal-900);border-radius:var(--radius-md)}
94
130
  .bar > span.gold{background:var(--gold-500)}
95
131
 
96
- .pill{display:inline-flex;align-items:center;gap:2.5mm;padding:1.5mm 4mm;border-radius:50px;background:var(--gold-500);color:var(--text-on-dark);font-family:var(--display);font-style:italic;font-weight:500;font-size:10pt;letter-spacing:.3pt}
97
- .pill::before{content:"";width:2mm;height:2mm;border-radius:50%;background:#fff}
132
+ /* --- DEMAND GAUGE --- */
133
+ .pill{display:inline-flex;align-items:center;gap:2.5mm;padding:2mm 5mm;border-radius:50px;background:var(--gold-500);color:var(--text-on-dark);font-family:var(--display);font-style:italic;font-weight:500;font-size:11pt;letter-spacing:.3pt}
134
+ .pill::before{content:"";width:2.2mm;height:2.2mm;border-radius:50%;background:#fff}
135
+ .gauge{display:flex;align-items:center;gap:6mm;margin-top:4mm}
136
+ .gauge-track{flex:1;height:5mm;background:var(--paper-75);border-radius:50px;position:relative;overflow:hidden}
137
+ .gauge-fill{position:absolute;inset:0 50% 0 0;background:linear-gradient(90deg,var(--teal-900),var(--gold-500))}
138
+ .gauge-marker{position:absolute;top:-2mm;width:1.2mm;height:9mm;background:var(--text-default);border-radius:2px}
139
+ .gauge-ends{display:flex;justify-content:space-between;font-family:var(--sans);font-weight:500;font-size:7.5pt;letter-spacing:1.5pt;text-transform:uppercase;color:var(--text-muted);margin-top:2mm}
98
140
 
99
- .spark{width:100%;height:38mm;display:block;background:var(--surface-card);border:1px solid var(--rule-300);border-radius:var(--radius-md)}
141
+ /* --- SPARKLINE --- */
142
+ .spark{width:100%;height:36mm;display:block;background:var(--surface-card);border:1px solid var(--rule-300);border-radius:var(--radius-md)}
100
143
  .spark .pl{fill:none;stroke:var(--teal-900);stroke-width:1.4}
101
144
  .spark .pl-psf{fill:none;stroke:var(--gold-500);stroke-width:1.4;stroke-dasharray:2 1.5}
102
145
  .spark .pt{fill:var(--teal-900)}
103
146
  .spark .pt-psf{fill:var(--gold-500)}
104
147
  .spark text{font-family:Inter,sans-serif;font-size:5pt;fill:#6E6E6E;letter-spacing:.4pt}
105
148
  .spark .axis{stroke:var(--rule-300);stroke-width:.4}
106
-
107
149
  .legend{display:flex;gap:6mm;font-family:var(--sans);font-weight:500;font-size:7pt;letter-spacing:1.3pt;text-transform:uppercase;color:var(--text-muted);margin-top:2mm}
108
150
  .legend .sw{display:inline-block;width:6mm;height:1mm;vertical-align:middle;margin-right:2mm;background:var(--teal-900)}
109
151
  .legend .sw.gold{background:var(--gold-500)}
110
152
 
111
- .doc-foot{position:absolute;bottom:9mm;left:16mm;right:16mm;display:flex;justify-content:space-between;font-family:var(--sans);font-weight:500;font-size:8pt;letter-spacing:1.5pt;text-transform:uppercase;color:var(--text-muted)}
112
- .page.dark .doc-foot{color:#7FA0A0}
153
+ /* --- AGENT LISTINGS --- */
154
+ .listings{display:grid;grid-template-columns:repeat(2,1fr);gap:4mm;margin-top:3mm}
155
+ .listing{display:grid;grid-template-columns:50mm 1fr;border:1px solid var(--rule-300);border-radius:var(--radius-xl);overflow:hidden;background:var(--surface-card);transition:background 200ms,border-color 200ms}
156
+ .listing:hover{background:var(--paper-50);border-color:var(--gold-500)}
157
+ .listing .photo{position:relative;aspect-ratio:4/3;background:var(--paper-75)}
158
+ .listing .photo img{width:100%;height:100%;object-fit:cover;display:block}
159
+ .listing .photo .badge{position:absolute;left:2mm;top:2mm;background:var(--gold-500);color:#fff;font-family:var(--sans);font-weight:600;font-size:6pt;letter-spacing:1.2pt;text-transform:uppercase;padding:.9mm 2.2mm;border-radius:50px}
160
+ .listing .photo .badge.sold{background:#2E7D63}
161
+ .listing .photo .badge.under{background:#7C5BC4}
162
+ .listing .meta{padding:3mm 4mm;display:flex;flex-direction:column;justify-content:center;gap:.5mm}
163
+ .listing .meta .addr{font-family:var(--display);font-style:italic;font-weight:500;font-size:13pt;color:var(--text-default);line-height:1.15;letter-spacing:-.2pt}
164
+ .listing .meta .price{font-family:var(--display);font-style:italic;font-weight:500;font-size:14pt;color:var(--text-default);margin-top:1mm;line-height:1;letter-spacing:-.2pt}
165
+ .listing .meta .kfs{display:flex;flex-wrap:wrap;gap:1.2mm;margin-top:1.5mm}
166
+ .listing .meta .kfs span{font-family:var(--sans);font-weight:500;font-size:6.5pt;letter-spacing:.4pt;color:var(--text-default);background:var(--paper-75);padding:.8mm 2mm;border-radius:50px}
113
167
 
114
- .sources{margin-top:5mm;padding-top:5mm;border-top:1px solid var(--rule-300)}
168
+ /* --- SOURCES --- */
169
+ .sources{margin-top:6mm;padding-top:5mm;border-top:1px solid var(--rule-300)}
115
170
  .sources h4{margin-bottom:3mm}
116
171
  .sources p{font-size:8pt;color:var(--text-muted);line-height:1.55;font-family:var(--body);font-style:italic}
117
172
  .sources p + p{margin-top:2.5mm}
173
+
174
+ /* --- WORDMARK FALLBACK --- */
175
+ .wm{display:inline-flex;flex-direction:column;align-items:flex-start;line-height:1;color:var(--teal-900)}
176
+ .wm.light{color:var(--paper-0)}
177
+ .wm-name{font-family:var(--display);font-weight:600;font-style:normal;font-size:34pt;letter-spacing:-1pt;line-height:.9}
178
+ .wm-sub{font-family:var(--sans);font-weight:600;font-size:7pt;letter-spacing:2pt;text-transform:uppercase;margin-top:2mm}
179
+ .wm.small .wm-name{font-size:20pt}
180
+ .wm.small .wm-sub{margin-top:.8mm;font-size:5.5pt;letter-spacing:1.8pt}
118
181
  </style>
119
182
  </head>
120
183
  <body>
121
184
 
122
185
  <!-- PAGE 1 — COVER -->
123
186
  <section class="page dark">
187
+ <div class="cover-bg"></div>
124
188
  <div class="cover-frame">
125
189
  <div>
126
- <div class="cover-eyebrow">Real Agent · Pre-valuation</div>
127
- <div class="cover-rule" style="margin-top:6mm"></div>
190
+ <!-- REPLACE: wordmark_light -->
128
191
  </div>
129
- <div>
130
- <h4 style="color:var(--gold-500);margin-bottom:6mm">Pre-valuation pack</h4>
131
- <h1 style="color:var(--text-on-dark);max-width:170mm"><!-- REPLACE: address --></h1>
132
- <div style="margin-top:10mm"><span class="pc-chip"><!-- REPLACE: postcode --></span></div>
192
+ <div class="cover-hero">
193
+ <div class="cover-rule"></div>
194
+ <h4 style="color:var(--gold-500);margin:6mm 0 4mm"><!-- REPLACE: brand_name --> · Pre-valuation</h4>
195
+ <h1><!-- REPLACE: address --></h1>
196
+ <p class="lede">A view of what this property is worth — <!-- REPLACE: generated -->.</p>
197
+ <div style="margin-top:8mm"><span class="pc-chip"><!-- REPLACE: postcode --></span></div>
133
198
  </div>
134
199
  <dl class="cover-meta">
135
200
  <div><dt>Report</dt><dd>Pre-valuation</dd></div>
201
+ <div><dt>Address</dt><dd style="font-size:11pt;line-height:1.2"><!-- REPLACE: address_short --></dd></div>
136
202
  <div><dt>Postcode</dt><dd><!-- REPLACE: postcode --></dd></div>
137
203
  <div><dt>Generated</dt><dd><!-- REPLACE: generated --></dd></div>
138
204
  </dl>
139
205
  </div>
140
- <div class="doc-foot" style="z-index:2"><span>Real Agent · Property Intelligence</span><span>01</span></div>
206
+ <div class="doc-foot" style="z-index:2"><span><!-- REPLACE: brand_name --> · Property Intelligence</span><span>01</span></div>
141
207
  </section>
142
208
 
143
- <!-- PAGE 2 — VALUATION -->
209
+ <!-- PAGE 2 — SUBJECT VALUATION -->
144
210
  <section class="page">
145
211
  <header class="doc-head">
146
- <div class="wm">Real Agent</div>
147
- <div class="breadcrumb">Valuation · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
212
+ <!-- REPLACE: wordmark_dark -->
213
+ <div class="breadcrumb">Subject valuation · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
148
214
  </header>
149
- <div class="eyebrow">Valuation evidence</div>
215
+ <div class="eyebrow">Subject property</div>
150
216
  <h2 style="margin-top:3mm">What this property is worth.</h2>
151
- <div class="kpis-4">
152
- <div class="kpi"><div class="label">Avg asking £</div><div class="value"><!-- REPLACE: kpi_avg_asking --></div><div class="sub">Live listings — <!-- REPLACE: postcode --></div></div>
153
- <div class="kpi"><div class="label">Asking £/sqft</div><div class="value"><!-- REPLACE: kpi_asking_psf --></div><div class="sub">Mean listing PSF</div></div>
154
- <div class="kpi"><div class="label">Avg sold £</div><div class="value"><!-- REPLACE: kpi_avg_sold --></div><div class="sub">Completed transactions</div></div>
155
- <div class="kpi"><div class="label">Sold £/sqft</div><div class="value"><!-- REPLACE: kpi_sold_psf --></div><div class="sub">Achieved PSF</div></div>
156
- </div>
157
- <div class="two-col" style="grid-template-columns:1.15fr .85fr">
158
- <div class="panel banded">
159
- <h4>Nearest sold comparables</h4>
160
- <table class="cmp" style="margin-top:3mm">
161
- <tr><th>Date</th><th>Address</th><th>Type</th><th style="text-align:right">Price</th></tr>
162
- <!-- REPLACE: sold_comps_rows -->
163
- </table>
164
- </div>
165
- <div class="panel">
166
- <h4>Live asking comparables</h4>
167
- <div class="ask-grid" style="margin-top:3mm">
168
- <!-- REPLACE: asking_comps_tiles -->
169
- </div>
170
- </div>
217
+ <div class="kpis">
218
+ <div class="kpi subject"><div class="label">Floor area</div><div class="value"><!-- REPLACE: kpi_subject_sqft --></div><div class="sub"><!-- REPLACE: kpi_subject_sqft_sub --></div></div>
219
+ <div class="kpi subject"><div class="label">Bedrooms</div><div class="value"><!-- REPLACE: kpi_subject_beds --></div><div class="sub">As recorded</div></div>
220
+ <div class="kpi subject"><div class="label">EPC rating</div><div class="value"><!-- REPLACE: kpi_subject_epc --></div><div class="sub"><!-- REPLACE: kpi_subject_epc_sub --></div></div>
221
+ <div class="kpi subject"><div class="label">Type</div><div class="value" style="font-size:16pt"><!-- REPLACE: kpi_subject_type --></div><div class="sub"><!-- REPLACE: kpi_subject_tenure --></div></div>
171
222
  </div>
172
- <div class="doc-foot"><span>Real Agent · Property Intelligence</span><span>02</span></div>
223
+ <!-- REPLACE: valuation_block -->
224
+ <p class="muted" style="margin-top:6mm;max-width:170mm"><!-- REPLACE: subject_narrative --></p>
225
+ <div class="doc-foot"><span><!-- REPLACE: brand_name --> · Property Intelligence</span><span>02</span></div>
173
226
  </section>
174
227
 
175
- <!-- PAGE 3 — AREA -->
228
+ <!-- PAGE 3 — MARKET CONTEXT -->
176
229
  <section class="page">
177
230
  <header class="doc-head">
178
- <div class="wm">Real Agent</div>
179
- <div class="breadcrumb">Area · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
231
+ <!-- REPLACE: wordmark_dark -->
232
+ <div class="breadcrumb">Market context · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
180
233
  </header>
181
- <div class="eyebrow">Area read</div>
182
- <h2 style="margin-top:3mm"><!-- REPLACE: area_headline --></h2>
183
- <div class="kpis-4">
184
- <div class="kpi"><div class="label">Crime rating</div><div class="value"><!-- REPLACE: kpi_crime --></div><div class="sub">Area average</div></div>
185
- <div class="kpi"><div class="label">Flood risk</div><div class="value"><!-- REPLACE: kpi_flood --></div><div class="sub">Postcode level</div></div>
186
- <div class="kpi"><div class="label">Council tax · D</div><div class="value"><!-- REPLACE: kpi_band_d --></div><div class="sub">Annual at band D</div></div>
187
- <div class="kpi"><div class="label">Population</div><div class="value"><!-- REPLACE: kpi_population --></div><div class="sub">Local area</div></div>
234
+ <div class="eyebrow">Market summary</div>
235
+ <h2 style="margin-top:3mm"><!-- REPLACE: summary_headline --></h2>
236
+ <div class="summary" style="max-width:170mm"><!-- REPLACE: summary_paragraphs --></div>
237
+ <div style="height:5mm"></div>
238
+ <div class="kpis three">
239
+ <div class="kpi gold"><div class="label">Average asking £</div><div class="value"><!-- REPLACE: kpi_avg_asking --></div><div class="sub">Current listings · <!-- REPLACE: postcode --></div></div>
240
+ <div class="kpi"><div class="label">Average sold £</div><div class="value"><!-- REPLACE: kpi_avg_sold --></div><div class="sub">Completed transactions</div></div>
241
+ <div class="kpi"><div class="label">Price per sq ft</div><div class="value"><!-- REPLACE: kpi_psf --></div><div class="sub">Asking-price basis</div></div>
188
242
  </div>
189
- <div class="two-col">
190
- <div class="panel">
191
- <h4>Crime breakdown · 12-month</h4>
192
- <div class="dist" style="margin-top:3mm">
193
- <!-- REPLACE: crime_rows -->
243
+ <div class="two-col" style="align-items:stretch">
244
+ <div class="panel banded" style="display:flex;flex-direction:column">
245
+ <h4>Price growth</h4>
246
+ <div style="display:flex;align-items:baseline;gap:4mm;margin-top:3mm">
247
+ <span style="font-family:var(--display);font-style:italic;font-weight:500;font-size:30pt;color:var(--teal-900);line-height:1;letter-spacing:-.5pt"><!-- REPLACE: kpi_yoy --></span>
248
+ <span class="muted" style="font-style:italic">year on year</span>
194
249
  </div>
250
+ <p class="muted" style="margin-top:3mm"><!-- REPLACE: price_growth_note --></p>
195
251
  </div>
196
- <div class="panel banded">
197
- <h4>Council-tax bands</h4>
198
- <table class="cmp" style="margin-top:3mm">
199
- <tr><th>Band</th><th style="text-align:right">Annual £</th></tr>
200
- <!-- REPLACE: band_rows -->
201
- </table>
252
+ <div class="panel" style="display:flex;flex-direction:column">
253
+ <h4>Demand rating</h4>
254
+ <div style="margin-top:3mm"><span class="pill"><!-- REPLACE: demand_rating --></span></div>
255
+ <div class="gauge"><div class="gauge-track"><div class="gauge-fill"></div><div class="gauge-marker" style="left:<!-- REPLACE: gauge_position -->"></div></div></div>
256
+ <div class="gauge-ends"><span>Buyer's market</span><span>Seller's market</span></div>
257
+ <p class="muted" style="margin-top:4mm"><!-- REPLACE: demand_note --></p>
202
258
  </div>
203
259
  </div>
204
- <div class="doc-foot"><span>Real Agent · Property Intelligence</span><span>03</span></div>
260
+ <div class="panel" style="margin-top:5mm">
261
+ <h4>7-year price trend · £ and £/sqft</h4>
262
+ <!-- REPLACE: spark_svg -->
263
+ <div class="legend"><span><span class="sw"></span>Average £</span><span><span class="sw gold"></span>£/sqft</span></div>
264
+ </div>
265
+ <div class="doc-foot"><span><!-- REPLACE: brand_name --> · Property Intelligence</span><span>03</span></div>
205
266
  </section>
206
267
 
207
- <!-- PAGE 4 — DEMAND + TREND + SOURCES -->
268
+ <!-- PAGE 4 — COMPARABLES (FULL-WIDTH, STACKED) -->
208
269
  <section class="page">
209
270
  <header class="doc-head">
210
- <div class="wm">Real Agent</div>
211
- <div class="breadcrumb">Demand &amp; trend · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
271
+ <!-- REPLACE: wordmark_dark -->
272
+ <div class="breadcrumb">Comparables · <!-- REPLACE: postcode --> · <!-- REPLACE: generated --></div>
212
273
  </header>
213
- <div class="eyebrow">Market posture</div>
214
- <h2 style="margin-top:3mm">How the market is moving.</h2>
215
- <div class="kpis-4">
216
- <div class="kpi"><div class="label">Demand</div><div class="value" style="font-size:14pt"><!-- REPLACE: kpi_demand_rating --></div><div class="sub">Sales-side rating</div></div>
217
- <div class="kpi"><div class="label">Days on market</div><div class="value"><!-- REPLACE: kpi_dom --></div><div class="sub">Average list-to-sale</div></div>
218
- <div class="kpi"><div class="label">Turnover / mo</div><div class="value"><!-- REPLACE: kpi_turnover --></div><div class="sub">Stock churn</div></div>
219
- <div class="kpi"><div class="label">For sale</div><div class="value"><!-- REPLACE: kpi_for_sale --></div><div class="sub">Live listings</div></div>
220
- </div>
221
- <div class="two-col" style="grid-template-columns:1.4fr .6fr">
222
- <div class="panel">
223
- <h4>7-year price trend · £ and £/sqft</h4>
224
- <!-- REPLACE: spark_svg -->
225
- <div class="legend"><span><span class="sw"></span>Average £</span><span><span class="sw gold"></span>£/sqft</span></div>
226
- </div>
227
- <div class="panel banded">
228
- <h4>Rental side</h4>
229
- <div style="margin-top:3mm"><span class="pill"><!-- REPLACE: rental_rating --></span></div>
230
- <table class="cmp" style="margin-top:4mm">
231
- <tr><td>Days on market</td><td class="num"><!-- REPLACE: rental_dom --></td></tr>
232
- <tr><td>Turnover / month</td><td class="num"><!-- REPLACE: rental_turnover --></td></tr>
233
- <tr><td>For rent</td><td class="num"><!-- REPLACE: rental_for_rent --></td></tr>
234
- </table>
235
- </div>
274
+ <div class="eyebrow">Evidence</div>
275
+ <h2 style="margin-top:3mm;margin-bottom:5mm">The comparables behind the range.</h2>
276
+ <div class="panel banded">
277
+ <h4>Nearest sold transactions · Land Registry</h4>
278
+ <table class="cmp" style="margin-top:3mm">
279
+ <tr><th>Date</th><th>Address</th><th>Type</th><th style="text-align:right">Price</th></tr>
280
+ <!-- REPLACE: sold_comps_rows -->
281
+ </table>
236
282
  </div>
237
283
  <div class="panel" style="margin-top:5mm">
238
- <h4>Property-type mix</h4>
239
- <div class="dist" style="margin-top:2mm">
240
- <!-- REPLACE: type_dist_rows -->
284
+ <h4>Live asking comparables</h4>
285
+ <div class="ask-grid" style="margin-top:3mm">
286
+ <!-- REPLACE: asking_comps_tiles -->
241
287
  </div>
242
288
  </div>
289
+ <div class="doc-foot"><span><!-- REPLACE: brand_name --> · Property Intelligence</span><span>04</span></div>
290
+ </section>
291
+
292
+ <!-- PAGE 5 — AGENT LISTINGS + SOURCES -->
293
+ <section class="page">
294
+ <header class="doc-head">
295
+ <!-- REPLACE: wordmark_dark -->
296
+ <div class="breadcrumb">Recently with <!-- REPLACE: brand_name --> · <!-- REPLACE: postcode --></div>
297
+ </header>
298
+ <div class="eyebrow">Recently with <!-- REPLACE: brand_name --></div>
299
+ <h2 style="margin-top:3mm;margin-bottom:2mm">What we have been delivering nearby.</h2>
300
+ <p class="muted" style="max-width:170mm">A selection of recent sales, properties under offer and live instructions handled by <!-- REPLACE: brand_name -->. If you would like the same outcome on <!-- REPLACE: address_short -->, we would welcome a conversation.</p>
301
+ <div class="listings"><!-- REPLACE: agent_listings_cards --></div>
243
302
  <div class="sources">
244
303
  <h4>Sources &amp; methodology</h4>
245
- <p><strong>Sources.</strong> PropertyData (asking, sold, demand, growth, crime, flood, council tax, property-type mix). HM Land Registry (sold transactions). Home Office (recorded crime). Environment Agency (flood risk). Valuation Office Agency (council-tax bands).</p>
246
- <p><strong>Method.</strong> Twelve PropertyData endpoints called on the postcode derived from the address. £/sqft baselines from listing &amp; transaction prices. 7-year trend from PropertyData growth series. Sample sizes vary by postcode density.</p>
304
+ <p><strong>Sources.</strong> PropertyData (asking, sold, demand, growth, crime, flood, council tax, property-type mix). HM Land Registry (sold transactions). Home Office (recorded crime). Environment Agency (flood risk). Valuation Office Agency (council-tax bands). Department for Levelling Up, Housing &amp; Communities — EPC register (subject floor area &amp; energy rating).</p>
305
+ <p><strong>Method.</strong> Twelve PropertyData endpoints called on the postcode derived from the address, plus one EPC lookup on the subject address. Valuation range = subject floor area × the Land Registry 70-percent £/sqft band, with operator-supplied adjustments applied linearly. Live and recent listings shown on the previous page were picked by <!-- REPLACE: brand_name -->.</p>
247
306
  <p><strong>Accuracy.</strong> Property data can change rapidly. Figures are estimates — obtain independent professional advice for specific decisions. This pack is not financial or investment advice.</p>
248
307
  </div>
249
- <div class="doc-foot"><span>Real Agent · Generated <!-- REPLACE: generated --> · <!-- REPLACE: postcode --></span><span>04</span></div>
308
+ <div class="doc-foot"><span><!-- REPLACE: brand_name --> · Generated <!-- REPLACE: generated --> · <!-- REPLACE: postcode --></span><span>05</span></div>
250
309
  </section>
251
310
 
252
311
  </body>
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AACrE,OAAO,EAA0E,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAIzH,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAA;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AA6E3D,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACvF,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;CAC/B;AAoHD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAusBjD"}
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AACrE,OAAO,EAA0E,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAIzH,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAA;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AA6E3D,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACvF,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;CAC/B;AAoHD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CA8sBjD"}
@@ -308,11 +308,15 @@ export function buildHttpApp(deps) {
308
308
  const model = typeof body.model === 'string' && /^[A-Za-z0-9._-]{1,64}$/.test(body.model)
309
309
  ? body.model
310
310
  : undefined;
311
+ const initialMessage = typeof body.initialMessage === 'string' && body.initialMessage.length > 0
312
+ ? body.initialMessage
313
+ : undefined;
311
314
  const aboutOwnerShape = body.aboutOwner == null ? 'absent' : (typeof body.aboutOwner === 'object' ? 'object' : typeof body.aboutOwner);
312
315
  const dormantPluginsShape = Array.isArray(body.dormantPlugins)
313
316
  ? `array(${body.dormantPlugins.length})`
314
317
  : body.dormantPlugins == null ? 'absent' : typeof body.dormantPlugins;
315
- deps.logger(`spawn-request senderId=${senderId || 'missing'} role=${role || 'missing'} channel=${channel || 'missing'} permissionMode=${typeof body.permissionMode === 'string' ? body.permissionMode : 'default'} channels=${Array.isArray(body.channels) ? body.channels.length : 0} attachmentDir=${typeof body.attachmentDir === 'string' ? 'set' : 'absent'} aboutOwner=${aboutOwnerShape} dormantPlugins=${dormantPluginsShape} tunnelUrl=${typeof body.tunnelUrl === 'string' ? 'set' : (body.tunnelUrl === null ? 'null' : 'absent')}`);
318
+ const initialMessageBytes = typeof body.initialMessage === 'string' ? Buffer.byteLength(body.initialMessage, 'utf8') : 0;
319
+ deps.logger(`spawn-request senderId=${senderId || 'missing'} role=${role || 'missing'} channel=${channel || 'missing'} permissionMode=${typeof body.permissionMode === 'string' ? body.permissionMode : 'default'} channels=${Array.isArray(body.channels) ? body.channels.length : 0} attachmentDir=${typeof body.attachmentDir === 'string' ? 'set' : 'absent'} aboutOwner=${aboutOwnerShape} dormantPlugins=${dormantPluginsShape} tunnelUrl=${typeof body.tunnelUrl === 'string' ? 'set' : (body.tunnelUrl === null ? 'null' : 'absent')} initialMessageBytes=${initialMessageBytes}`);
316
320
  if (!senderId || !ROLES.includes(role) || !CHANNELS.includes(channel)) {
317
321
  timed(deps.logger, 'POST', '/spawn', 400, Date.now() - start);
318
322
  return c.json({ error: 'invalid-arguments', detail: { senderId: !!senderId, role, channel } }, 400);
@@ -360,6 +364,7 @@ export function buildHttpApp(deps) {
360
364
  hidden,
361
365
  specialist,
362
366
  model,
367
+ initialMessage,
363
368
  });
364
369
  if (!result.ok) {
365
370
  if ('rejected' in result) {