@mapled/cli 0.17.0 → 0.17.1

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.
package/README.md CHANGED
@@ -73,7 +73,7 @@ Only public values live here — the project id, where the generated types go, t
73
73
  npx @mapled/cli types generate
74
74
  ```
75
75
 
76
- Reads the project's schema and writes `mapled-types.ts` (the path from `mapled.json`, or `--out <file>`): one interface per collection and single, keyed maps, a `MapledSchema` that ties them together, and doc comments with the field types. Sensitive fields never reach the site and are left out. A group field is typed by an interface of its items; the project's component types become one interface each (`HeroComponent`, with `_type: "hero"` and the item's `_key`), a `components` field a list of the union of the types it allows, and `MapledComponent` the union of them all — switch on `_type` to render an item.
76
+ Reads the project's schema and writes `mapled-types.ts` (the path from `mapled.json`, or `--out <file>`): one interface per collection and single, keyed maps, a `MapledSchema` that ties them together, and doc comments with the field types. Sensitive fields never reach the site and are left out. A group field is typed by an interface of its items; the project's component types become one interface each (`HeroComponent`, with `_type: "hero"` and the item's `_key`; a group inside a type, a list of its items' interface — `PricingTiersItem[]`), a `components` field a list of the union of the types it allows, and `MapledComponent` the union of them all — switch on `_type` to render an item.
77
77
 
78
78
  ```ts
79
79
  import type { MapledSchema } from "./mapled-types";
@@ -195,7 +195,7 @@ npx @mapled/cli media upload public/products/hoodie.jpg https://example.com/cove
195
195
  npx @mapled/cli media upload --run <runId>
196
196
  ```
197
197
 
198
- `media upload` puts images and files into the project's Media: a path is read from this repository (a path from the site's root, `/images/a.png`, is looked for under `public/` and `static/` too; nothing outside the repository is read), an address is downloaded by Mapled. PNG, JPEG, WebP, GIF and SVG up to 10 MB, PDF up to 25 MB; the same bytes uploaded twice are one file. Each line names the asset id an image or file field holds. `--run <runId>` uploads every file an approved setup plan names that isn't in Mapled yet, for `apply_setup_plan` to put into the records (`--json` for scripts); a file that didn't upload is named with the reason and the command exits 1.
198
+ `media upload` puts images and files into the project's Media: a path is read from this repository (a path from the site's root, `/images/a.png`, is looked for under `public/` and `static/` too; nothing outside the repository is read), an address is downloaded by Mapled. PNG, JPEG, WebP, GIF and SVG up to 10 MB, PDF and 3D models (GLB, or glTF as one file) up to 25 MB; the same bytes uploaded twice are one file. Each line names the asset id an image or file field holds. `--run <runId>` uploads every file an approved setup plan names that isn't in Mapled yet, for `apply_setup_plan` to put into the records (`--json` for scripts); a file that didn't upload is named with the reason and the command exits 1.
199
199
 
200
200
  ## Leave a guide for the next agent
201
201
 
@@ -0,0 +1,50 @@
1
+ /** The page the browser shows at the end of `mapled auth login` — the
2
+ loopback redirect on 127.0.0.1. One template for every outcome, drawn
3
+ after the S-56 service pages of the app (Figma 570:9128): the logo in
4
+ the top corner of a page panel, a centred heading and subtitle, at
5
+ most one primary action. The page loads nothing — no fonts, no
6
+ images, no scripts from anywhere: styles and the logo are inline, the
7
+ one script carries this response's nonce. The values are the app's
8
+ tokens (apps/web/src/app/globals.css), copied: the page can't read
9
+ them from here. Dark only, as the app. */
10
+ export type CallbackView =
11
+ /** Signed in; `url` is the project in Mapled, where the tab goes on. */
12
+ {
13
+ kind: "signed-in";
14
+ project: string;
15
+ url: string | null;
16
+ }
17
+ /** The code came, but the sign-in didn't complete (exchange, API). */
18
+ | {
19
+ kind: "failed";
20
+ }
21
+ /** The person cancelled or denied on the consent screen. */
22
+ | {
23
+ kind: "cancelled";
24
+ }
25
+ /** A redirect that isn't the running command's — an older sign-in. */
26
+ | {
27
+ kind: "expired";
28
+ }
29
+ /** A redirect without its code. */
30
+ | {
31
+ kind: "incomplete";
32
+ }
33
+ /** Nobody told the page how the sign-in ended — the command stopped
34
+ waiting for it (`HOLD_MS` in oauth.ts). */
35
+ | {
36
+ kind: "handed-over";
37
+ };
38
+ /** Seconds before a signed-in tab opens the project by itself. */
39
+ export declare const REDIRECT_SECONDS = 5;
40
+ /** Only a web address goes into the page: Mapled's answer names it, and
41
+ anything else (`javascript:`, a bare word) leaves the tab where it is. */
42
+ export declare function safeUrl(value: unknown): string | null;
43
+ export type RenderedPage = {
44
+ status: number;
45
+ html: string;
46
+ csp: string;
47
+ };
48
+ /** The whole response for a view. The project's name is the person's own
49
+ text and is escaped like everything else that goes in. */
50
+ export declare function callbackPage(view: CallbackView): RenderedPage;
@@ -0,0 +1,141 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { LOGO_SVG } from "./logo.js";
3
+ /** Seconds before a signed-in tab opens the project by itself. */
4
+ export const REDIRECT_SECONDS = 5;
5
+ const text = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6
+ /** Only a web address goes into the page: Mapled's answer names it, and
7
+ anything else (`javascript:`, a bare word) leaves the tab where it is. */
8
+ export function safeUrl(value) {
9
+ if (typeof value !== "string")
10
+ return null;
11
+ try {
12
+ const url = new URL(value);
13
+ return url.protocol === "https:" || url.protocol === "http:" ? url.toString() : null;
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ function copyOf(view) {
20
+ switch (view.kind) {
21
+ case "signed-in":
22
+ return view.url
23
+ ? {
24
+ status: 200,
25
+ title: "You're signed in",
26
+ body: `Your AI agent is connected to ${view.project}. Follow the setup in Mapled.`,
27
+ action: { label: "Open setup status", href: view.url },
28
+ }
29
+ : {
30
+ status: 200,
31
+ title: "You're signed in",
32
+ body: `Your AI agent is connected to ${view.project}. You can close this tab and go back to your agent.`,
33
+ };
34
+ case "failed":
35
+ return {
36
+ status: 200,
37
+ title: "Sign-in didn't finish",
38
+ body: "Mapled couldn't complete the sign-in. Go back to your AI agent and try again.",
39
+ };
40
+ case "cancelled":
41
+ return {
42
+ status: 200,
43
+ title: "Sign-in cancelled",
44
+ body: "Your AI agent isn't connected. You can close this tab and go back to your agent.",
45
+ };
46
+ case "expired":
47
+ return {
48
+ status: 400,
49
+ title: "This sign-in link has expired",
50
+ body: "It belongs to an earlier sign-in. Go back to your AI agent and start again.",
51
+ };
52
+ case "incomplete":
53
+ return {
54
+ status: 400,
55
+ title: "This sign-in link is incomplete",
56
+ body: "Go back to your AI agent and start the sign-in again.",
57
+ };
58
+ case "handed-over":
59
+ return {
60
+ status: 200,
61
+ title: "Back to your AI agent",
62
+ body: "Your AI agent finishes the sign-in. You can close this tab.",
63
+ };
64
+ }
65
+ }
66
+ /* The app's tokens, by name: --bg-page #010101, --surface-page #0a0a0a,
67
+ --text-primary #fefefe, --text-secondary #989898, --accent #eb5c1a,
68
+ --accent-hover #d54908, --shadow-bevel, --focus-glow, --radius-panel 16,
69
+ --control-lg 48; heading 32 Medium / 1 / -0.04em, subtitle 16 / 1.48 /
70
+ -0.02em, note 14 (FormHeading, accept.note). */
71
+ const STYLE = "*{box-sizing:border-box;margin:0}" +
72
+ ":root{color-scheme:dark}" +
73
+ "html,body{min-height:100%}" +
74
+ "body{min-height:100vh;min-height:100dvh;display:flex;padding:16px;background:#010101;color:#fefefe;" +
75
+ "font-family:Inter,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;-webkit-font-smoothing:antialiased}" +
76
+ "main{flex:1;min-width:0;display:flex;flex-direction:column;padding:20px;border-radius:16px;background:#0a0a0a}" +
77
+ "header{display:flex;align-items:center;min-height:32px}" +
78
+ "header svg{display:block;width:122px;height:32px}" +
79
+ ".box{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:40px;" +
80
+ "width:100%;max-width:528px;margin:0 auto;padding:0 8px 32px;text-align:center}" +
81
+ ".heading{display:flex;flex-direction:column;gap:8px}" +
82
+ "h1{font-size:32px;font-weight:500;line-height:1;letter-spacing:-0.04em;text-wrap:balance}" +
83
+ "p{font-size:16px;line-height:1.48;letter-spacing:-0.02em;color:#989898;text-wrap:pretty;overflow-wrap:break-word}" +
84
+ ".group{display:flex;flex-direction:column;align-items:center;gap:16px}" +
85
+ ".button{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:0 24px;" +
86
+ "border-radius:1000px;background:#eb5c1a;color:#fefefe;font-size:14px;font-weight:500;line-height:1;" +
87
+ "text-decoration:none;white-space:nowrap;transition:background-color .2s ease;" +
88
+ "box-shadow:inset 0 0 0 1px rgb(255 255 255/8%),inset -2px -2px 2px 0 rgb(255 255 255/25%),inset 2px 2px 2px 0 rgb(255 255 255/25%)}" +
89
+ ".button:hover{background:#d54908}" +
90
+ ".button:focus-visible{outline:0;box-shadow:inset 0 0 0 1px rgb(255 255 255/8%),inset -2px -2px 2px 0 rgb(255 255 255/25%)," +
91
+ "inset 2px 2px 2px 0 rgb(255 255 255/25%),0 0 4px 0 #2d82cc}" +
92
+ ".note{font-size:14px;line-height:normal;letter-spacing:0}" +
93
+ "@media (max-width:600px){h1{font-size:28px}}" +
94
+ "@media (prefers-reduced-motion:reduce){.button{transition:none}}";
95
+ /** The countdown: one line updated each second, then the same address
96
+ the button has. `replace`: Back doesn't land on the loopback, which is
97
+ gone by then. */
98
+ const SCRIPT = "(function(){var s=document.currentScript,to=s.getAttribute('data-to'),n=Number(s.getAttribute('data-seconds')),c=document.getElementById('count');" +
99
+ "function tick(){if(n<=0){location.replace(to);return}if(c)c.textContent=n+(n===1?' second':' seconds');n-=1;setTimeout(tick,1000)}tick()})()";
100
+ const seconds = (n) => `${n} ${n === 1 ? "second" : "seconds"}`;
101
+ /** The whole response for a view. The project's name is the person's own
102
+ text and is escaped like everything else that goes in. */
103
+ export function callbackPage(view) {
104
+ const copy = copyOf(view);
105
+ const nonce = randomBytes(16).toString("base64");
106
+ const action = copy.action;
107
+ const html = "<!doctype html>" +
108
+ '<html lang="en"><head><meta charset="utf-8">' +
109
+ '<meta name="viewport" content="width=device-width, initial-scale=1">' +
110
+ '<meta name="robots" content="noindex, nofollow">' +
111
+ '<meta name="referrer" content="no-referrer">' +
112
+ `<title>${text(copy.title)} · Mapled</title>` +
113
+ // without scripts the tab still moves on, after the same pause
114
+ (action ? `<noscript><meta http-equiv="refresh" content="${REDIRECT_SECONDS};url=${text(action.href)}"></noscript>` : "") +
115
+ `<style>${STYLE}</style>` +
116
+ "</head><body><main>" +
117
+ `<header>${LOGO_SVG}</header>` +
118
+ '<div class="box">' +
119
+ `<div class="heading"><h1>${text(copy.title)}</h1><p>${text(copy.body)}</p></div>` +
120
+ (action
121
+ ? '<div class="group">' +
122
+ `<a class="button" href="${text(action.href)}">${text(action.label)}</a>` +
123
+ `<p class="note">Opening automatically in <span id="count">${seconds(REDIRECT_SECONDS)}</span></p>` +
124
+ "</div>"
125
+ : "") +
126
+ "</div></main>" +
127
+ (action
128
+ ? `<script nonce="${nonce}" data-to="${text(action.href)}" data-seconds="${REDIRECT_SECONDS}">${SCRIPT}</script>`
129
+ : "") +
130
+ "</body></html>";
131
+ const csp = [
132
+ "default-src 'none'",
133
+ `script-src 'nonce-${nonce}'`,
134
+ "style-src 'unsafe-inline'",
135
+ "img-src data:",
136
+ "base-uri 'none'",
137
+ "form-action 'none'",
138
+ "frame-ancestors 'none'",
139
+ ].join("; ");
140
+ return { status: copy.status, html, csp };
141
+ }
package/dist/commands.js CHANGED
@@ -7,6 +7,7 @@ import { connectionsFor, findConnection, readCredentials, removeConnection, upse
7
7
  import * as dr from "./doctor.js";
8
8
  import { CliError, SignInNeeded } from "./errors.js";
9
9
  import { checkManifest, compareManifests, fileExistsIn, MANIFEST_FILE, manifestSummary, orderManifest, parseManifest, plural, readManifestFile, writeManifestFile, } from "./manifest.js";
10
+ import { safeUrl } from "./callbackPage.js";
10
11
  import { authorize, clientKnown, exchangeCode, registerClient, revokeToken } from "./oauth.js";
11
12
  import { formatChecks, GLYPH, paint, summarize, useColor } from "./output.js";
12
13
  import { diffSchema, formatChanges, pinSchema, readPin, SCHEMA_FILE, summarizeChanges, writePin } from "./pin.js";
@@ -49,18 +50,31 @@ export async function login(ctx, flags) {
49
50
  timeoutMs: ctx.loginTimeoutMs,
50
51
  project: projectFlag(flags),
51
52
  });
52
- const tokens = await exchangeCode(api, client.clientId, grant, ctx.fetch);
53
- const status = await apiGet(api, "/v1/agent/integration", tokens.accessToken, ctx.fetch);
54
- const conn = {
55
- api,
56
- projectId: status.project.id,
57
- projectName: status.project.name,
58
- clientId: client.clientId,
59
- ...tokens,
60
- createdAt: new Date().toISOString(),
61
- };
62
- store = upsertConnection(store, conn);
63
- await writeCredentials(ctx.credentialsFile, store);
53
+ // the tab says "signed in" only once the tokens are kept: until then
54
+ // anything that fails (exchange, API, the credentials file) is a
55
+ // sign-in that didn't finish
56
+ let conn;
57
+ let status;
58
+ try {
59
+ const tokens = await exchangeCode(api, client.clientId, grant, ctx.fetch);
60
+ status = await apiGet(api, "/v1/agent/integration", tokens.accessToken, ctx.fetch);
61
+ conn = {
62
+ api,
63
+ projectId: status.project.id,
64
+ projectName: status.project.name,
65
+ clientId: client.clientId,
66
+ ...tokens,
67
+ createdAt: new Date().toISOString(),
68
+ };
69
+ store = upsertConnection(store, conn);
70
+ await writeCredentials(ctx.credentialsFile, store);
71
+ }
72
+ catch (err) {
73
+ grant.tab.show({ kind: "failed" });
74
+ throw err;
75
+ }
76
+ // the tab goes on to the project in Mapled, where the setup shows
77
+ grant.tab.show({ kind: "signed-in", project: status.project.name, url: safeUrl(status.project.dashboardUrl) });
64
78
  ctx.out(`Signed in to ${clean(conn.projectName, 80)}.`);
65
79
  if (!found)
66
80
  ctx.out("Next: run `mapled project link` in the site's repository.");
@@ -466,8 +480,9 @@ async function loadManifest(dir) {
466
480
  keeps one, otherwise the live schema of a signed-in project. */
467
481
  async function schemaForChecks(ctx, flags, found) {
468
482
  const pin = await readPin(found.dir);
483
+ // the pin's component types too: the blocks' templates and bindings name their sub-fields
469
484
  if (pin)
470
- return { schema: { collections: pin.pin.collections }, note: null };
485
+ return { schema: { collections: pin.pin.collections, ...(pin.pin.componentTypes ? { componentTypes: pin.pin.componentTypes } : {}) }, note: null };
471
486
  try {
472
487
  const { session } = await openSession(ctx, flags);
473
488
  return { schema: await session.get("/v1/agent/schema"), note: null };
@@ -943,7 +958,7 @@ export async function doctor(ctx, flags) {
943
958
  checks.push(dr.checkTypes(existing, schema ? generateTypes(schema, { projectName: status?.project.name, sdk: dr.sdkOf(framework) }) : null, typesPath, framework));
944
959
  const pin = found ? await readPin(dir).catch(() => null) : null;
945
960
  const livePin = schema && found ? pinSchema(schema, found.config.project) : null;
946
- const pinChanges = pin && livePin ? diffSchema(pin.pin.collections, livePin.collections) : null;
961
+ const pinChanges = pin && livePin ? diffSchema(pin.pin.collections, livePin.collections, { before: pin.pin.componentTypes, after: livePin.componentTypes }) : null;
947
962
  checks.push(dr.checkSchemaPin(pin?.pin ?? null, livePin?.hash ?? null, pinChanges));
948
963
  const localManifest = await loadManifest(dir).catch(() => null);
949
964
  let remoteManifest = "unknown";
package/dist/doctor.d.ts CHANGED
@@ -18,11 +18,13 @@ export type Check = {
18
18
  };
19
19
  /** GET /v1/agent/integration */
20
20
  export type IntegrationStatus = {
21
+ /** `dashboardUrl` — the project in Mapled; missing from an older API */
21
22
  project: {
22
23
  id: string;
23
24
  name: string;
24
25
  slug: string;
25
26
  productionDomain: string | null;
27
+ dashboardUrl?: string;
26
28
  };
27
29
  connection: {
28
30
  id: string;
package/dist/logo.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** The Mapled logo — apps/web/public/brand/logo.svg (Figma, 122×32), with
2
+ its coordinates rounded to two decimals so the sign-in page carries it
3
+ inline: the page is served from 127.0.0.1 and loads nothing. */
4
+ export declare const LOGO_SVG = "<svg width=\"122\" height=\"32\" role=\"img\" aria-label=\"Mapled\" viewBox=\"0 0 122 32.03\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M41.62 7.49H45.87L51.57 21.08H51.8L57.49 7.49H61.75V26.25H58.41V13.36H58.23L52.93 26.2H50.44L45.13 13.33H44.96V26.25H41.62V7.49Z\" fill=\"#FEFEFE\"/><path d=\"M67.41 26.54C66.5 26.54 65.68 26.38 64.95 26.06C64.22 25.74 63.65 25.26 63.23 24.63C62.81 24 62.6 23.23 62.6 22.3C62.6 21.51 62.75 20.85 63.05 20.33C63.35 19.81 63.76 19.4 64.27 19.09C64.79 18.78 65.38 18.54 66.03 18.38C66.68 18.22 67.36 18.1 68.06 18.02C68.9 17.94 69.59 17.86 70.11 17.8C70.64 17.72 71.02 17.61 71.26 17.47C71.5 17.31 71.62 17.08 71.62 16.76V16.71C71.62 16.02 71.41 15.48 70.99 15.1C70.57 14.72 69.97 14.53 69.18 14.53C68.35 14.53 67.69 14.71 67.21 15.07C66.73 15.42 66.4 15.84 66.23 16.32L63.07 15.88C63.32 15.03 63.73 14.31 64.3 13.74C64.88 13.16 65.58 12.72 66.41 12.44C67.24 12.14 68.16 12 69.17 12C69.86 12 70.55 12.08 71.24 12.23C71.92 12.39 72.55 12.66 73.12 13.02C73.69 13.38 74.14 13.87 74.49 14.5C74.84 15.12 75.01 15.9 75.01 16.83V26.25H71.75V24.32H71.64C71.43 24.71 71.14 25.08 70.77 25.42C70.4 25.75 69.93 26.03 69.37 26.23C68.82 26.43 68.16 26.54 67.41 26.54ZM68.29 24.1C68.98 24.1 69.57 23.97 70.07 23.7C70.57 23.44 70.95 23.08 71.22 22.64C71.49 22.2 71.63 21.72 71.63 21.2V19.55C71.52 19.63 71.34 19.71 71.09 19.78C70.84 19.86 70.56 19.92 70.24 19.98C69.93 20.03 69.62 20.08 69.32 20.12C69.01 20.17 68.74 20.2 68.52 20.23C68.01 20.3 67.56 20.41 67.16 20.56C66.76 20.71 66.45 20.93 66.21 21.2C65.98 21.47 65.87 21.82 65.87 22.25C65.87 22.86 66.1 23.32 66.55 23.63C67.01 23.94 67.59 24.1 68.29 24.1Z\" fill=\"#FEFEFE\"/><path d=\"M76.31 31.53V12.18H79.65V14.51H79.85C80.02 14.16 80.27 13.8 80.59 13.42C80.9 13.03 81.34 12.69 81.88 12.42C82.42 12.14 83.12 12 83.96 12C85.07 12 86.07 12.27 86.97 12.83C87.87 13.38 88.58 14.2 89.1 15.28C89.63 16.35 89.9 17.67 89.9 19.23C89.9 20.78 89.64 22.09 89.12 23.17C88.6 24.25 87.9 25.08 87 25.65C86.11 26.21 85.1 26.5 83.97 26.5C83.14 26.5 82.46 26.36 81.92 26.1C81.37 25.83 80.94 25.5 80.6 25.12C80.28 24.74 80.03 24.38 79.85 24.03H79.71V31.53H76.31ZM79.64 19.22C79.64 20.13 79.77 20.92 80.03 21.61C80.3 22.29 80.69 22.83 81.19 23.21C81.69 23.59 82.3 23.78 83.02 23.78C83.77 23.78 84.4 23.58 84.91 23.19C85.41 22.79 85.79 22.25 86.05 21.57C86.31 20.88 86.44 20.1 86.44 19.22C86.44 18.34 86.31 17.57 86.06 16.89C85.8 16.21 85.42 15.68 84.92 15.29C84.41 14.91 83.78 14.72 83.02 14.72C82.3 14.72 81.68 14.9 81.18 15.28C80.67 15.65 80.29 16.17 80.02 16.84C79.77 17.51 79.64 18.31 79.64 19.22Z\" fill=\"#FEFEFE\"/><path d=\"M94.09 7.49V26.25H90.69V7.49H94.09Z\" fill=\"#FEFEFE\"/><path d=\"M101.84 26.53C100.39 26.53 99.15 26.23 98.1 25.65C97.05 25.05 96.25 24.22 95.69 23.14C95.13 22.05 94.84 20.77 94.84 19.3C94.84 17.85 95.13 16.58 95.69 15.49C96.26 14.39 97.05 13.53 98.07 12.92C99.09 12.3 100.28 12 101.66 12C102.54 12 103.38 12.14 104.17 12.42C104.96 12.69 105.66 13.12 106.27 13.7C106.88 14.28 107.36 15.02 107.71 15.92C108.06 16.81 108.24 17.87 108.24 19.11V20.12H96.44V17.89H104.98C104.98 17.25 104.84 16.69 104.56 16.19C104.29 15.69 103.9 15.3 103.41 15.01C102.92 14.72 102.35 14.58 101.7 14.58C101.01 14.58 100.4 14.74 99.88 15.07C99.35 15.4 98.94 15.83 98.65 16.36C98.36 16.88 98.22 17.46 98.21 18.09V20.04C98.21 20.86 98.36 21.56 98.67 22.15C98.97 22.73 99.4 23.17 99.95 23.48C100.5 23.79 101.15 23.94 101.88 23.94C102.38 23.94 102.82 23.88 103.22 23.74C103.62 23.6 103.97 23.4 104.26 23.13C104.56 22.86 104.78 22.53 104.93 22.13L108.1 22.48C107.9 23.3 107.51 24.01 106.95 24.62C106.4 25.23 105.68 25.7 104.82 26.03C103.95 26.36 102.95 26.53 101.84 26.53Z\" fill=\"#FEFEFE\"/><path d=\"M114.34 26.5C113.2 26.5 112.19 26.21 111.3 25.65C110.41 25.08 109.7 24.25 109.18 23.17C108.66 22.09 108.4 20.78 108.4 19.23C108.4 17.67 108.67 16.35 109.19 15.28C109.72 14.2 110.44 13.38 111.34 12.83C112.24 12.27 113.24 12 114.34 12C115.19 12 115.88 12.14 116.43 12.42C116.97 12.69 117.4 13.03 117.72 13.42C118.04 13.8 118.28 14.16 118.46 14.51H118.6V7.49H122V26.25H118.66V24.03H118.46C118.28 24.38 118.03 24.74 117.7 25.12C117.37 25.5 116.93 25.83 116.39 26.1C115.84 26.36 115.16 26.5 114.34 26.5ZM115.28 23.78C116 23.78 116.61 23.59 117.12 23.21C117.62 22.83 118.01 22.29 118.27 21.61C118.53 20.92 118.66 20.13 118.66 19.22C118.66 18.31 118.53 17.51 118.27 16.84C118.01 16.17 117.63 15.65 117.13 15.28C116.63 14.9 116.01 14.72 115.28 14.72C114.53 14.72 113.9 14.91 113.39 15.29C112.88 15.68 112.5 16.21 112.25 16.89C111.99 17.57 111.86 18.34 111.86 19.22C111.86 20.1 111.99 20.88 112.25 21.57C112.51 22.25 112.89 22.79 113.4 23.19C113.91 23.58 114.54 23.78 115.28 23.78Z\" fill=\"#FEFEFE\"/><path d=\"M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z\" fill=\"url(#g0)\"/><path d=\"M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z\" fill=\"url(#g1)\"/><path d=\"M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z\" fill=\"url(#g2)\"/><path d=\"M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z\" fill=\"url(#g3)\"/><path d=\"M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.79 5.28 10.91 5.03L10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.24 4.52 21.39 4.43 21.51 4.31L21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15L27.3 5.17C27.44 5.38 27.73 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39L29.43 14.49C29.34 15.53 29.09 16.53 30.25 17C30.4 17.06 30.61 17.18 30.78 17.27L30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2L21.81 27.49C20.71 28.99 19.55 30.52 18.49 32.03C18.18 31.44 17.25 29.54 16.84 29.15L16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.5 4.59 20.37L4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.13 18.4 10.23 18.29L10.24 18.27C10.34 18.15 10.38 17.99 10.36 17.83L10.36 17.8C10.29 17.42 9.66 17.07 9.3 16.83L9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.36 10.63 5.55 10.22 5.5 9.93L5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63ZM5.18 7.89C5.37 8.52 5.58 9.19 5.72 9.85C5.77 10.06 5.72 10.29 5.63 10.48C5.54 10.67 5.39 10.86 5.19 10.95C4.67 11.17 4.12 11.36 3.58 11.53C3.19 11.66 2.8 11.78 2.42 11.91L9.36 16.6C9.51 16.7 9.81 16.87 10.04 17.05C10.16 17.14 10.28 17.24 10.38 17.36C10.48 17.47 10.56 17.61 10.59 17.76H10.59C10.63 17.99 10.57 18.23 10.43 18.41L10.43 18.41L10.43 18.41C10.36 18.5 10.27 18.58 10.17 18.64C10.07 18.69 9.95 18.75 9.81 18.75C9.18 18.76 8.44 18.69 7.82 18.65L7.82 18.65L7.82 18.65L3.82 18.34C4.16 18.96 4.52 19.62 4.8 20.27C4.84 20.38 4.85 20.5 4.85 20.6C4.85 20.7 4.83 20.81 4.8 20.9L4.8 20.9L4.8 20.9C4.73 21.08 4.62 21.23 4.48 21.36C4.35 21.46 4.06 21.64 3.78 21.81C3.49 21.99 3.21 22.15 3.06 22.24L0.46 23.83C1.45 24.37 2.43 24.97 3.39 25.52C3.69 25.7 4.04 25.88 4.41 26.08C4.76 26.28 5.12 26.49 5.4 26.69C5.55 26.81 5.67 26.98 5.72 27.17C5.75 27.26 5.75 27.36 5.75 27.45C5.74 27.55 5.72 27.66 5.7 27.77C5.65 28 5.58 28.25 5.5 28.5C5.41 28.76 5.32 29.01 5.24 29.23C5.22 29.31 5.19 29.38 5.17 29.45L12.52 28.89H12.53L14.79 28.72C15.19 28.69 15.66 28.63 16.1 28.64L16.15 28.64L16.15 28.64C16.44 28.66 16.74 28.76 16.98 28.96C17.11 29.07 17.26 29.29 17.41 29.53C17.56 29.77 17.73 30.07 17.89 30.38C18.12 30.8 18.35 31.25 18.52 31.58C19.6 30.08 20.75 28.55 21.84 27.06C22.47 26.19 23.54 24.66 24.26 23.9L24.27 23.89L24.27 23.89C24.78 23.42 25.23 23.11 25.75 22.74L25.98 22.57L25.98 22.57L27.84 21.25L27.85 21.25C29.21 20.28 30.71 19.18 32.11 18.23L30.74 17.51L30.74 17.51C30.54 17.41 30.32 17.28 30.16 17.21C29.83 17.08 29.59 16.9 29.42 16.68C29.25 16.45 29.17 16.2 29.13 15.95C29.1 15.69 29.11 15.43 29.13 15.16C29.14 15.03 29.16 14.9 29.17 14.77C29.18 14.64 29.2 14.5 29.21 14.37L29.38 12.17L29.94 5.11C29.76 5.17 29.57 5.23 29.38 5.29C29.16 5.35 28.96 5.43 28.73 5.51C28.5 5.58 28.26 5.65 28.01 5.68L27.98 5.69C27.65 5.72 27.27 5.57 27.08 5.27C26.73 4.72 26.4 4.13 26.08 3.59C25.45 2.55 24.83 1.52 24.22 0.48L22.61 3.04H22.61C22.51 3.19 22.35 3.46 22.17 3.75C22 4.02 21.82 4.3 21.71 4.43L21.71 4.43C21.56 4.61 21.36 4.73 21.13 4.78L21.13 4.78C20.92 4.82 20.72 4.78 20.55 4.73C20.38 4.67 20.21 4.58 20.09 4.52C19.61 4.28 19.12 4.04 18.64 3.79L18.91 7.34C18.94 7.7 19 8.13 19.01 8.51V8.51C19.01 8.64 19.03 8.8 19.05 8.99C19.07 9.17 19.08 9.37 19.07 9.56C19.05 9.75 19 9.95 18.88 10.12C18.74 10.29 18.55 10.4 18.3 10.44L18.27 10.44C18.07 10.47 17.89 10.4 17.74 10.3C17.6 10.21 17.46 10.07 17.35 9.93C17.13 9.67 16.93 9.33 16.82 9.17L16.82 9.17L15.67 7.54C14.51 5.88 13.23 4.12 12.08 2.43C11.78 3.31 11.49 4.27 11.13 5.11C11.04 5.31 10.84 5.46 10.66 5.55C10.47 5.64 10.23 5.71 10.02 5.66C9.47 5.55 8.91 5.37 8.38 5.22L8.38 5.22L8.38 5.22L4.78 4.18L4.78 4.18C4.69 4.16 4.42 4.08 4.16 4C4.1 3.98 4.05 3.97 3.99 3.95L5.18 7.89Z\" fill=\"url(#g4)\"/><defs><linearGradient id=\"g0\" x1=\"3.66\" y1=\"3.62\" x2=\"25.15\" y2=\"25.49\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#EB5C1A\"/><stop offset=\"1\" stop-color=\"#CD3E2E\"/></linearGradient><linearGradient id=\"g1\" x1=\"27.28\" y1=\"1.91\" x2=\"2.36\" y2=\"27.27\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0.36\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/><stop offset=\"0.5\" stop-color=\"#EB5C1A\"/><stop offset=\"0.62\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/></linearGradient><linearGradient id=\"g2\" x1=\"36.46\" y1=\"13.12\" x2=\"11.14\" y2=\"12.29\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0.34\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/><stop offset=\"0.5\" stop-color=\"#EB5C1A\"/><stop offset=\"0.65\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/></linearGradient><linearGradient id=\"g3\" x1=\"18.9\" y1=\"11.28\" x2=\"18.34\" y2=\"36.85\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0.34\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/><stop offset=\"0.5\" stop-color=\"#EB5C1A\"/><stop offset=\"0.65\" stop-color=\"#EB5C1A\" stop-opacity=\"0\"/></linearGradient><linearGradient id=\"g4\" x1=\"3.66\" y1=\"3.62\" x2=\"24.21\" y2=\"24.27\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#CD3E2E\"/><stop offset=\"0.33\" stop-color=\"#EB5C1A\"/><stop offset=\"0.66\" stop-color=\"#CD3E2E\"/><stop offset=\"1\" stop-color=\"#EB5C1A\"/></linearGradient></defs></svg>";
package/dist/logo.js ADDED
@@ -0,0 +1,4 @@
1
+ /** The Mapled logo — apps/web/public/brand/logo.svg (Figma, 122×32), with
2
+ its coordinates rounded to two decimals so the sign-in page carries it
3
+ inline: the page is served from 127.0.0.1 and loads nothing. */
4
+ export const LOGO_SVG = `<svg width="122" height="32" role="img" aria-label="Mapled" viewBox="0 0 122 32.03" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M41.62 7.49H45.87L51.57 21.08H51.8L57.49 7.49H61.75V26.25H58.41V13.36H58.23L52.93 26.2H50.44L45.13 13.33H44.96V26.25H41.62V7.49Z" fill="#FEFEFE"/><path d="M67.41 26.54C66.5 26.54 65.68 26.38 64.95 26.06C64.22 25.74 63.65 25.26 63.23 24.63C62.81 24 62.6 23.23 62.6 22.3C62.6 21.51 62.75 20.85 63.05 20.33C63.35 19.81 63.76 19.4 64.27 19.09C64.79 18.78 65.38 18.54 66.03 18.38C66.68 18.22 67.36 18.1 68.06 18.02C68.9 17.94 69.59 17.86 70.11 17.8C70.64 17.72 71.02 17.61 71.26 17.47C71.5 17.31 71.62 17.08 71.62 16.76V16.71C71.62 16.02 71.41 15.48 70.99 15.1C70.57 14.72 69.97 14.53 69.18 14.53C68.35 14.53 67.69 14.71 67.21 15.07C66.73 15.42 66.4 15.84 66.23 16.32L63.07 15.88C63.32 15.03 63.73 14.31 64.3 13.74C64.88 13.16 65.58 12.72 66.41 12.44C67.24 12.14 68.16 12 69.17 12C69.86 12 70.55 12.08 71.24 12.23C71.92 12.39 72.55 12.66 73.12 13.02C73.69 13.38 74.14 13.87 74.49 14.5C74.84 15.12 75.01 15.9 75.01 16.83V26.25H71.75V24.32H71.64C71.43 24.71 71.14 25.08 70.77 25.42C70.4 25.75 69.93 26.03 69.37 26.23C68.82 26.43 68.16 26.54 67.41 26.54ZM68.29 24.1C68.98 24.1 69.57 23.97 70.07 23.7C70.57 23.44 70.95 23.08 71.22 22.64C71.49 22.2 71.63 21.72 71.63 21.2V19.55C71.52 19.63 71.34 19.71 71.09 19.78C70.84 19.86 70.56 19.92 70.24 19.98C69.93 20.03 69.62 20.08 69.32 20.12C69.01 20.17 68.74 20.2 68.52 20.23C68.01 20.3 67.56 20.41 67.16 20.56C66.76 20.71 66.45 20.93 66.21 21.2C65.98 21.47 65.87 21.82 65.87 22.25C65.87 22.86 66.1 23.32 66.55 23.63C67.01 23.94 67.59 24.1 68.29 24.1Z" fill="#FEFEFE"/><path d="M76.31 31.53V12.18H79.65V14.51H79.85C80.02 14.16 80.27 13.8 80.59 13.42C80.9 13.03 81.34 12.69 81.88 12.42C82.42 12.14 83.12 12 83.96 12C85.07 12 86.07 12.27 86.97 12.83C87.87 13.38 88.58 14.2 89.1 15.28C89.63 16.35 89.9 17.67 89.9 19.23C89.9 20.78 89.64 22.09 89.12 23.17C88.6 24.25 87.9 25.08 87 25.65C86.11 26.21 85.1 26.5 83.97 26.5C83.14 26.5 82.46 26.36 81.92 26.1C81.37 25.83 80.94 25.5 80.6 25.12C80.28 24.74 80.03 24.38 79.85 24.03H79.71V31.53H76.31ZM79.64 19.22C79.64 20.13 79.77 20.92 80.03 21.61C80.3 22.29 80.69 22.83 81.19 23.21C81.69 23.59 82.3 23.78 83.02 23.78C83.77 23.78 84.4 23.58 84.91 23.19C85.41 22.79 85.79 22.25 86.05 21.57C86.31 20.88 86.44 20.1 86.44 19.22C86.44 18.34 86.31 17.57 86.06 16.89C85.8 16.21 85.42 15.68 84.92 15.29C84.41 14.91 83.78 14.72 83.02 14.72C82.3 14.72 81.68 14.9 81.18 15.28C80.67 15.65 80.29 16.17 80.02 16.84C79.77 17.51 79.64 18.31 79.64 19.22Z" fill="#FEFEFE"/><path d="M94.09 7.49V26.25H90.69V7.49H94.09Z" fill="#FEFEFE"/><path d="M101.84 26.53C100.39 26.53 99.15 26.23 98.1 25.65C97.05 25.05 96.25 24.22 95.69 23.14C95.13 22.05 94.84 20.77 94.84 19.3C94.84 17.85 95.13 16.58 95.69 15.49C96.26 14.39 97.05 13.53 98.07 12.92C99.09 12.3 100.28 12 101.66 12C102.54 12 103.38 12.14 104.17 12.42C104.96 12.69 105.66 13.12 106.27 13.7C106.88 14.28 107.36 15.02 107.71 15.92C108.06 16.81 108.24 17.87 108.24 19.11V20.12H96.44V17.89H104.98C104.98 17.25 104.84 16.69 104.56 16.19C104.29 15.69 103.9 15.3 103.41 15.01C102.92 14.72 102.35 14.58 101.7 14.58C101.01 14.58 100.4 14.74 99.88 15.07C99.35 15.4 98.94 15.83 98.65 16.36C98.36 16.88 98.22 17.46 98.21 18.09V20.04C98.21 20.86 98.36 21.56 98.67 22.15C98.97 22.73 99.4 23.17 99.95 23.48C100.5 23.79 101.15 23.94 101.88 23.94C102.38 23.94 102.82 23.88 103.22 23.74C103.62 23.6 103.97 23.4 104.26 23.13C104.56 22.86 104.78 22.53 104.93 22.13L108.1 22.48C107.9 23.3 107.51 24.01 106.95 24.62C106.4 25.23 105.68 25.7 104.82 26.03C103.95 26.36 102.95 26.53 101.84 26.53Z" fill="#FEFEFE"/><path d="M114.34 26.5C113.2 26.5 112.19 26.21 111.3 25.65C110.41 25.08 109.7 24.25 109.18 23.17C108.66 22.09 108.4 20.78 108.4 19.23C108.4 17.67 108.67 16.35 109.19 15.28C109.72 14.2 110.44 13.38 111.34 12.83C112.24 12.27 113.24 12 114.34 12C115.19 12 115.88 12.14 116.43 12.42C116.97 12.69 117.4 13.03 117.72 13.42C118.04 13.8 118.28 14.16 118.46 14.51H118.6V7.49H122V26.25H118.66V24.03H118.46C118.28 24.38 118.03 24.74 117.7 25.12C117.37 25.5 116.93 25.83 116.39 26.1C115.84 26.36 115.16 26.5 114.34 26.5ZM115.28 23.78C116 23.78 116.61 23.59 117.12 23.21C117.62 22.83 118.01 22.29 118.27 21.61C118.53 20.92 118.66 20.13 118.66 19.22C118.66 18.31 118.53 17.51 118.27 16.84C118.01 16.17 117.63 15.65 117.13 15.28C116.63 14.9 116.01 14.72 115.28 14.72C114.53 14.72 113.9 14.91 113.39 15.29C112.88 15.68 112.5 16.21 112.25 16.89C111.99 17.57 111.86 18.34 111.86 19.22C111.86 20.1 111.99 20.88 112.25 21.57C112.51 22.25 112.89 22.79 113.4 23.19C113.91 23.58 114.54 23.78 115.28 23.78Z" fill="#FEFEFE"/><path d="M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z" fill="url(#g0)"/><path d="M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z" fill="url(#g1)"/><path d="M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z" fill="url(#g2)"/><path d="M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.8 5.28 10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.25 4.51 21.41 4.42 21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15C27.42 5.37 27.72 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39C29.36 15.46 29.05 16.52 30.25 17C30.42 17.07 30.67 17.22 30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2C20.86 28.79 19.62 30.42 18.49 32.03C18.17 31.43 17.22 29.48 16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.49 4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.15 18.39 10.24 18.27C10.35 18.14 10.39 17.97 10.36 17.8C10.28 17.39 9.58 17.02 9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.37 10.62 5.56 10.2 5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63Z" fill="url(#g3)"/><path d="M3.65 3.63C3.75 3.63 4.68 3.91 4.85 3.96L8.45 5C8.98 5.15 9.53 5.33 10.07 5.44C10.34 5.49 10.79 5.28 10.91 5.03L10.91 5.02C11.33 4.04 11.66 2.92 12.01 1.92C13.22 3.73 14.61 5.62 15.86 7.41L17.01 9.04C17.26 9.4 17.74 10.29 18.24 10.22C19.1 10.1 18.79 9.1 18.77 8.51C18.76 8.14 18.71 7.73 18.68 7.36L18.37 3.38C18.97 3.71 19.59 4.01 20.19 4.32C20.45 4.45 20.79 4.62 21.08 4.55C21.24 4.52 21.39 4.43 21.51 4.31L21.53 4.28C21.72 4.06 22.22 3.22 22.41 2.92L24.23 0.03C24.9 1.18 25.59 2.33 26.28 3.47C26.61 4.03 26.93 4.6 27.28 5.15L27.3 5.17C27.44 5.38 27.73 5.49 27.98 5.46C28.44 5.39 28.87 5.2 29.31 5.07C29.61 4.98 29.91 4.88 30.21 4.79L29.61 12.19L29.44 14.39L29.43 14.49C29.34 15.53 29.09 16.53 30.25 17C30.4 17.06 30.61 17.18 30.78 17.27L30.85 17.31L32.57 18.2C31.07 19.2 29.46 20.39 27.98 21.44L26.12 22.76C25.49 23.21 25 23.53 24.43 24.05C23.72 24.8 22.67 26.31 22.03 27.2L21.81 27.49C20.71 28.99 19.55 30.52 18.49 32.03C18.18 31.44 17.25 29.54 16.84 29.15L16.82 29.13C16.63 28.97 16.38 28.89 16.13 28.87C15.7 28.85 15.24 28.91 14.81 28.95L4.84 29.7C4.99 29.18 5.63 27.67 5.5 27.23C5.46 27.09 5.37 26.96 5.26 26.88C4.73 26.49 3.87 26.07 3.27 25.72C2.18 25.1 1.11 24.42 0 23.84L2.94 22.05C3.24 21.86 4.1 21.37 4.33 21.18C4.44 21.09 4.53 20.96 4.58 20.83C4.62 20.7 4.64 20.5 4.59 20.37L4.58 20.36C4.25 19.59 3.81 18.82 3.42 18.08L7.84 18.42C8.46 18.46 9.19 18.53 9.81 18.52C9.95 18.52 10.13 18.4 10.23 18.29L10.24 18.27C10.34 18.15 10.38 17.99 10.36 17.83L10.36 17.8C10.29 17.42 9.66 17.07 9.3 16.83L9.23 16.79L1.91 11.84C2.94 11.46 4.09 11.18 5.09 10.74C5.36 10.63 5.55 10.22 5.5 9.93L5.49 9.9C5.36 9.25 5.14 8.6 4.95 7.95L3.65 3.63ZM5.18 7.89C5.37 8.52 5.58 9.19 5.72 9.85C5.77 10.06 5.72 10.29 5.63 10.48C5.54 10.67 5.39 10.86 5.19 10.95C4.67 11.17 4.12 11.36 3.58 11.53C3.19 11.66 2.8 11.78 2.42 11.91L9.36 16.6C9.51 16.7 9.81 16.87 10.04 17.05C10.16 17.14 10.28 17.24 10.38 17.36C10.48 17.47 10.56 17.61 10.59 17.76H10.59C10.63 17.99 10.57 18.23 10.43 18.41L10.43 18.41L10.43 18.41C10.36 18.5 10.27 18.58 10.17 18.64C10.07 18.69 9.95 18.75 9.81 18.75C9.18 18.76 8.44 18.69 7.82 18.65L7.82 18.65L7.82 18.65L3.82 18.34C4.16 18.96 4.52 19.62 4.8 20.27C4.84 20.38 4.85 20.5 4.85 20.6C4.85 20.7 4.83 20.81 4.8 20.9L4.8 20.9L4.8 20.9C4.73 21.08 4.62 21.23 4.48 21.36C4.35 21.46 4.06 21.64 3.78 21.81C3.49 21.99 3.21 22.15 3.06 22.24L0.46 23.83C1.45 24.37 2.43 24.97 3.39 25.52C3.69 25.7 4.04 25.88 4.41 26.08C4.76 26.28 5.12 26.49 5.4 26.69C5.55 26.81 5.67 26.98 5.72 27.17C5.75 27.26 5.75 27.36 5.75 27.45C5.74 27.55 5.72 27.66 5.7 27.77C5.65 28 5.58 28.25 5.5 28.5C5.41 28.76 5.32 29.01 5.24 29.23C5.22 29.31 5.19 29.38 5.17 29.45L12.52 28.89H12.53L14.79 28.72C15.19 28.69 15.66 28.63 16.1 28.64L16.15 28.64L16.15 28.64C16.44 28.66 16.74 28.76 16.98 28.96C17.11 29.07 17.26 29.29 17.41 29.53C17.56 29.77 17.73 30.07 17.89 30.38C18.12 30.8 18.35 31.25 18.52 31.58C19.6 30.08 20.75 28.55 21.84 27.06C22.47 26.19 23.54 24.66 24.26 23.9L24.27 23.89L24.27 23.89C24.78 23.42 25.23 23.11 25.75 22.74L25.98 22.57L25.98 22.57L27.84 21.25L27.85 21.25C29.21 20.28 30.71 19.18 32.11 18.23L30.74 17.51L30.74 17.51C30.54 17.41 30.32 17.28 30.16 17.21C29.83 17.08 29.59 16.9 29.42 16.68C29.25 16.45 29.17 16.2 29.13 15.95C29.1 15.69 29.11 15.43 29.13 15.16C29.14 15.03 29.16 14.9 29.17 14.77C29.18 14.64 29.2 14.5 29.21 14.37L29.38 12.17L29.94 5.11C29.76 5.17 29.57 5.23 29.38 5.29C29.16 5.35 28.96 5.43 28.73 5.51C28.5 5.58 28.26 5.65 28.01 5.68L27.98 5.69C27.65 5.72 27.27 5.57 27.08 5.27C26.73 4.72 26.4 4.13 26.08 3.59C25.45 2.55 24.83 1.52 24.22 0.48L22.61 3.04H22.61C22.51 3.19 22.35 3.46 22.17 3.75C22 4.02 21.82 4.3 21.71 4.43L21.71 4.43C21.56 4.61 21.36 4.73 21.13 4.78L21.13 4.78C20.92 4.82 20.72 4.78 20.55 4.73C20.38 4.67 20.21 4.58 20.09 4.52C19.61 4.28 19.12 4.04 18.64 3.79L18.91 7.34C18.94 7.7 19 8.13 19.01 8.51V8.51C19.01 8.64 19.03 8.8 19.05 8.99C19.07 9.17 19.08 9.37 19.07 9.56C19.05 9.75 19 9.95 18.88 10.12C18.74 10.29 18.55 10.4 18.3 10.44L18.27 10.44C18.07 10.47 17.89 10.4 17.74 10.3C17.6 10.21 17.46 10.07 17.35 9.93C17.13 9.67 16.93 9.33 16.82 9.17L16.82 9.17L15.67 7.54C14.51 5.88 13.23 4.12 12.08 2.43C11.78 3.31 11.49 4.27 11.13 5.11C11.04 5.31 10.84 5.46 10.66 5.55C10.47 5.64 10.23 5.71 10.02 5.66C9.47 5.55 8.91 5.37 8.38 5.22L8.38 5.22L8.38 5.22L4.78 4.18L4.78 4.18C4.69 4.16 4.42 4.08 4.16 4C4.1 3.98 4.05 3.97 3.99 3.95L5.18 7.89Z" fill="url(#g4)"/><defs><linearGradient id="g0" x1="3.66" y1="3.62" x2="25.15" y2="25.49" gradientUnits="userSpaceOnUse"><stop stop-color="#EB5C1A"/><stop offset="1" stop-color="#CD3E2E"/></linearGradient><linearGradient id="g1" x1="27.28" y1="1.91" x2="2.36" y2="27.27" gradientUnits="userSpaceOnUse"><stop offset="0.36" stop-color="#EB5C1A" stop-opacity="0"/><stop offset="0.5" stop-color="#EB5C1A"/><stop offset="0.62" stop-color="#EB5C1A" stop-opacity="0"/></linearGradient><linearGradient id="g2" x1="36.46" y1="13.12" x2="11.14" y2="12.29" gradientUnits="userSpaceOnUse"><stop offset="0.34" stop-color="#EB5C1A" stop-opacity="0"/><stop offset="0.5" stop-color="#EB5C1A"/><stop offset="0.65" stop-color="#EB5C1A" stop-opacity="0"/></linearGradient><linearGradient id="g3" x1="18.9" y1="11.28" x2="18.34" y2="36.85" gradientUnits="userSpaceOnUse"><stop offset="0.34" stop-color="#EB5C1A" stop-opacity="0"/><stop offset="0.5" stop-color="#EB5C1A"/><stop offset="0.65" stop-color="#EB5C1A" stop-opacity="0"/></linearGradient><linearGradient id="g4" x1="3.66" y1="3.62" x2="24.21" y2="24.27" gradientUnits="userSpaceOnUse"><stop stop-color="#CD3E2E"/><stop offset="0.33" stop-color="#EB5C1A"/><stop offset="0.66" stop-color="#CD3E2E"/><stop offset="1" stop-color="#EB5C1A"/></linearGradient></defs></svg>`;
@@ -78,17 +78,43 @@ export declare function parseManifest(raw: string, file: string): {
78
78
  manifest: Manifest;
79
79
  problems: Problem[];
80
80
  };
81
- export type SchemaIndex = Map<string, {
81
+ type SubFieldEntry = {
82
82
  displayName: string;
83
- kind: string;
84
- fields: Map<string, {
83
+ type: string;
84
+ /** a component type's group sub-field (§45.4): the sub-fields of its items */
85
+ sub?: Map<string, SubFieldEntry>;
86
+ };
87
+ type FieldEntry = SubFieldEntry & {
88
+ /** a group's sub-fields */
89
+ sub?: Map<string, SubFieldEntry>;
90
+ /** the block types a components field takes (§45.4) */
91
+ allowed?: string[];
92
+ };
93
+ export type SchemaIndex = {
94
+ collections: Map<string, {
85
95
  displayName: string;
86
- type: string;
96
+ kind: string;
97
+ fields: Map<string, FieldEntry>;
98
+ /** previous key → current key (§33.5): a binding on it still works, through the alias */
99
+ aliases: Map<string, string>;
87
100
  }>;
88
- /** previous key → current key (§33.5): a binding on it still works, through the alias */
89
- aliases: Map<string, string>;
90
- }>;
101
+ /** the component types a components field names (§45.4) */
102
+ types: Map<string, {
103
+ displayName: string;
104
+ fields: Map<string, SubFieldEntry>;
105
+ }>;
106
+ };
91
107
  export declare function indexSchema(schema: Schema): SchemaIndex;
108
+ /** A binding's field as a path (§20) — the API's `fieldPath`
109
+ (lib/bindings.ts): `team.name`, a group's sub-field;
110
+ `sections[hero].heading`, a sub-field of the blocks of one type;
111
+ `sections[pricing].tiers.price`, a sub-field of the items of a
112
+ block's group sub-field; null for a field's plain key. */
113
+ export declare function fieldPath(field: string): {
114
+ head: string;
115
+ type: string | null;
116
+ rest: string[];
117
+ } | null;
92
118
  /** What a well-formed manifest still gets wrong: bindings the schema
93
119
  can't back (Mapled would grade them outdated or mismatched), files the
94
120
  repository doesn't have, pages the list doesn't know. Warnings only —
@@ -126,3 +152,4 @@ export type ManifestComparison = {
126
152
  localesDiffer: boolean;
127
153
  };
128
154
  export declare function compareManifests(local: Manifest, remote: Manifest): ManifestComparison;
155
+ export {};
package/dist/manifest.js CHANGED
@@ -30,7 +30,7 @@ export const LIMITS = { bindings: 500, pages: 200, notes: 20 };
30
30
  export const COMPATIBLE = {
31
31
  text: ["short_text", "long_text", "slug", "number", "date", "datetime", "enum", "url", "email", "color"],
32
32
  rich_text: ["rich_text", "long_text"],
33
- image: ["image"],
33
+ image: ["image", "gallery"],
34
34
  image_alt: ["short_text", "long_text"],
35
35
  link: ["short_text", "slug", "url", "email", "file"],
36
36
  number: ["number"],
@@ -45,6 +45,7 @@ export function targetFor(fieldType) {
45
45
  case "rich_text":
46
46
  return "rich_text";
47
47
  case "image":
48
+ case "gallery":
48
49
  return "image";
49
50
  case "url":
50
51
  case "email":
@@ -59,6 +60,7 @@ export function targetFor(fieldType) {
59
60
  return "boolean";
60
61
  case "relation":
61
62
  case "group":
63
+ case "components":
62
64
  case "json":
63
65
  case "location":
64
66
  return "other";
@@ -72,6 +74,7 @@ export const FIELD_TYPE_LABEL = {
72
74
  rich_text: "rich text",
73
75
  slug: "slug",
74
76
  image: "image",
77
+ gallery: "gallery",
75
78
  file: "file",
76
79
  number: "number",
77
80
  boolean: "boolean",
@@ -300,22 +303,87 @@ export function parseManifest(raw, file) {
300
303
  }
301
304
  return { manifest, problems };
302
305
  }
306
+ const subFields = (fields) => new Map(fields.map((s) => [s.key, { displayName: s.displayName, type: s.type, ...(s.group ? { sub: subFields(s.group.fields) } : {}) }]));
303
307
  export function indexSchema(schema) {
304
- const index = new Map();
308
+ const collections = new Map();
309
+ // a computed field (§14.9) binds as a field of its result type
310
+ const COMPUTED_AS = { number: "number", text: "short_text", boolean: "boolean", date: "date", datetime: "datetime" };
305
311
  for (const c of schema.collections) {
306
312
  const fields = new Map();
307
313
  const aliases = new Map();
308
- // a computed field (§14.9) binds as a field of its result type
309
- const COMPUTED_AS = { number: "number", text: "short_text", boolean: "boolean", date: "date", datetime: "datetime" };
310
314
  for (const f of c.fields) {
311
315
  const type = f.type === "computed" && f.computed ? (COMPUTED_AS[f.computed.resultType] ?? f.type) : f.type;
312
- fields.set(f.key, { displayName: f.displayName, type });
316
+ const entry = { displayName: f.displayName, type };
317
+ if (f.group)
318
+ entry.sub = subFields(f.group.fields);
319
+ if (f.components)
320
+ entry.allowed = [...f.components.allowed];
321
+ fields.set(f.key, entry);
313
322
  for (const a of f.aliases ?? [])
314
323
  aliases.set(a, f.key);
315
324
  }
316
- index.set(c.key, { displayName: c.displayName, kind: c.kind, fields, aliases });
325
+ collections.set(c.key, { displayName: c.displayName, kind: c.kind, fields, aliases });
317
326
  }
318
- return index;
327
+ const types = new Map((schema.componentTypes ?? []).map((t) => [t.key, { displayName: t.displayName, fields: subFields(t.fields) }]));
328
+ return { collections, types };
329
+ }
330
+ /** A binding's field as a path (§20) — the API's `fieldPath`
331
+ (lib/bindings.ts): `team.name`, a group's sub-field;
332
+ `sections[hero].heading`, a sub-field of the blocks of one type;
333
+ `sections[pricing].tiers.price`, a sub-field of the items of a
334
+ block's group sub-field; null for a field's plain key. */
335
+ export function fieldPath(field) {
336
+ const m = /^([^.[\]]+)(?:\[([^.[\]]+)\])?((?:\.[^.[\]]+)*)$/.exec(field);
337
+ if (!m || (m[2] === undefined && m[3] === ""))
338
+ return null;
339
+ return { head: m[1], type: m[2] ?? null, rest: m[3] === "" ? [] : m[3].slice(1).split(".") };
340
+ }
341
+ function reach(collection, key, types) {
342
+ const path = fieldPath(key);
343
+ const head = path?.head ?? key;
344
+ const renamedTo = collection.aliases.get(head) ?? null;
345
+ const field = collection.fields.get(renamedTo ?? head);
346
+ if (!field)
347
+ return { kind: "gone", why: `no field "${head}" in "${collection.displayName}"` };
348
+ if (!path || renamedTo)
349
+ return { kind: "field", type: field.type, displayName: field.displayName, renamedTo };
350
+ let sub;
351
+ if (field.sub) {
352
+ if (path.type !== null)
353
+ return { kind: "gone", why: `"${field.displayName}" is a group, not a list of blocks` };
354
+ sub = field.sub.get(path.rest[0]);
355
+ if (!sub)
356
+ return { kind: "gone", why: `no sub-field "${path.rest[0]}" in "${field.displayName}"` };
357
+ }
358
+ else if (field.allowed) {
359
+ if (path.type === null)
360
+ return { kind: "unchecked" };
361
+ const type = types.get(path.type);
362
+ if (!type)
363
+ return { kind: "gone", why: `no block type "${path.type}"` };
364
+ if (!field.allowed.includes(path.type))
365
+ return { kind: "gone", why: `"${field.displayName}" doesn't take "${type.displayName}" blocks` };
366
+ if (path.rest.length === 0)
367
+ return { kind: "unchecked" };
368
+ sub = type.fields.get(path.rest[0]);
369
+ if (!sub)
370
+ return { kind: "gone", why: `no sub-field "${path.rest[0]}" in "${type.displayName}"` };
371
+ }
372
+ else {
373
+ return { kind: "unchecked" };
374
+ }
375
+ // a block's group sub-field (§45.4): a sub-field of its items
376
+ if (sub.sub && path.rest.length > 1) {
377
+ const inner = sub.sub.get(path.rest[1]);
378
+ if (!inner)
379
+ return { kind: "gone", why: `no sub-field "${path.rest[1]}" in "${sub.displayName}"` };
380
+ if (path.rest.length > 2)
381
+ return { kind: "unchecked" };
382
+ return { kind: "field", type: inner.type, displayName: inner.displayName, renamedTo: null };
383
+ }
384
+ if (path.rest.length > 1)
385
+ return { kind: "unchecked" };
386
+ return { kind: "field", type: sub.type, displayName: sub.displayName, renamedTo: null };
319
387
  }
320
388
  function article(word) {
321
389
  return /^[aeiou]/i.test(word) ? "an" : "a";
@@ -346,23 +414,23 @@ export async function checkManifest(manifest, opts) {
346
414
  const at = `bindings[${i}]`;
347
415
  const who = `${at} (${b.key})`;
348
416
  if (index) {
349
- const collection = index.get(b.collection);
417
+ const collection = index.collections.get(b.collection);
350
418
  if (!collection)
351
419
  warn(`${at}.collection`, `${who}: no collection "${b.collection}" in the schema — Mapled marks it outdated.`);
352
420
  else if (b.field) {
353
- const field = collection.fields.get(b.field);
354
- const renamedTo = collection.aliases.get(b.field);
355
- if (!field && renamedTo) {
356
- warn(`${at}.field`, `${who}: "${b.field}" in "${collection.displayName}" was renamed to "${renamedTo}" — it still works through an alias, and Mapled marks the binding outdated. Read "${renamedTo}", then remove the alias.`);
421
+ const reached = reach(collection, b.field, index.types);
422
+ const head = fieldPath(b.field)?.head ?? b.field;
423
+ if (reached.kind === "gone") {
424
+ warn(`${at}.field`, `${who}: ${reached.why} — Mapled marks it outdated.`);
357
425
  }
358
- else if (!field) {
359
- warn(`${at}.field`, `${who}: no field "${b.field}" in "${collection.displayName}" — Mapled marks it outdated.`);
426
+ else if (reached.kind === "field" && reached.renamedTo) {
427
+ warn(`${at}.field`, `${who}: "${head}" in "${collection.displayName}" was renamed to "${reached.renamedTo}" — it still works through an alias, and Mapled marks the binding outdated. Read "${reached.renamedTo}", then remove the alias.`);
360
428
  }
361
- else {
429
+ else if (reached.kind === "field") {
362
430
  const allowed = COMPATIBLE[b.target];
363
- if (allowed && !allowed.includes(field.type)) {
364
- const label = typeLabel(field.type);
365
- warn(`${at}.target`, `${who}: "${field.displayName}" is ${article(label)} ${label} field, but the binding renders it as ${b.target.replace("_", " ")}.`);
431
+ if (allowed && !allowed.includes(reached.type)) {
432
+ const label = typeLabel(reached.type);
433
+ warn(`${at}.target`, `${who}: "${reached.displayName}" is ${article(label)} ${label} field, but the binding renders it as ${b.target.replace("_", " ")}.`);
366
434
  }
367
435
  }
368
436
  }
package/dist/media.js CHANGED
@@ -17,8 +17,10 @@ const TYPES = {
17
17
  ".gif": "image/gif",
18
18
  ".svg": "image/svg+xml",
19
19
  ".pdf": "application/pdf",
20
+ ".glb": "model/gltf-binary",
21
+ ".gltf": "model/gltf+json",
20
22
  };
21
- /** What Media's upload says: "Up to 10 MB per image"; a PDF up to 25 MB. */
23
+ /** What Media's upload says: "Up to 10 MB per image"; a PDF or a 3D model up to 25 MB. */
22
24
  const IMAGE_LIMIT = 10 * 1024 * 1024;
23
25
  const FILE_LIMIT = 25 * 1024 * 1024;
24
26
  /** Uploads in flight at once. */
@@ -57,9 +59,9 @@ async function uploadFile(session, f, root, source, run) {
57
59
  return { source, ok: false, error: "not found in the repository." };
58
60
  const mime = TYPES[path.extname(file).toLowerCase()];
59
61
  if (!mime)
60
- return { source, ok: false, error: "isn't a file Media takes: PNG, JPEG, WebP, GIF, SVG or PDF." };
62
+ return { source, ok: false, error: "isn't a file Media takes: PNG, JPEG, WebP, GIF, SVG, PDF, GLB or glTF." };
61
63
  const bytes = await readFile(file);
62
- const limit = mime === "application/pdf" ? FILE_LIMIT : IMAGE_LIMIT;
64
+ const limit = mime.startsWith("image/") ? IMAGE_LIMIT : FILE_LIMIT;
63
65
  if (bytes.length > limit)
64
66
  return { source, ok: false, error: `is larger than ${limit / 1024 / 1024} MB. Compress it and try again.` };
65
67
  if (bytes.length === 0)