@aglyn/aglyn 1.0.0-beta.244 → 1.0.0-beta.247

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 (64) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/browser-family.d.ts +49 -0
  3. package/src/lib/app-utils/browser-family.js +78 -0
  4. package/src/lib/app-utils/browser-family.js.map +1 -0
  5. package/src/lib/app-utils/contact-custom-fields.d.ts +23 -1
  6. package/src/lib/app-utils/contact-custom-fields.js +84 -2
  7. package/src/lib/app-utils/contact-custom-fields.js.map +1 -1
  8. package/src/lib/app-utils/crm.d.ts +7 -1
  9. package/src/lib/app-utils/crm.js.map +1 -1
  10. package/src/lib/app-utils/default-site.js +21 -33
  11. package/src/lib/app-utils/default-site.js.map +1 -1
  12. package/src/lib/app-utils/docs-help-sections.generated.js +14 -13
  13. package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
  14. package/src/lib/app-utils/docs-help.generated.d.ts +13 -13
  15. package/src/lib/app-utils/docs-help.generated.js +17 -6
  16. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  17. package/src/lib/app-utils/docs-index.generated.js +238 -56
  18. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  19. package/src/lib/app-utils/element-pick-protocol.d.ts +54 -0
  20. package/src/lib/app-utils/element-pick-protocol.js +41 -0
  21. package/src/lib/app-utils/element-pick-protocol.js.map +1 -0
  22. package/src/lib/app-utils/element-pick-target.d.ts +32 -0
  23. package/src/lib/app-utils/element-pick-target.js +47 -0
  24. package/src/lib/app-utils/element-pick-target.js.map +1 -0
  25. package/src/lib/app-utils/error-beacon.d.ts +115 -4
  26. package/src/lib/app-utils/error-beacon.js +180 -11
  27. package/src/lib/app-utils/error-beacon.js.map +1 -1
  28. package/src/lib/app-utils/form-contract.js +13 -6
  29. package/src/lib/app-utils/form-contract.js.map +1 -1
  30. package/src/lib/app-utils/forms.d.ts +31 -0
  31. package/src/lib/app-utils/forms.js +213 -16
  32. package/src/lib/app-utils/forms.js.map +1 -1
  33. package/src/lib/app-utils/health-report.d.ts +13 -0
  34. package/src/lib/app-utils/health-report.js +24 -0
  35. package/src/lib/app-utils/health-report.js.map +1 -1
  36. package/src/lib/app-utils/media-takedown-reach.d.ts +12 -6
  37. package/src/lib/app-utils/media-takedown-reach.js +11 -6
  38. package/src/lib/app-utils/media-takedown-reach.js.map +1 -1
  39. package/src/lib/app-utils/node-definition-sanitizer.js +12 -0
  40. package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
  41. package/src/lib/app-utils/seo-locale.d.ts +14 -0
  42. package/src/lib/app-utils/seo-locale.js +15 -0
  43. package/src/lib/app-utils/seo-locale.js.map +1 -1
  44. package/src/lib/app-utils/seo-site-scan.js +18 -3
  45. package/src/lib/app-utils/seo-site-scan.js.map +1 -1
  46. package/src/lib/app-utils/site-live-url.d.ts +24 -0
  47. package/src/lib/app-utils/site-live-url.js +60 -0
  48. package/src/lib/app-utils/site-live-url.js.map +1 -0
  49. package/src/lib/app-utils/starter-template-nodes.d.ts +13 -0
  50. package/src/lib/app-utils/starter-template-nodes.js +40 -0
  51. package/src/lib/app-utils/starter-template-nodes.js.map +1 -1
  52. package/src/lib/app-utils/starter-templates.d.ts +1 -1
  53. package/src/lib/app-utils/starter-templates.js +19 -31
  54. package/src/lib/app-utils/starter-templates.js.map +1 -1
  55. package/src/lib/plugin-manager/feature-plugins.d.ts +74 -3
  56. package/src/lib/plugin-manager/feature-plugins.js +9 -0
  57. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  58. package/src/lib/plugin-manager/plugin-ai-capabilities.d.ts +18 -0
  59. package/src/lib/plugin-manager/plugin-ai-capabilities.js.map +1 -1
  60. package/src/lib/plugin-manager/plugin-resource-drafts.d.ts +23 -0
  61. package/src/lib/plugin-manager/plugin-resource-drafts.js.map +1 -1
  62. package/src/lib/plugin-manager/stock-photo-provider.d.ts +67 -0
  63. package/src/lib/plugin-manager/stock-photo-provider.js +14 -1
  64. package/src/lib/plugin-manager/stock-photo-provider.js.map +1 -1
@@ -387,7 +387,7 @@ export const DOCS_SECTION_INDEX = [
387
387
  title: 'Build from Assist chat',
388
388
  heading: 'What one request can build',
389
389
  anchor: '#what-it-can-build',
390
- text: 'One message can ask for any mix of:\n- pages: home, about, services, contact, pricing, a landing page;\n- a header and footer shared by the pages;\n- a form: a contact form, a quote request, a sign-up form;\n- a reusable component: a card or block placed on several pages;\n- an email design, such as a welcome, a reply or an announcement, and an email campaign, drafted and left unsent;\n- a page template for blog posts, products or authors;\n- an automation: when a form is sent, do something;\n- a site function that works out a value, such as a price or a quote, and site variables, such as a phone number kept in one place;\n- products to sell, with a description, tags and options;\n- a booking service visitors can book online, with its length, hours and price;\n- an announcement bar or a popup;\n- an A/B test of a page or of an email\'s subject line;\n- a funnel that counts visits from one step to the next;\n- a change to a page or layout the site already has, saved as a new version visitors do not see until you publish it.\nOne build holds up to 16 things and 8 pages. On the Free plan it holds 2 pages, and some parts, such as templates, campaigns, automations, products and edits to existing pages, need a paid plan. The card says when your request goes past a limit; ask for the rest in a second message.'
390
+ text: 'One message can ask for any mix of:\n- pages: home, about, services, contact, pricing, a landing page;\n- a header and footer shared by the pages;\n- a form: a contact form, a quote request, a sign-up form;\n- a reusable component: a card or block placed on several pages;\n- an email design, such as a welcome, a reply or an announcement, and an email campaign, drafted and left unsent;\n- a page template for blog posts, products or authors;\n- an automation: when a form is sent, do something;\n- a site function that works out a value, such as a price or a quote, and site variables, such as a phone number kept in one place;\n- products to sell, with a description, tags and options;\n- a booking service visitors can book online, with its length, hours and price;\n- events on the site\'s calendar, each with its date and time, place, description and a cover photo, published so the Event List on your pages shows them. They need the Event Calendar add-on. See Events Calendar;\n- an announcement bar or a popup;\n- an A/B test of a page or of an email\'s subject line;\n- a funnel that counts visits from one step to the next;\n- CRM setup: a deal pipeline with its stages, custom fields on contacts, companies, deals or leads, and new values for a picklist such as lead status or source. These are saved straight to your CRM, as they are when you set them up yourself;\n- a change to a page or layout the site already has, saved as a new version visitors do not see until you publish it;\n- redirects: send an old address to a page you have, change where a redirect goes, or stop one, such as redirect /old-menu to /menu. See Redirects;\n- a change to the site\'s settings: its name, search title and description, title pattern, favicon, logo or social image (from images already in your media library), its langu'
391
391
  },
392
392
  {
393
393
  path: '/ai/assist-builds',
@@ -408,7 +408,7 @@ export const DOCS_SECTION_INDEX = [
408
408
  title: 'Build from Assist chat',
409
409
  heading: 'One job, many parts',
410
410
  anchor: '#one-job-many-parts',
411
- text: 'Everything in the plan is built by one job, each part by the same builder that makes it on its own page, in the order the parts need each other: the layout and the form before the page that places them.\n- Each part stands on its own. A part that fails does not undo the others. What depends on it is built without it, or not built, and the card says which.\n- Everything is a draft. Pages are unpublished drafts unless you ticked the publish box. Products have no photo and the price you stated, if any. Booking services and funnels are drafts to activate. Overlays and automations are switched off, A/B tests are stopped, and campaigns are unsent and aimed at nobody.\n- Names are your own. A new variable or function never takes a name the site already uses.\nWhen it is done the card says how many parts were built, such as 5 of 6 built; 1 failed. Try again what failed builds only the parts that failed, and shows what that is likely to cost.\nIf your credits run out partway, the card says Paused. What is built so far is kept. Choose Resume after you upgrade or when your credits renew, and it carries on with the next part.\nTo change something it made, ask in the chat, such as make the about page shorter. Assist opens that draft and proposes the change there.'
411
+ text: 'Everything in the plan is built by one job, each part by the same builder that makes it on its own page, in the order the parts need each other: the layout and the form before the page that places them.\n- Each part stands on its own. A part that fails does not undo the others. What depends on it is built without it, or not built, and the card says which.\n- Everything is a draft. Pages are unpublished drafts unless you ticked the publish box. Products have no photo and the price you stated, if any. Booking services and funnels are drafts to activate. Overlays and automations are switched off, A/B tests are stopped, and campaigns are unsent and aimed at nobody. The exceptions are a redirect, CRM setup, store setup, site settings, tracking tags and media library changes: a redirect rule, a CRM pipeline, custom field or picklist value, the shipping, pickup, delivery and tax settings, the site\'s settings, its tracking tags and a file\'s folder, tags, name and alt text have no draft, so they work as soon as the build saves them, as they do when you save them yourself. The plan card lists each one before you confirm, and Aglyn AI uses only the prices and rates you state.\n- Names are your own. A new variable or function never takes a name the site already uses.\n- Settings are saved live. A change to the site\'s settings has no draft: like a save in Settings, it reaches your live site as soon as that part is built. Making the site Spanish sets its language; it does not translate the pages. A value that cannot be used, such as an email address that is not one, is named on the card and the rest are saved. Assist never changes your site\'s address, domain, members, billing, plugins or cookie banner, and never hides the site from search engines. Tracking IDs change only as a tracking c'
412
412
  },
413
413
  {
414
414
  path: '/ai/assist-builds',
@@ -422,7 +422,7 @@ export const DOCS_SECTION_INDEX = [
422
422
  title: 'Build from Assist chat',
423
423
  heading: 'What it costs',
424
424
  anchor: '#what-it-costs',
425
- text: 'A build spends AI credits for each part it makes, and the card shows the estimate before you confirm. Products, booking services, overlays, A/B tests, funnels and variables cost almost nothing. If the build fails because of something on our side, the credits are given back, and the card says so. See Credits given back.'
425
+ text: 'A build spends AI credits for each part it makes, and the card shows the estimate before you confirm. Products, booking services, overlays, A/B tests, funnels, variables and CRM setup cost almost nothing, and redirects and store setup cost nothing. If the build fails because of something on our side, the credits are given back, and the card says so. See Credits given back.'
426
426
  },
427
427
  {
428
428
  path: '/ai/assist-builds',
@@ -723,7 +723,7 @@ export const DOCS_SECTION_INDEX = [
723
723
  title: 'The AI CRM built into Aglyn',
724
724
  heading: '',
725
725
  anchor: '',
726
- text: 'The AI CRM built into Aglyn\nAglyn AI works in three places in the CRM. In each one it makes a suggestion and you decide what happens next: nothing is saved, sent or imported until you do it yourself.\n- On a record\'s page, a short summary of where things stand with a contact, company, deal or lead, with a suggested next step.\n- In the email composer, a draft of the one-to-one email you describe.\n- In an import, a suggested match between the columns of your file and the fields they fill.'
726
+ text: 'The AI CRM built into Aglyn\nAglyn AI works in three places in the CRM. In each one it makes a suggestion and you decide what happens next: nothing is saved, sent or imported until you do it yourself.\n- On a record\'s page, a short summary of where things stand with a contact, company, deal or lead, with a suggested next step.\n- In the email composer, a draft of the one-to-one email you describe.\n- In an import, a suggested match between the columns of your file and the fields they fill.\nIt can also set up the CRM from the Assist chat: your deal pipelines and their stages, your custom fields, and new values for your picklists. You confirm the plan before anything is saved.'
727
727
  },
728
728
  {
729
729
  path: '/ai/crm-by-ai',
@@ -753,6 +753,13 @@ export const DOCS_SECTION_INDEX = [
753
753
  anchor: '#what-is-sent',
754
754
  text: 'The CRM decides what AI may read, and it reads the same record you would see. For a summary or an email draft, AI is given the whole record as the CRM shows it to you:\n- every standard field — for a person their name and its parts, salutation, job title, department, company, every email address, every phone and fax number, birthdate, assistant, who they report to, mailing and other address, lifecycle stage, lead source and Do not call; for a company its domain, website, phone, fax, account fields, billing and shipping address and parent company; for a deal its pipeline and stages, stage, amount, products, type, lead source, campaign, next step, probability, forecast category, the person and company it is with, and up to 10 of its contacts by name with the role each plays and which is Primary (a contact you cannot see is left out); for a lead its contact details, address, account fields, status and campaigns;\n- your picklists\' labels as the record holds them, and your custom fields, each under its label;\n- the person\'s marketing consent — opted in and since when, declined, or none recorded;\n- who owns the record and who each open task is assigned to, by name;\n- the record\'s notes (their first 600 characters);\n- its 12 newest timeline entries: the day, the kind of activity, an email\'s sender, recipient, subject and delivery state, and the first 280 characters of what was logged;\n- up to 8 open tasks with their notes and, for a contact or company, up to 5 deals.\nText you wrote is sent as written. A record that holds a great deal at once has its longest texts — notes, timeline entries, task notes and custom values — shortened to fit, and no field is left out.\nAI is never given a password, a sign-in token, an account identifier or a record\'s internal id. A related record — t'
755
755
  },
756
+ {
757
+ path: '/ai/crm-by-ai',
758
+ title: 'The AI CRM built into Aglyn',
759
+ heading: 'Set up the CRM from the chat',
760
+ anchor: '#set-up-the-crm',
761
+ text: 'Ask Assist to build your CRM setup, for example "set up a sales pipeline for my agency: Discovery, Proposal, Negotiation, Won/Lost", "add a Budget field to opportunities" or "add Renewal as a deal type". The plan card lists each pipeline, field and list of values; once you confirm, they are saved to your CRM exactly as if you had set them up yourself in Deals and Custom fields. Unlike pages and emails, they are not drafts: a pipeline and a field are in use as soon as they are saved.\n- Pipelines. A new pipeline gets the stages you list, in order, with its Won and Lost stages named as you ask (otherwise Closed Won and Closed Lost). A stage\'s win probability is the one you give, such as "Proposal at 60%", or else is spread from low to high across the stages. Your first pipeline becomes the default; a later one does only when you say so. Ask to rename a pipeline, add a stage or put stages in a new order and the pipeline you have is changed instead of a second one made.\n- Custom fields go on contacts, companies (accounts), deals (opportunities) or leads, with the CRM\'s field types: text, number, date, choice, checkbox, link and currency. An amount such as a budget is a currency field, in the currency you name ("a Budget field in euros") or US dollars when you name none.\n- Picklist values. Ask to add values to a list the CRM keeps — "add Contacted as a lead status meaning Working", "add Podcast and Webinar series as inbound lead sources", "add Renewal as a deal type", "add Platinum to the Tier choices on companies" — and they are added at the end of the list, as Add value in CRM → Fields adds them. Every picklist there can be added to, and a custom Choice field\'s choices too. A lead status names what it means (never Qualified, which only converting a lead sets); a lead source'
762
+ },
756
763
  {
757
764
  path: '/ai/crm-by-ai',
758
765
  title: 'The AI CRM built into Aglyn',
@@ -786,7 +793,7 @@ export const DOCS_SECTION_INDEX = [
786
793
  title: 'Generate a form from a description',
787
794
  heading: 'What the form gets',
788
795
  anchor: '#what-the-form-gets',
789
- text: '- Fields of the types a form supports: text, email, multiline, dropdown, radio choice, checkboxes and star rating. Each has a label, and is marked Required only when the form cannot do its job without the answer.\n- Marketing consent. When the form asks for an email address, it gets the Marketing consent field, the same one the Besigner\'s element picker adds: a Marketing emails checkbox with the single option Email me news and offers, left unticked and named as the form\'s Marketing consent field. A visitor who ticks it is recorded as consenting; submitting the form is never consent on its own. You can reword the label and the option on the form.\n- Routing. Every submission lands in the Inbox. When your brief describes each submission as a sales lead, the form also files a lead in CRM → Leads, which you can switch off on the form\'s page. When your brief asks to add people to an email list, the job tells you how: add an action on form submissions that enrolls the people who tick the consent box. The job never picks a list for you, and it never reads your lists, contacts or submissions.'
796
+ text: '- Fields of the types a form supports: text, email, multiline, dropdown, radio choice, checkboxes and star rating. Each has a label, and is marked Required only when the form cannot do its job without the answer. They are built from the Besigner\'s separate form elements, so you edit and style them like any field you add yourself.\n- Marketing consent. When the form asks for an email address, it gets the Marketing consent field, the same one the Besigner\'s element picker adds: a single Checkbox beside the words Email me news and offers, left unticked and named as the form\'s Marketing consent field. A visitor who ticks it is recorded as consenting; submitting the form is never consent on its own. You can reword the text beside the box on the form.\n- Routing. Every submission lands in the Inbox. When your brief describes each submission as a sales lead, the form also files a lead in CRM → Leads, which you can switch off on the form\'s page. When your brief asks to add people to an email list, the job tells you how: add an action on form submissions that enrolls the people who tick the consent box. The job never picks a list for you, and it never reads your lists, contacts or submissions.'
790
797
  },
791
798
  {
792
799
  path: '/ai/generate-a-form',
@@ -828,7 +835,7 @@ export const DOCS_SECTION_INDEX = [
828
835
  title: 'Generate a website from a prompt',
829
836
  heading: 'Starting a new site from a few questions',
830
837
  anchor: '#starting-a-new-site-from-a-few-questions',
831
- text: 'A site you have just created opens on its Setup page, and Start your site opens over it with one question first: how do you want to start?\n- Start from the starter site gives the site a ready-made home page with a header, footer and contact form, live at its address, for you to edit.\n- Start with AI asks a few questions instead: what kind of site you are creating, who it is for, which of the starter shapes you like, and where your contact form\'s submissions should go. It writes the brief for you and plans the site from it. Back returns to the first question.\nEach answer changes what gets built. Who the site is for is who every page\'s search listing is written for, and who the contact form asks its questions of. Where submissions go is the form\'s routing: the Inbox, or the Inbox and a lead in CRM for every message that carries an email address. You can change that on the form itself afterwards.\nSkip is in the bar at the top on both steps, and so are the close control and the Escape key. Before a site is being planned, all three do what the starter card does: the site gets the starter home page, and nothing else is created — no job, no half-built site behind you — and the site does not ask again. Once the site is being planned they only close the window; the job carries on.\nUntil one of those happens, a site that started this way has no page yet, and its address shows a short coming soon page with the site\'s name, which search engines are asked not to index.\nEvery question, step and button of the guided start is walked through on Start a new site with AI.\nOn the Free plan\nA Free workspace\'s AI start builds one or two pages: the home page and the one page your business most needs, such as services, booking or contact. Paid plans can generate more pages. The questions show '
838
+ text: 'Create site opens Start your site straight away, before the site exists. Its first step asks the site\'s name and address, and one question: how do you want to start?\n- Start from the starter site gives the site a ready-made home page with a header, footer and contact form, live at its address, for you to edit.\n- Start with AI asks a few questions instead: what kind of site you are creating, who it is for, which of the starter shapes you like, and where your contact form\'s submissions should go. It writes the brief for you and plans the site from it. Back returns to the first question.\nEach answer changes what gets built. Who the site is for is who every page\'s search listing is written for, and who the contact form asks its questions of. Where submissions go is the form\'s routing: the Inbox, or the Inbox and a lead in CRM for every message that carries an email address. You can change that on the form itself afterwards.\nNothing is created until you choose. The starter card and Skip (in the bar at the top on both steps) create the site with the starter home page. Plan my site creates the site and starts planning it. The close control and the Escape key create nothing: the window closes and no site is made. Once the site is being planned, closing only closes the window; the job carries on.\nUntil the job publishes its pages, a site that started with AI has no page yet, and its address shows a short coming soon page with the site\'s name, which search engines are asked not to index.\nEvery question, step and button of the guided start is walked through on Start a new site with AI.\nOn the Free plan\nA Free workspace\'s AI start builds one or two pages: the home page and the one page your business most needs, such as services, booking or contact. Paid plans can generate more page'
832
839
  },
833
840
  {
834
841
  path: '/ai/generate-a-site',
@@ -982,7 +989,7 @@ export const DOCS_SECTION_INDEX = [
982
989
  title: 'Functions and variables with AI',
983
990
  heading: 'Write a variable',
984
991
  anchor: '#variable',
985
- text: 'Create with AI at the top of the Variables card writes one site variable — a name, a type and a value in that type\'s stored form, such as a dictionary of plan prices {"starter":19,"pro":49}. It opens in the variable editor, unsaved.'
992
+ text: 'Create with AI at the top of the Variables card writes one site variable — a name, a type and a value, such as a dictionary of plan prices with a starter entry of 19 and a pro entry of 49. It opens in the variable editor, unsaved, with each entry in its own row.'
986
993
  },
987
994
  {
988
995
  path: '/ai/logic-with-ai',
@@ -1143,7 +1150,7 @@ export const DOCS_SECTION_INDEX = [
1143
1150
  title: 'Product copy and catalogs with AI',
1144
1151
  heading: '',
1145
1152
  anchor: '',
1146
- text: 'Product copy and catalogs with AI\nAglyn AI can write the copy for your products and help you set up a store. Everything it does is a proposal: you review it, and nothing is saved to your catalog until you apply it. It never sets a price, and it never publishes a product.'
1153
+ text: 'Product copy and catalogs with AI\nAglyn AI can write the copy for your products and help you set up a store. Everything it does is a proposal: you review it, and nothing is saved to your catalog until you apply it. A proposed product comes with a suggested price you can change, and it never publishes a product.'
1147
1154
  },
1148
1155
  {
1149
1156
  path: '/ai/products-with-ai',
@@ -1164,7 +1171,7 @@ export const DOCS_SECTION_INDEX = [
1164
1171
  title: 'Product copy and catalogs with AI',
1165
1172
  heading: 'Propose a first catalog',
1166
1173
  anchor: '#propose-a-first-catalog',
1167
- text: 'On the products page, press Create with AI beside Add product (and beside Add your first product while the catalog is empty), or Propose products in Build your catalog with AI — both open the same brief. Propose products takes a brief, such as "a candle studio: hand-poured soy candles in 8 oz and 16 oz jars, and wax melts", and proposes up to twelve products, usually six or more unless your brief says how many: each with a name, type, description, tags, options, a search listing and a sentence saying what its photo should show.\nReview the table, untick any you do not want, and press Create drafts. Each product is created as a draft:\n- It starts at a placeholder price on every variant, for you to change in the product editor. You may clear a price on purpose: the product still saves, the table marks it Set a price, and your storefront shows Price coming soon with no way to buy it until it has one again.\n- It has no photo, and the table marks it Needs a photo with the suggested shot. Nothing is uploaded or linked for you.\n- Nothing is on your storefront until you set it to Active.\nA proposed product with the same name as one already in your catalog is left out.'
1174
+ text: 'On the products page, press Create with AI beside Add product (and beside Add your first product while the catalog is empty), or Propose products in Build your catalog with AI — both open the same brief. Propose products takes a brief, such as "a candle studio: hand-poured soy candles in 8 oz and 16 oz jars, and wax melts", and proposes up to twelve products, usually six or more unless your brief says how many: each with a name, type, description, tags, options, a search listing, a sentence saying what its photo should show, and a suggested price for that kind of product, such as about $8–12 for a bar of handmade soap or $30–45 for a gift set.\nReview the table, untick any you do not want, and press Create drafts. Each product is created as a draft:\n- It starts at its suggested price on every variant (the table shows it), or at a default price where none was suggested, for you to change in the product editor. You may clear a price on purpose: the product still saves, the table marks it Set a price, and your storefront shows Price coming soon with no way to buy it until it has one again.\n- It has no photo, and the table marks it Needs a photo with the suggested shot. Nothing is uploaded or linked for you.\n- Nothing is on your storefront until you set it to Active.\nA proposed product with the same name as one already in your catalog is left out.'
1168
1175
  },
1169
1176
  {
1170
1177
  path: '/ai/products-with-ai',
@@ -1178,7 +1185,7 @@ export const DOCS_SECTION_INDEX = [
1178
1185
  title: 'Product copy and catalogs with AI',
1179
1186
  heading: 'What the copy never says',
1180
1187
  anchor: '#what-the-copy-never-says',
1181
- text: 'Every proposal is checked before you see it, and a proposal that breaks a rule is written again or not shown:\n- No health claims, such as a product that cures, treats or prevents a condition, or is clinically proven or doctor recommended.\n- No financial or legal promises, such as guaranteed returns, income, or legal compliance.\n- No certification, award or endorsement your own product text does not state. If your text says certified organic, the copy may say so too.\n- No prices you did not give, and no links, emoji or formatting marks.\nThe rules help, but you are still the publisher: read the copy before you apply it.'
1188
+ text: 'Every proposal is checked before you see it, and a proposal that breaks a rule is written again or not shown:\n- No health claims, such as a product that cures, treats or prevents a condition, or is clinically proven or doctor recommended.\n- No financial or legal promises, such as guaranteed returns, income, or legal compliance.\n- No certification, award or endorsement your own product text does not state. If your text says certified organic, the copy may say so too.\n- No prices in the text you did not give (a proposed product\'s suggested price is a field of its own, never in its copy), and no links, emoji or formatting marks.\nThe rules help, but you are still the publisher: read the copy before you apply it.'
1182
1189
  },
1183
1190
  {
1184
1191
  path: '/ai/products-with-ai',
@@ -1248,14 +1255,14 @@ export const DOCS_SECTION_INDEX = [
1248
1255
  title: 'Start a new site with AI',
1249
1256
  heading: '',
1250
1257
  anchor: '',
1251
- text: 'Start a new site with AI\nA site you have just created opens on its Setup page with Start your site over it. Start with AI asks a few questions, then plans the site, writes every page, gives it a look of its own and publishes it at its address. This page walks through each question and what happens after you choose Plan my site.\nTo scaffold pages for a site that already exists, or for several sites at once, see Generate a website from a prompt.'
1258
+ text: 'Start a new site with AI\nCreate site opens Start your site straight away, before the site exists. Start with AI asks a few questions, then creates the site, plans it, writes every page, gives it a look of its own and publishes it at its address. This page walks through each question and what happens after you choose Plan my site.\nTo scaffold pages for a site that already exists, or for several sites at once, see Generate a website from a prompt.'
1252
1259
  },
1253
1260
  {
1254
1261
  path: '/ai/start-with-ai',
1255
1262
  title: 'Start a new site with AI',
1256
1263
  heading: 'How do you want to start?',
1257
1264
  anchor: '#how-do-you-want-to-start',
1258
- text: 'The first step offers two cards:\n- Start from the starter site gives the site a ready-made home page with a header, footer and contact form, live at its address, for you to edit.\n- Start with AI (marked Recommended) asks the questions below and builds the site for you. On the Free plan the card says how many pages a Free start makes.\nSkip, the close control and the Escape key all leave the window. Before anything is being planned, leaving gives the site the starter home page and nothing else, and the site does not ask again. If you have typed or picked something, the window first asks Leave without your answers?, because what you typed is not saved. Once the site is being planned, closing only closes the window; the job carries on.'
1265
+ text: 'The first step asks for the site\'s Site name and Subdomain, its free address on Aglyn. The subdomain follows the name until you change it, and is checked as you type: if it is taken, the field says so and offers available ones to pick. Then it offers two cards:\n- Start from the starter site gives the site a ready-made home page with a header, footer and contact form, live at its address, for you to edit.\n- Start with AI (marked Recommended) asks the questions below and builds the site for you. On the Free plan the card says how many pages a Free start makes.\nNo site exists until you choose. Start from the starter site and Skip (in the bar at the top) create the site with the starter home page and open it. Plan my site creates the site and starts planning it. The close control and the Escape key create nothing: the window closes and no site is made. If you have typed or picked something, the window first asks Leave without your answers?, because what you typed is not saved. Once the site is being planned, closing only closes the window; the job carries on.\nIf your role cannot create sites, or your plan has no site left, Create site says so before asking anything. If the site is created but its planning cannot start, the window says why; leaving then gives that site the starter home page, so it is never left empty.'
1259
1266
  },
1260
1267
  {
1261
1268
  path: '/ai/start-with-ai',
@@ -1290,7 +1297,7 @@ export const DOCS_SECTION_INDEX = [
1290
1297
  title: 'Start a new site with AI',
1291
1298
  heading: 'What gets built',
1292
1299
  anchor: '#what-gets-built',
1293
- text: 'Plan my site starts the job straight away. A guided start has no plan to approve. It builds, in this order:\n1. A look: a base theme, colors, fonts and the style of buttons, cards and forms, made for your kind of site. See Looks and themes.\n2. A header and footer, as the layout every page sits in, with a link to each page.\n3. A contact form, saved on the Forms page, routed the way you chose, and placed on the page that needs it.\n4. Your first posts or products, on paid plans, when the site is a blog or a store. See A store from the start and A blog from the start.\n5. Your pages, each with its sections, its address and its own search title and description. A home page opens with a hero and has several bands below it, such as services, about, social proof and a closing call to action. Photos come from your media library or a stock photo.\n6. A welcome email draft, if you asked for one.\n7. Publishing: see Published, and found by search engines.\nContact details are never made up. A phone number, address or opening hours appear only when you have entered them in your site settings.'
1300
+ text: 'Plan my site starts the job straight away. A guided start has no plan to approve. It builds, in this order:\n1. A look: a base theme, colors, fonts and the style of buttons, cards and forms, made for your kind of site. See Looks and themes.\n2. A header and footer, as the layout every page sits in, with a link to each page.\n3. A contact form, saved on the Forms page, routed the way you chose, and placed on the page that needs it.\n4. Your first posts or products, on paid plans, when the site is a blog or a store. See A store from the start and A blog from the start. Your first events, when your business holds them and your workspace has the Event Calendar add-on. See Events from the start.\n5. Your pages, each with its sections, its address and its own search title and description. A home page opens with a hero and has several bands below it, such as services, about, social proof and a closing call to action. Photos come from your media library or a stock photo.\n6. A welcome email draft, if you asked for one.\n7. Publishing: see Published, and found by search engines.\nContact details are never made up. A phone number, address or opening hours appear only when you have entered them in your site settings.'
1294
1301
  },
1295
1302
  {
1296
1303
  path: '/ai/start-with-ai',
@@ -1332,7 +1339,7 @@ export const DOCS_SECTION_INDEX = [
1332
1339
  title: 'Start a new site with AI',
1333
1340
  heading: 'A store from the start',
1334
1341
  anchor: '#a-store-from-the-start',
1335
- text: 'On a paid plan, a site with the Online store style also gets three to six products, each with a description and a photo, and a Cart button in the header. Each product gets a placeholder starting price so it can be bought; set its real price, and your own photo, in Products. A product without a price shows Price coming soon on the store, with no Add to cart, until you give it one. See Product copy and catalogs with AI.\nIt also gets the pages every store needs, ready to use and published with the rest of the site. They do not count toward the pages you asked for:\n- Your account at /account, where shoppers sign in or create an account, see their orders with status and tracking, keep their addresses, and find the items they saved with Save on a product page. User accounts are turned on for the site.\n- Your cart at /cart, with checkout.\nThese two are set to Unlisted, so search engines don\'t index them. The policy pages below are listed like the rest of your site.\n- Shipping & returns, Privacy policy and Terms of sale, written as drafts. The facts only you know, such as your return window or where you ship from, are left in [brackets] for you to fill in. If your plan already has a shipping page, it is used instead of a second one.\nThe header links Account beside the cart, and the footer links your account and policies. When the site is built, Finish your store lists what is left: connect payments, review your products and prices, set shipping and tax, and fill in your policies, each with a button to the page where you do it.'
1342
+ text: 'On a paid plan, a site with the Online store style also gets three to six products, each with a description and a photo, and a Cart button in the header. Each product gets a suggested price for what it is, so it can be bought; review or change it, and add your own photo, in Products. A product without a price shows Price coming soon on the store, with no Add to cart, until you give it one. See Product copy and catalogs with AI.\nIt also gets the pages every store needs, ready to use and published with the rest of the site. They do not count toward the pages you asked for:\n- Your account at /account, where shoppers sign in or create an account, see their orders with status and tracking, keep their addresses, and find the items they saved with Save on a product page. User accounts are turned on for the site.\n- Your cart at /cart, with checkout.\nThese two are set to Unlisted, so search engines don\'t index them. The policy pages below are listed like the rest of your site.\n- Shipping & returns, Privacy policy and Terms of sale, written as drafts. The facts only you know, such as your return window or where you ship from, are left in [brackets] for you to fill in. If your plan already has a shipping page, it is used instead of a second one.\nThe header links Account beside the cart, and the footer links your account and policies. When the site is built, Finish your store lists what is left: connect payments, review your products and prices, set shipping and tax, and fill in your policies, each with a button to the page where you do it.'
1336
1343
  },
1337
1344
  {
1338
1345
  path: '/ai/start-with-ai',
@@ -1341,6 +1348,13 @@ export const DOCS_SECTION_INDEX = [
1341
1348
  anchor: '#a-blog-from-the-start',
1342
1349
  text: 'On a paid plan, a site with the Blog & writing style also gets a Blog collection with three posts, signed with the business name and published with the site. Each post has a cover photo, and the blog\'s index page shows the covers on its cards. See Build a blog.'
1343
1350
  },
1351
+ {
1352
+ path: '/ai/start-with-ai',
1353
+ title: 'Start a new site with AI',
1354
+ heading: 'Events from the start',
1355
+ anchor: '#events-from-the-start',
1356
+ text: 'When your business holds dated events, such as a venue, a club, a studio with classes, a meetup, a church or a theater, and your workspace has the Event Calendar add-on, the start adds your first three upcoming events to the Events page, each with a cover photo. They are dated after the day you start, in your site\'s time zone, and a day or time you gave in your description is kept as you gave it. The page about your events, or else your home page, lists them with the Event List, in one of its planned sections.\nThe events are published, so they show on your site straight away, when you have the admin or editor role on the site. With the author role they are saved as drafts, and the job says so; someone with the editor role publishes them on the Events page. Without the add-on the start adds no events. Change or delete them on the Events page like any event.'
1357
+ },
1344
1358
  {
1345
1359
  path: '/ai/start-with-ai',
1346
1360
  title: 'Start a new site with AI',
@@ -1367,7 +1381,7 @@ export const DOCS_SECTION_INDEX = [
1367
1381
  title: 'Stock photos in AI sites',
1368
1382
  heading: '',
1369
1383
  anchor: '',
1370
- text: 'Stock photos in AI sites\nWhen Aglyn AI writes the pages of a site started with AI, each picture it needs, such as a hero, a service card or a blog cover, is found as a free stock photo that matches what that part of the page is about.'
1384
+ text: 'Stock photos in AI sites\nWhen Aglyn AI writes the pages of a site started with AI, each picture it needs, such as a hero, a service card or a blog cover, is found as a free stock photo that matches what that part of the page is about. An event Aglyn AI adds gets its cover photo the same way, from the event\'s title.'
1371
1385
  },
1372
1386
  {
1373
1387
  path: '/ai/stock-photos',
@@ -1416,7 +1430,7 @@ export const DOCS_SECTION_INDEX = [
1416
1430
  title: 'Change your site\'s theme with AI',
1417
1431
  heading: '',
1418
1432
  anchor: '',
1419
- text: 'Change your site\'s theme with AI\nThe Theme assistant sits on your site\'s Setup → Theme section, above the theme editor. Describe what you want and it proposes values for the editor\'s own controls — the same colors, font, corner radius, spacing, navigation heights, dark scheme and component overrides you can set by hand. Nothing changes on your site until you save.'
1433
+ text: 'Change your site\'s theme with AI\nThe Theme assistant sits on your site\'s Setup → Theme section, above the theme editor. Describe what you want and it proposes values for the editor\'s own controls — the same colors, font, corner radius, spacing, navigation heights, dark scheme and button, input and card styles you can set by hand. Nothing changes on your site until you save.'
1420
1434
  },
1421
1435
  {
1422
1436
  path: '/ai/theme-assist',
@@ -1752,7 +1766,7 @@ export const DOCS_SECTION_INDEX = [
1752
1766
  title: 'Element catalog',
1753
1767
  heading: 'Forms',
1754
1768
  anchor: '#forms',
1755
- text: 'Forms and their fields, covered with the feature they belong to — see Forms.'
1769
+ text: 'Forms and their fields, covered in full with the feature they belong to — see Forms.\nA Form holds the fields and sends them. Each field is built from separate elements, so every piece can be selected and styled with the Styles panel on its own:\n| Element | What it\'s for |\n| Form Control | One field\'s frame: holds its Form Label, input and Helper Text. |\n| Form Label | The words naming a field, above its input. |\n| Input | A box to type in — Text, Email, Phone, Link or Number, one line or several. |\n| Helper Text | A line of guidance under a field. |\n| Select / Select Option | A dropdown and its choices. |\n| Checkbox | A tick box. Several sharing one Field name are one multi-choice question. |\n| Radio Group / Radio | A set of choices of which one may be picked. |\n| Choice Label | The words beside a Checkbox or Radio placed inside it. |\n| Rating | Stars a visitor picks. |\nThe group\'s presets put these together: Text field, Email field, Message field, Dropdown field, Radio choice field, Checkbox, Rating field and Helper Text, plus Contact Form, Contact Section and Marketing consent. Every setting is described under Field types; to design the button yourself, see Style a field.'
1756
1770
  },
1757
1771
  {
1758
1772
  path: '/building-sites/besigner/element-catalog',
@@ -1773,7 +1787,7 @@ export const DOCS_SECTION_INDEX = [
1773
1787
  title: 'Element catalog',
1774
1788
  heading: 'Input',
1775
1789
  anchor: '#input',
1776
- text: 'Buttons and widgets.\nThe calculator elements belong to no built-in feature. They come from Calculators, a plugin you install from the marketplace, and appear under Input once it is installed:\n| Element | What it\'s for |\n| Function Widget | Runs one of your no-code functions on the live site and shows what it returns — a quote calculator, a shipping estimate, a score. Function name is the function from the site\'s Functions card; the widget draws an input per parameter — a number box, a switch or a list, under the label and starting value the function sets — a run button you can relabel, and the result under a Result label prefix. Results to show lists several named results instead of one, one per line as name | Label, and Update as the visitor types recomputes on every change, so there is no button. The function runs in the visitor\'s browser: its definition, and the site variables it names, are part of the page, so keep anything private out of both. |\n| Calculator | A container bound to one of your functions. Everything inside it reads that function: place Calculator Inputs and Calculator Results anywhere in it, between whatever stacks, grids and text the design calls for. Function name is the function from the site\'s Functions card. The results are always current; there is no run button. |\n| Calculator Input | Asks one parameter of the Calculator it sits in. Ask as picks the control: Automatic follows the parameter (a list when it has choices, a number box for a number, a switch for a true/false), and Quick picks draws buttons that set the value, so 10, 25, 50, 100 can sit beside a number box on the same parameter. Choices overrides the function\'s own, as value: Label, value: Label. |\n| Calculator Result | Shows one value of the Calculator it sits in: Value is a paramet'
1790
+ text: 'Buttons and widgets.\nA Button\'s Type decides what it does inside a Form: Submit sends the form (and the Form\'s built-in button steps aside, so the one you designed is the only one), Reset clears it, and Button does nothing on its own, for buttons that run an interaction. A Button that links to a page or URL ignores its Type.\nThe calculator elements belong to no built-in feature. They come from Calculators, a plugin you install from the marketplace, and appear under Input once it is installed:\n| Element | What it\'s for |\n| Function Widget | Runs one of your no-code functions on the live site and shows what it returns — a quote calculator, a shipping estimate, a score. Function name is the function from the site\'s Functions card; the widget draws an input per parameter — a number box, a switch or a list, under the label and starting value the function sets — a run button you can relabel, and the result under a Result label prefix. Results to show lists several named results instead of one, one per line as name | Label, and Update as the visitor types recomputes on every change, so there is no button. The function runs in the visitor\'s browser: its definition, and the site variables it names, are part of the page, so keep anything private out of both. |\n| Calculator | A container bound to one of your functions. Everything inside it reads that function: place Calculator Inputs and Calculator Results anywhere in it, between whatever stacks, grids and text the design calls for. Function name is the function from the site\'s Functions card. The results are always current; there is no run button. |\n| Calculator Input | Asks one parameter of the Calculator it sits in. Ask as picks the control: Automatic follows the parameter (a list when it has choices, a number box for a number,'
1777
1791
  },
1778
1792
  {
1779
1793
  path: '/building-sites/besigner/element-catalog',
@@ -1815,7 +1829,7 @@ export const DOCS_SECTION_INDEX = [
1815
1829
  title: 'Interactions & custom HTML',
1816
1830
  heading: 'Pick the target by clicking',
1817
1831
  anchor: '#pick-the-target-by-clicking',
1818
- text: 'Any action that points at an element — open a menu, show / hide, open a drawer, scroll to element, play a video — lets you choose the target visually: click Pick element, click the element on the canvas, and confirm. No CSS selectors to write, and the picker resolves the stable data-aglyn id under the hood so the target survives edits. A custom selector field is there as a secondary option for advanced cases (a class or attribute selector you maintain yourself).\nInteraction cookbook\n- Hamburger menu: on any button, When clicked → Open/close a drawer. (The Menu Button element does this without any interaction at all.)\n- Hover menu: on a Dropdown or Mega Menu element, When hovered → Open a menu at frequency every time. Clicking already toggles every menu with zero configuration; this adds the hover-open, and the menu closes itself when the pointer leaves.\n- Hover reveal: When hovered → Show an element plus When hover ends → Hide an element, both at frequency every time.\n- Mega menu from scratch (no Mega Menu element): wrap a trigger button and a panel in one Stack (wrapper: position relative; panel: ⋮ → Start hidden until an interaction shows it, position absolute below the trigger). On the wrapper: When hovered → Show the panel, When hover ends → Hide it with a small Delay (say 250ms) so the pointer can travel; add Close on Esc to the show step for keyboard dismissal. The Dropdown Panel preset (Navigation group) inserts exactly this pattern with both interactions pre-wired — see menus & navigation.\n- Scroll reveal: on a section, When scrolled into view → Append class visible with a CSS transition, frequency once per visitor.\n- Announcement click-through: When clicked → Track analytics event plus Go to a URL.\n- "Watch the demo" button: When clicked → Scroll to element and'
1832
+ text: 'Any action that points at an element — open a menu, show / hide, open a drawer, scroll to element, play a video — lets you choose the target visually: click Pick element, click the element on the canvas, and confirm. No CSS selectors to write, and the picker resolves the stable data-aglyn id under the hood so the target survives edits. A custom selector field is there as a secondary option for advanced cases (a class or attribute selector you maintain yourself).\nInteraction cookbook\n- Hamburger menu: on any button, When clicked → Open/close a drawer. (The Menu Button element does this without any interaction at all.)\n- Hover menu: on a Dropdown or Mega Menu element, When hovered → Open a menu at frequency every time. Clicking already toggles every menu with zero configuration; this adds the hover-open, and the menu closes itself when the pointer leaves.\n- Hover reveal: When hovered → Show an element plus When hover ends → Hide an element, both at frequency every time.\n- Mega menu from scratch (no Mega Menu element): wrap a trigger button and a panel in one Stack (wrapper: position relative; panel: ⋮ → Start hidden until an interaction shows it, position absolute below the trigger). On the wrapper: When hovered → Show the panel, When hover ends → Hide it with a small Delay (say 250ms) so the pointer can travel; add Close on Esc to the show step for keyboard dismissal. The Dropdown Panel preset (Navigation group) inserts exactly this pattern with both interactions pre-wired — see menus & navigation.\n- Scroll reveal: no interaction needed. Select the section, open Attributes → Animation, pick a preset such as Slide up, and leave Plays on On scroll into view — see element animations.\n- Announcement click-through: When clicked → Track analytics event plus Go to a URL.\n- "Wat'
1819
1833
  },
1820
1834
  {
1821
1835
  path: '/building-sites/besigner/interactions-and-custom-html',
@@ -2011,7 +2025,7 @@ export const DOCS_SECTION_INDEX = [
2011
2025
  title: 'Long documents in markdown',
2012
2026
  heading: 'The Markdown element',
2013
2027
  anchor: '#the-markdown-element',
2014
- text: 'Drop Markdown from the Text group of the ELEMENTS drawer, then write or paste your document into the Content attribute.\nContent is a visual editor, not a text box. Headings, bold, italic, links, lists, quotes, images, code blocks and tables all have toolbar buttons, and the shorthands below still work as you type — start a line with ## and it becomes a heading. Pasting from a word processor or a Google Doc keeps its formatting rather than arriving as one flat paragraph.\nThe toolbar\'s Markdown switch shows the raw source instead, for when you want to paste a whole file in one go or check exactly what\'s stored. Both views edit the same text — the element stores markdown either way.\nDouble-click the element on the canvas to get the same editor over the document itself, without going to the attributes panel — the same gesture that edits any other text element in place. What you type is kept as you type it, so Done, pressing Esc, and clicking another element all leave the document saved; use undo (⌘Z) to take an edit back.\nText is set for reading rather than for a layout: 17px on a generous line height, in the theme\'s primary text color, with headings that step up in size on wider screens. You don\'t need to style anything for it to look right.\nThe element draws its Content attribute and nothing else, so it takes no child elements — there\'s no position in a parsed document an element could occupy. Dropping onto it places your element next to the Markdown block rather than inside it, the same way every other leaf element behaves. To put a picture in the document, write it as markdown — — and to put one beside the document, drop an Image as a sibling.\nWhat the markdown supports\n| You write | You get |\n| ## A heading | A top-level heading — and an anchor a contents list can link'
2028
+ text: 'Drop Markdown from the Text group of the ELEMENTS drawer, then write or paste your document into the Content attribute.\nContent is a visual editor, not a text box. Headings, bold, italic, links, lists, quotes, images, code blocks and tables all have toolbar buttons, and the shorthands below still work as you type — start a line with ## and it becomes a heading. Pasting from a word processor or a Google Doc keeps its formatting rather than arriving as one flat paragraph.\nThe toolbar\'s Markdown switch shows the raw source instead, for when you want to paste a whole file in one go or check exactly what\'s stored. Both views edit the same text — the element stores markdown either way.\nDouble-click the element on the canvas to get the same editor over the document itself, without going to the attributes panel — the same gesture that edits any other text element in place. What you type is kept as you type it, so Done, pressing Esc, and clicking another element all leave the document saved; use undo (⌘Z) to take an edit back.\nText is set for reading rather than for a layout: 17px on a generous line height, in the theme\'s primary text color, with headings that step up in size on wider screens. You don\'t need to style anything for it to look right.\nThe element draws its Content attribute and nothing else, so it takes no child elements — there\'s no position in a parsed document an element could occupy. Dropping onto it places your element next to the Markdown block rather than inside it, the same way every other leaf element behaves. To put a picture in the document, place the cursor where it goes and select the toolbar\'s Image button: type its Alt text, then select Choose from media to pick it from the site\'s media library (or paste a URL). To put one beside the document, drop an'
2015
2029
  },
2016
2030
  {
2017
2031
  path: '/building-sites/besigner/long-form-markdown',
@@ -2655,14 +2669,14 @@ export const DOCS_SECTION_INDEX = [
2655
2669
  title: 'Bindings, Variables & Functions',
2656
2670
  heading: 'Typed variables',
2657
2671
  anchor: '#typed-variables',
2658
- text: 'Create typed site variables and reference them as {{name}} in any prop. Types keep values consistent across the site.'
2672
+ text: 'Create typed site variables and reference them as {{name}} in any prop. Types keep values consistent across the site.\nA Dictionary variable holds named entries — one plan\'s name, annual price and number of sites, say. Its editor is a table: press Add entry, give the entry an Entry name, pick its Type (Text, Number or True/false) and fill in the Value. A Collection list works the same way without names: Add item adds the next value in the list, and × removes one. On a page, a bare {{name}} shows a dictionary as name: value pairs and a list comma-separated.'
2659
2673
  },
2660
2674
  {
2661
2675
  path: '/building-sites/bindings/overview',
2662
2676
  title: 'Bindings, Variables & Functions',
2663
2677
  heading: 'No-code functions',
2664
2678
  anchor: '#no-code-functions',
2665
- text: 'Build functions in the in-editor function builder with a safe evaluator — no arbitrary code execution. Compose variables and other functions, and call them inline with {{fn:name(args)}}.\nA function is parameters in, numbered if / then / otherwise steps, and one value out. Inside a step, an expression can use:\n- + - / and parentheses, on numbers; + also joins text.\n- Any site variable, by its name. A function that prices a plan can read extrasiteprice directly, so changing the variable changes every page and every calculator that uses it. A function can read a variable and never set one, and a parameter or local variable with the same name wins.\n- A dictionary variable\'s members, as name.member. Keep one dictionary per plan — {"name": "Pro", "annual": 39, "sites": 3} — and read planpro.annual. A text variable inside the function can hold a copy of one (chosen = planpro), so the function can pick a plan and then read chosen.sites.\n- These built-ins: min(a, b, …), max(a, b, …), round(value, places), floor(value), ceil(value), abs(value), and format(value, places), which writes a number with thousands separators — \'$\' + format(1396) is $1,396.\nThere are no loops and no way to add a built-in, which is what keeps the evaluator safe to run on a page.\nCreate with AI on the Functions and Variables cards writes one from a description, and a saved function\'s editor can explain, change or fix it — each opens unsaved in the editor. See Functions and variables with AI.\nThe Functions card {#functions-card}\nThe Functions card on a site\'s Logic page lists every function the site has, each with its parameters and the value it returns — press Add function to build one, or Edit to change it. Usage finds where a function is used before you change it, and Delete removes it. Your plan sets ho'
2679
+ text: 'Build functions in the in-editor function builder with a safe evaluator — no arbitrary code execution. Compose variables and other functions, and call them inline with {{fn:name(args)}}.\nA function is parameters in, numbered if / then / otherwise steps, and one value out. Each box in a step has an ƒx button beside it. Press it, choose what to Work out, and pick the values it works on — a parameter, one of the function\'s own variables, a site variable, a number or some text — then press Use formula:\n| Work out | What it does |\n| Use a value | One value as it is |\n| Add, Subtract, Multiply, Divide | Arithmetic on two or more values (Add another for more) |\n| Smallest of, Largest of | The lowest or highest of the values |\n| Round, Round down, Round up | Rounds to the Decimal places you pick, or to a whole number |\n| Without its minus sign | The value as a positive number |\n| Format as money | The amount with a currency Sign and thousands separators — 1396 reads $1,396.00 |\n| Format with thousands separators | 1234567 reads 1,234,567 |\n| Join text | Puts texts together with a space, a comma, a dash or nothing Between each |\nThe dialog shows what the box will read before you use it. When the box already holds a formula, What is there now offers it as a value, so you can build on it — add two prices, then Format as money with the sum.\nWhat a formula can read:\n- Any site variable, by its name. A function that prices a plan can read extrasiteprice directly, so changing the variable changes every page and every calculator that uses it. A function can read a variable and never set one, and a parameter or local variable with the same name wins.\n- A dictionary variable\'s entries. Keep one dictionary per plan and the ƒx picker lists each entry under the variable — planpro → annual. '
2666
2680
  },
2667
2681
  {
2668
2682
  path: '/building-sites/bindings/overview',
@@ -3203,6 +3217,13 @@ export const DOCS_SECTION_INDEX = [
3203
3217
  anchor: '#import-and-export',
3204
3218
  text: 'Import and Export sit at the top of the URL redirects card and work on the site you have open. Like adding a rule by hand, importing takes a publishing role (Editor or Admin) and a plan that includes redirects.\nExport writes every rule on the site as CSV, JSON or NDJSON. You pick the columns and their order; the default (Re-importable) puts the Aglyn ID first so the file can come back in and update the same rules. Deleted rules are never exported.\nImport takes a CSV, JSON or NDJSON file of up to 5,000 rules.\nColumns\n| Column | What it holds |\n| -- | -- |\n| Aglyn ID | The rule\'s ID. Exported, and used on import to find the rule; never changed by a file. |\n| From path | Required for a new rule. A path like /old-page, saved the way the manager saves it: lowercase, without a trailing slash or a query string. For a regular expression rule, the pattern. |\n| Kind | exact, prefix or regex; Path prefix and Regular expression work too. Blank means exact. |\n| To | Required for a new rule. A path on your site or an https:// address. |\n| Status code | 301, 302, 307 or 308. Blank means 302. |\n| Priority | A whole number; lower fires first. Blank means 100. |\n| Enabled | Yes or no. Blank means on. |\n| Hits in the last 30 days, Last hit, Off-site destination approved by, Created, Updated, Created by | Exported only. |\nColumns from Shopify (Redirect from, Redirect to), the WordPress Redirection plugin (source, target, code), Yoast SEO (Origin, Target, Type), Wix (Old URL, New URL) and Webflow (Old path, Redirect to path) are recognized by name.\nHow a row finds an existing rule\n1. By its Aglyn ID, when the file has that column (an exported file does).\n2. Otherwise by its from path within its kind, read the way the manager saves it, so /Old-Page/ finds the exact rule for /old-page. An exa'
3205
3219
  },
3220
+ {
3221
+ path: '/building-sites/redirects/overview',
3222
+ title: 'Redirects',
3223
+ heading: 'Ask Aglyn AI',
3224
+ anchor: '#ask-aglyn-ai',
3225
+ text: 'You can ask Aglyn Assist for a redirect in plain words, such as redirect /old-menu to /menu, send /shop to my store page or stop redirecting /promo. The plan card lists each one, and Confirm plan saves it.\n- A redirect Aglyn AI makes is checked exactly as one you save: the same publishing role, plan and limit, the same loop and duplicate checks, and the same review of an off-site destination. It also never sends visitors into a loop other rules already make.\n- It works as soon as it is saved, like one you save yourself. It is 302 unless you say the move is permanent.\n- It never redirects the address of a published page unless you ask for that page to send visitors elsewhere.\n- To change or stop a redirect, name its address. Stopping one deletes it, as Delete does on this page.\n- It costs no AI credits.'
3226
+ },
3206
3227
  {
3207
3228
  path: '/building-sites/redirects/overview',
3208
3229
  title: 'Redirects',
@@ -3509,7 +3530,7 @@ export const DOCS_SECTION_INDEX = [
3509
3530
  title: 'SEO Toolkit',
3510
3531
  heading: 'SEO check',
3511
3532
  anchor: '#seo-check',
3512
- text: 'Setup → SEO starts with an SEO check card. Press Run the check and it reads every page your sitemap lists — every published page whose visibility is Public, without template pages or error pages — and lists what a search result or a crawler would find wrong. The check is part of every plan and needs no add-on. It changes nothing on your site: fix what it finds in each page\'s SEO card or in the designer, publish, and run it again.\nEach page is checked as it is published: the headings, text, images and links of the reusable components it places count as the page\'s own, with the values that placement gives them, and so do the rows a repeated element shows. A finding about something a component draws points at the component on the page; fix it in the component or in the values the page gives it.\nA very large site is checked on its first 150 pages, and the card says how many it left out. For each page it checks:\n| Check | What counts as a finding |\n| Search title | Missing, over 60 characters, or the same as another page\'s. A title with variables is checked as it renders. |\n| Search description | Missing, over 155 characters, or the same as another page\'s. |\n| Main heading | No h1, more than one, or one that says little (Home, Welcome, a single short word). |\n| Images | An image with no description. |\n| Links | No other page or shared layout links to the page. The home page never counts. |\n| Target keywords | A keyword you named that the page never says. |\nIt also checks the site as a whole: whether search engines are asked to stay away, whether your structured data names and describes who publishes the site, and whether your /llms.txt carries guidance of your own.\nEach page gets a score out of 100 — a finding takes off more the more it matters — and the site\'s score is the '
3533
+ text: 'Setup → SEO starts with an SEO check card. Press Run the check and it reads every page your sitemap lists — every published page whose visibility is Public, without template pages or error pages — and lists what a search result or a crawler would find wrong. The check is part of every plan and needs no add-on. It changes nothing on your site: fix what it finds in each page\'s SEO card or in the designer, publish, and run it again.\nEach page is checked as it is published: the headings, text, images and links of the reusable components it places count as the page\'s own, with the values that placement gives them, and so do the rows a repeated element shows. A finding about something a component draws points at the component on the page; fix it in the component or in the values the page gives it.\nA very large site is checked on its first 150 pages, and the card says how many it left out. For each page it checks:\n| Check | What counts as a finding |\n| Search title | Missing, over 60 characters, or the same as another page\'s. A title with variables is checked as it renders. |\n| Search description | Missing, over 155 characters, or the same as another page\'s. |\n| Main heading | No h1, more than one, or one that says little (Home, Welcome, a single short word). |\n| Images | An image with no description. |\n| Links | No other page or shared layout links to the page. The home page never counts. |\n| Target keywords | A keyword you named that the page never says. |\nIt also checks the site as a whole: whether search engines are asked to stay away, whether your structured data names and describes who publishes the site, and whether your /llms.txt carries guidance of your own.\nThe result opens with the site\'s Launch status: hidden while Discourage search engines is on, otherwise open to'
3513
3534
  },
3514
3535
  {
3515
3536
  path: '/building-sites/seo/overview',
@@ -4160,7 +4181,7 @@ export const DOCS_SECTION_INDEX = [
4160
4181
  title: 'Edit your theme',
4161
4182
  heading: 'Style components',
4162
4183
  anchor: '#style-components',
4163
- text: 'Component overrides restyle MUI components site-wide beyond the palette and type. The editor takes MUI\'s component theme API as JSON, keyed by component (MuiButton, MuiOutlinedInput, MuiCard, MuiAlert…):\n- defaultProps — a prop\'s default, e.g. { "variant": "outlined" }.\n- styleOverrides — literal CSS per slot. "padding": 8 is 8px.\n- sx — the same per-slot styles in theme terms, resolved separately for light and dark: palette paths ("borderColor": "divider", "bgcolor": "primary.main"), spacing units ("px": 2 is 16px), radius multiples ("borderRadius": 2), shadow levels ("boxShadow": 3) and whole text styles ("typography": "button"). Use it for anything that should follow the scheme.\n- variants — styles that apply only when props match, e.g. { "props": { "variant": "outlined" }, "sx": { "borderWidth": 2 } }.\nYour overrides are added to the platform\'s own component styles rather than replacing them, so the contrast fixes the platform applies to buttons and links stay in place.'
4184
+ text: 'The Style components card sets how buttons, form inputs and cards look across the whole site. Pick each from a list; the preview updates as you go, and nothing changes on your site until you press Save.\nButtons\n- Button style — Filled, Outlined or Text only, for every button that does not pick a style of its own.\n- Button corners — from Square through multiples of your site\'s Border radius to a Pill.\n- Button text case — As typed, UPPERCASE or Capitalize Each Word.\n- Button text weight — Regular, Medium, Semibold or Bold.\n- Button padding — Compact, Comfortable, Roomy or Wide, in steps of your site\'s Spacing unit.\nForm inputs\n- Input style — Outlined (a box with a border) or Filled (a shaded box with a line underneath).\n- Input corners — the same corner choices as buttons.\n- Input background — None, or one of your theme\'s colors: Paper, Background or a tint.\n- Input border color — Divider, Secondary text, Text, or one of your brand colors.\nCards\n- Card style — Shadow or Outline, for every card that does not pick its own.\n- Card shadow depth — Flat, Soft, Medium or Strong.\n- Card corners — the same corner choices, without the pill.\nColors are your theme\'s colors, not fixed values, so they follow the visitor\'s light or dark scheme and change when you change the palette. Corners and padding follow the Shape & spacing card the same way. Theme default on any of these keeps the look your theme ships with.\nA single button, input or card you style in the Besigner keeps its own settings; these choices set the look of everything you have not styled one by one.\nAdvanced, at the bottom of the card, lists everything styled on your site beyond the choices above, such as a change the Theme assistant proposed for another component. Reset to theme defaults there removes all of it, inclu'
4164
4185
  },
4165
4186
  {
4166
4187
  path: '/building-sites/theme-builder/edit-your-theme',
@@ -4223,7 +4244,7 @@ export const DOCS_SECTION_INDEX = [
4223
4244
  title: 'Bookings & Scheduling',
4224
4245
  heading: 'Set up bookings',
4225
4246
  anchor: '#set-up-bookings',
4226
- text: 'The Services card on the site\'s Bookings page defines what visitors can book: each service\'s length, price and the weekly hours it is offered in.\n1. Select Add service and enter its Name, Duration (minutes) and Price (0 is free). A paid service needs Stripe connected first (see above); Show the price as offers a label such as a free estimate instead — see Price labels.\n2. Choose the service\'s Timezone and, under Weekly availability, the days and hours slots are offered.\n3. Under Booking form, choose whether to ask for a phone number or an address — see Asking for a phone number and an address.\n4. Select Save service. A service you add here is active at once.\n5. Add the booking widget to a page as a canvas element, so visitors can pick a service and a time.\nDraft services {#draft-services}\nA service is either active — it takes bookings — or a draft: set up, and offered nowhere. A draft is left out of the booking widget\'s list, shows no open times, and a booking for it is refused, even through a link that names it.\n- A service you add with Add service is active as soon as you save it.\n- A service set up for you elsewhere in Aglyn, rather than added on this page, starts as a draft, so nothing goes live before you have looked at it. If no price was given, it is set to Contact for price.\n- On the Bookings page a draft carries a Draft label and an Activate button. Activate puts it on your site straight away.\n- Deactivate turns an active service back into a draft: it stops taking bookings without being deleted, and the bookings it already has stay.\nA draft counts toward your plan\'s service allowance, like an active service.\nPrice varies, free estimate, or contact for price {#price-labels}\nA service that is quoted at the job doesn\'t need a price. In the service\'s dialog, Show t'
4247
+ text: 'The Services card on the site\'s Bookings page defines what visitors can book: each service\'s length, price and the weekly hours it is offered in.\n1. Select Add service and enter its Name, Duration (minutes) and Price (0 is free). A paid service needs Stripe connected first (see above); Show the price as offers a label such as a free estimate instead — see Price labels.\n2. Choose the service\'s Timezone. Under Weekly availability, switch on each day slots are offered and pick the From and To times; select Add hours for a second block on the same day, such as after lunch.\n3. Under Booking form, choose whether to ask for a phone number or an address — see Asking for a phone number and an address.\n4. Select Save service. A service you add here is active at once.\n5. Add the booking widget to a page as a canvas element, so visitors can pick a service and a time.\nDraft services {#draft-services}\nA service is either active — it takes bookings — or a draft: set up, and offered nowhere. A draft is left out of the booking widget\'s list, shows no open times, and a booking for it is refused, even through a link that names it.\n- A service you add with Add service is active as soon as you save it.\n- A service set up for you elsewhere in Aglyn, rather than added on this page, starts as a draft, so nothing goes live before you have looked at it. If no price was given, it is set to Contact for price.\n- On the Bookings page a draft carries a Draft label and an Activate button. Activate puts it on your site straight away.\n- Deactivate turns an active service back into a draft: it stops taking bookings without being deleted, and the bookings it already has stay.\nA draft counts toward your plan\'s service allowance, like an active service.\nPrice varies, free estimate, or contact for price {#pr'
4227
4248
  },
4228
4249
  {
4229
4250
  path: '/commerce-and-bookings/bookings/overview',
@@ -4265,7 +4286,7 @@ export const DOCS_SECTION_INDEX = [
4265
4286
  title: 'Product catalog',
4266
4287
  heading: 'Products, options, and variants',
4267
4288
  anchor: '#products-options-and-variants',
4268
- text: 'A product is what you manage; a variant is what a customer actually buys. Products define up to 3 options (like Size or Color, each with up to 25 values), and the products hub expands them into a variants matrix — up to 100 variants per product, each with its own SKU, barcode, price, compare-at price, weight, image, and inventory count.\n- Types: physical (shippable), digital (delivered as downloads), or service.\n- Status: draft (invisible to visitors), active, or archived. A product created for you rather than added in the editor — a proposed product, for one — starts as a draft with no photo, and its price stays empty unless one was given. It counts toward your plan\'s product allowance like any other product.\n- Pricing: a variant with a compare-at price above its price shows a sale badge on storefront blocks.\n- Inventory: leave blank for untracked, 0 means sold out — the same semantics the original product block used. Stock is not tracked on a digital or service subscription-only product: nothing decrements it, on the first charge or on any renewal, so the field is disabled there. A physical subscription tracks normally — every paid cycle decrements one unit per box shipped — and Both — buyer chooses keeps tracking on the one-time sales.\nProducts created with the earlier single-price product block are lifted into this model automatically as a single default variant — nothing breaks and no migration step is needed.'
4289
+ text: 'A product is what you manage; a variant is what a customer actually buys. Products define up to 3 options (like Size or Color, each with up to 25 values), and the products hub expands them into a variants matrix — up to 100 variants per product, each with its own SKU, barcode, price, compare-at price, weight, image, and inventory count.\n- Types: physical (shippable), digital (delivered as downloads), or service.\n- Status: draft (invisible to visitors), active, or archived. A product created for you rather than added in the editor — a proposed product, for one — starts as a draft with no photo, at the price it was given (an AI proposal\'s suggested price) or else a default price, for you to change. It counts toward your plan\'s product allowance like any other product.\n- Pricing: a variant with a compare-at price above its price shows a sale badge on storefront blocks.\n- Inventory: leave blank for untracked, 0 means sold out — the same semantics the original product block used. Stock is not tracked on a digital or service subscription-only product: nothing decrements it, on the first charge or on any renewal, so the field is disabled there. A physical subscription tracks normally — every paid cycle decrements one unit per box shipped — and Both — buyer chooses keeps tracking on the one-time sales.\nProducts created with the earlier single-price product block are lifted into this model automatically as a single default variant — nothing breaks and no migration step is needed.'
4269
4290
  },
4270
4291
  {
4271
4292
  path: '/commerce-and-bookings/commerce/catalog',
@@ -4279,7 +4300,7 @@ export const DOCS_SECTION_INDEX = [
4279
4300
  title: 'Product catalog',
4280
4301
  heading: 'Write and propose with AI',
4281
4302
  anchor: '#ai',
4282
- text: 'Aglyn AI can write a product\'s description, search listing and tags from what it says and shows, write copy for many products or an import at once, propose a first catalog from a brief, and propose categories and discounts. Every proposal is reviewed before it is saved. Proposed products are created as drafts with their prices left empty, and proposed discounts are created switched off. See Products with AI.'
4303
+ text: 'Aglyn AI can write a product\'s description, search listing and tags from what it says and shows, write copy for many products or an import at once, propose a first catalog from a brief, and propose categories and discounts. Every proposal is reviewed before it is saved. Proposed products are created as drafts at their suggested prices, and proposed discounts are created switched off. See Products with AI.'
4283
4304
  },
4284
4305
  {
4285
4306
  path: '/commerce-and-bookings/commerce/catalog',
@@ -4300,7 +4321,7 @@ export const DOCS_SECTION_INDEX = [
4300
4321
  title: 'Product catalog',
4301
4322
  heading: 'Product reviews',
4302
4323
  anchor: '#product-reviews',
4303
- text: 'The Review moderation card, in the products hub\'s Promotions section, holds the reviews shoppers leave on your products until you approve or reject them. Pro plan and above.\n1. Add a Product reviews block to your product page template, so shoppers can rate a product from 1 to 5 and write a review with their email address.\n2. Each new review waits on the card under Show: Pending. A Verified label means that email has a paid order for the product.\n3. Select Approve to publish a review, or Reject to keep it off your site. Reply adds your answer under it.\nOnly approved reviews show on your site, with the product\'s average rating. Switch Show to Approved, Rejected or All to look back.'
4324
+ text: 'Shoppers rate a product from 1 to 5 and write a review in the Product reviews block on your product page template. Pro plan and above.\nReview settings {#review-settings}\nThe Reviews card in Settings decides who can review your products and when customers are asked for a review.\nWho can review. By default only customers who bought the product can review it, and their reviews show a Verified buyer badge. A customer is verified when they are signed in to their account on your store with the email their order went to, or when they open the link in their review-request email. Typing an email address into the form never verifies anyone. Everyone else sees "Only customers who bought this can review" and a Sign in link. To accept reviews from anyone, set Who can review to Anyone on the Reviews card in Settings: verified buyers still publish right away, and everyone else gives a name and an email (never shown) and waits for your approval.\nThe review-request email. A set number of days after an order is fulfilled (7 by default, anywhere from 3 to 30), the buyer gets one email asking for a review, with a link for each product on the order. Each link works once, for 60 days, and only for that order, product and buyer. Items that were refunded are left out, and register sales are never asked. The email respects unsubscribes and your suppression list. Turn it off or change the delay on the Reviews card, and change its wording under Emails → Review request.\nReview moderation {#review-moderation}\nThe Review moderation card, in the products hub\'s Promotions section, lists your reviews so you can publish, hide and reply to them:\n1. Verified reviews publish as soon as they are written, good or bad. You can Hide one only for a content reason: spam or advertising, abusive or hateful languag'
4304
4325
  },
4305
4326
  {
4306
4327
  path: '/commerce-and-bookings/commerce/catalog',
@@ -4489,7 +4510,7 @@ export const DOCS_SECTION_INDEX = [
4489
4510
  title: 'Fulfillment, returns and webhooks',
4490
4511
  heading: 'Order webhooks',
4491
4512
  anchor: '#order-webhooks',
4492
- text: 'An order webhook posts each order event to an address you choose, as it happens: a warehouse system, an ERP, a spreadsheet script. Add them under Settings → Order webhooks in the Products hub. Managing webhooks needs the admin role and organization-wide membership, the same as refunds.\nAdd endpoint asks for:\n- Endpoint URL — an https:// address on a public server. Redirects are not followed, so give the final address.\n- Events — any of the events below.\nWhen you add an endpoint, its signing secret is shown once. Copy it into your endpoint\'s settings; Roll secret makes a new one if it is lost. A store can keep 10 endpoints. Pause stops deliveries to one without deleting it, and Send test event posts a webhook.test event now.\n| Event | When |\n| order.paid | An order was paid: online, buy-now, a payment link, a POS sale or a subscription renewal. |\n| order.fulfilled | A shipment was recorded, once per shipment. |\n| order.delivered | The order was marked delivered. |\n| order.refunded | Money went back to the buyer, once per refund, including a refund made in the Stripe Dashboard. |\n| order.cancelled | The order was canceled. |\n| return.requested | A buyer asked for a return, or you opened one. |\n| return.approved | You approved a return, or opened one yourself. |\n| return.declined | You declined a return request. |\n| return.received | The returned items arrived. |\n| return.refunded | A return was refunded. |\nWhat your endpoint receives\nA POST with a JSON body:\ndata.order is the order in the same shape the API returns for GET /v1/sites/{siteId}/orders/{orderId}. Money is in whole cents. Three headers come with it:\n| Header | What it holds |\n| Aglyn-Event | The event, e.g. order.paid. |\n| Aglyn-Event-Id | The event\'s id. It is the same on every retry, so store it and ignore a'
4513
+ text: 'An order webhook posts each order event to an address you choose, as it happens: a warehouse system, an ERP, a spreadsheet script. Add them under Settings → Order webhooks in the Products hub. Managing webhooks needs the admin role and organization-wide membership, the same as refunds.\nAdd endpoint asks for:\n- Endpoint URL — an https:// address on a public server. Redirects are not followed, so give the final address.\n- Events — any of the events below.\nWhen you add an endpoint, its signing secret is shown once. Copy it into your endpoint\'s settings; Roll secret makes a new one if it is lost. A store can keep 10 endpoints. Pause stops deliveries to one without deleting it, and Send test event posts a webhook.test event now.\n| Event | When |\n| order.paid | An order was paid: online, buy-now, a payment link, a POS sale or a subscription renewal. |\n| order.fulfilled | A shipment was recorded, once per shipment. |\n| order.delivered | The order was marked delivered. |\n| order.refunded | Money went back to the buyer, once per refund, including a refund made in the Stripe Dashboard. |\n| order.cancelled | The order was canceled. |\n| return.requested | A buyer asked for a return, or you opened one. |\n| return.approved | You approved a return, or opened one yourself. |\n| return.declined | You declined a return request. |\n| return.received | The returned items arrived. |\n| return.refunded | A return was refunded. |\nWhen an endpoint is down\nAn endpoint has 8 seconds to answer each event. One that doesn\'t is sent the event again, on a schedule that lasts about a day, and the site\'s managers are told if the last try fails.\nWhoever builds your endpoint needs Order webhooks for developers: what each event carries and how to check that it came from your store.\nDeliveries on an endpoint '
4493
4514
  },
4494
4515
  {
4495
4516
  path: '/commerce-and-bookings/commerce/orders-and-returns',
@@ -4552,7 +4573,7 @@ export const DOCS_SECTION_INDEX = [
4552
4573
  title: 'Commerce',
4553
4574
  heading: 'Shipping & taxes',
4554
4575
  anchor: '#shipping--taxes',
4555
- text: '- Shipping zones own countries (\'\' = rest of world); rates are flat, free-over-subtotal, or subtotal/weight tiers; optional local pickup. See Shipping.\n- Taxes: manual per-region rates (state beats country, VAT-style inclusive pricing supported) or Stripe Tax automatic calculation; products can be tax-exempt.\nTax settings {#tax-settings}\nThe Taxes card, in the store\'s settings, decides how your store charges sales tax: rates you enter, Stripe Tax, or none at all. Checkout stays off until you choose an option and save, so no order is taken that cannot be taxed correctly.\n1. Choose the Calculation:\n- Manual rates — you enter the rates.\n- Stripe Tax (automatic) — Stripe works out the tax for each buyer\'s location at checkout. Activate Stripe Tax in your Stripe dashboard first.\n- Don\'t collect sales tax — no tax is added to any order, and orders still go through. Choose it when you have no obligation to collect.\n2. For manual rates, enter the Origin country and Origin state: where the store ships or sells from. It is not the address Aglyn bills your workspace at, and not where your payouts go.\n3. Select Add rate for each region you collect in: a Country, an optional State, the rate in % and the Label buyers see. A state rate beats a country rate.\n4. Turn on Prices include tax if your prices already include it, VAT-style.\n5. Optionally set a Lodging tax rate for reservations (see below) and a Service tax rate for paid bookings (see Bookings).\n6. Select Save tax settings.\nWhat the store has collected is reported on the Storefront sales tax card. A store that uses Avalara or TaxJar sets that up separately: see Tax services.\nLodging tax on reservations\nA stay is not goods. The sales-tax settings above configure a goods rate resolved against an address; occupancy (lodging/hotel)'
4576
+ text: '- Shipping zones own countries (\'\' = rest of world); rates are flat, free-over-subtotal, or subtotal/weight tiers; optional local pickup. See Shipping.\n- Taxes: manual per-region rates (state beats country, VAT-style inclusive pricing supported) or Stripe Tax automatic calculation; products can be tax-exempt.\nTax settings {#tax-settings}\nThe Taxes card, in the store\'s settings, decides how your store charges sales tax: rates you enter, Stripe Tax, or none at all. Checkout stays off until you choose an option and save, so no order is taken that cannot be taxed correctly.\n1. Choose the Calculation:\n- Manual rates — you enter the rates.\n- Stripe Tax (automatic) — Stripe works out the tax for each buyer\'s location at checkout. Activate Stripe Tax in your Stripe dashboard first.\n- Don\'t collect sales tax — no tax is added to any order, and orders still go through. Choose it when you have no obligation to collect.\n2. For manual rates, enter the Origin country and Origin state: where the store ships or sells from. It is not the address Aglyn bills your workspace at, and not where your payouts go.\n3. Select Add rate for each region you collect in: a Country, an optional State, the rate in % and the Label buyers see. A state rate beats a country rate.\n4. Turn on Prices include tax if your prices already include it, VAT-style.\n5. Optionally set a Lodging tax rate for reservations (see below) and a Service tax rate for paid bookings (see Bookings).\n6. Select Save tax settings.\nWhat the store has collected is reported on the Storefront sales tax card. A store that uses Avalara or TaxJar sets that up separately: see Tax services.\nAsk Aglyn AI. You can ask Aglyn Assist to set up tax, such as charge 8.25% Texas sales tax, we sell from Austin, calculate tax automatically or we don\'t co'
4556
4577
  },
4557
4578
  {
4558
4579
  path: '/commerce-and-bookings/commerce/overview',
@@ -4615,14 +4636,14 @@ export const DOCS_SECTION_INDEX = [
4615
4636
  title: 'Pickup & local delivery',
4616
4637
  heading: 'Set up pickup',
4617
4638
  anchor: '#set-up-pickup',
4618
- text: 'Pickup is turned on per location, on the Inventory locations card in the store\'s settings, so buyers can collect orders there at the hours you set. On a location\'s row, choose Pickup, then:\n1. Turn on Buyers can pick up orders here.\n2. Enter the Pickup hours, one line per set of days, like Mo-Fr 09:00-17:00 and Sa 10:00-14:00. A line that doesn\'t read as days and times is flagged before you save.\n3. Add Arrival instructions if buyers need them, such as which door to use.\n4. Choose how long an order is Usually ready in, or leave it unsaid.\nGive the location an address too (Add address on its row), so buyers know where to go. Every location with pickup on is offered at the cart, with your default location first.\nWhen a buyer picks up at a location, that location\'s stock is reserved while they check out and sold from that location when they pay. If the location doesn\'t have enough, the cart says so and the buyer can choose another location or have it shipped. Canceling the order puts the stock back at the same location.\nThe Offer free local pickup switch on the Shipping card is the older, unnamed pickup choice. Once any location offers pickup, the cart uses your locations instead.'
4639
+ text: 'Pickup is turned on per location, on the Inventory locations card in the store\'s settings, so buyers can collect orders there at the hours you set. On a location\'s row, choose Pickup, then:\n1. Turn on Buyers can pick up orders here.\n2. Under Pickup hours, switch on each day buyers can collect, then pick the From and To times. For a split day, such as a lunch break, select Add hours on that day.\n3. Add Arrival instructions if buyers need them, such as which door to use.\n4. Choose how long an order is Usually ready in, or leave it unsaid.\nGive the location an address too (Add address on its row), so buyers know where to go. Every location with pickup on is offered at the cart, with your default location first.\nWhen a buyer picks up at a location, that location\'s stock is reserved while they check out and sold from that location when they pay. If the location doesn\'t have enough, the cart says so and the buyer can choose another location or have it shipped. Canceling the order puts the stock back at the same location.\nThe Offer free local pickup switch on the Shipping card is the older, unnamed pickup choice. Once any location offers pickup, the cart uses your locations instead.'
4619
4640
  },
4620
4641
  {
4621
4642
  path: '/commerce-and-bookings/commerce/pickup-and-local-delivery',
4622
4643
  title: 'Pickup & local delivery',
4623
4644
  heading: 'Set up local delivery',
4624
4645
  anchor: '#set-up-local-delivery',
4625
- text: 'The Local delivery card, in the store\'s settings, lets your own driver deliver orders: buyers enter their postal code at the cart, pay your fee and book a delivery time. To set it up:\n1. Turn on Deliver orders yourself and enter the two-letter Country you deliver in.\n2. Optionally choose the location orders Leave from. Its stock is reserved and sold for delivery orders.\n3. Add one or more Zones. A zone lists the postal codes it covers: exact codes such as 10001, a prefix ending in such as 100, or a range such as 10010-10020. Each zone has its own Fee, an optional Minimum order and an optional Free over amount. When a postal code is in more than one zone, the zone listed first is used.\n4. Enter your Delivery windows, one per line, like Mo-Fr 09:00-12:00. Each line is offered on each of its days.\n5. Choose how long before a window an order must be placed (Order at least) and how many days ahead buyers can book.\n6. Optionally add What buyers should know, such as "We text when we\'re 10 minutes away." It shows at the cart and on the receipt.\nThe card lists anything that stops checkout from offering delivery, such as a zone with no postal codes or no delivery windows.\nAt the cart, the buyer enters their postal code and sees the fee, or why delivery isn\'t available, such as an order below the zone\'s minimum. Checkout charges the fee as the order\'s shipping and asks for an address in your country only. If the address the buyer then enters is outside all of your zones, the order is flagged and you\'re notified, so you can contact the buyer or refund the delivery.'
4646
+ text: 'The Local delivery card, in the store\'s settings, lets your own driver deliver orders: buyers enter their postal code at the cart, pay your fee and book a delivery time. To set it up:\n1. Turn on Deliver orders yourself and enter the two-letter Country you deliver in.\n2. Optionally choose the location orders Leave from. Its stock is reserved and sold for delivery orders.\n3. Add one or more Zones. A zone lists the postal codes it covers: exact codes such as 10001, a prefix ending in such as 100, or a range such as 10010-10020. Each zone has its own Fee, an optional Minimum order and an optional Free over amount. When a postal code is in more than one zone, the zone listed first is used.\n4. Under Delivery windows, switch on each day you deliver and pick a window\'s From and To times. Select Add window for a second window on the same day. Each window is offered on its day.\n5. Choose how long before a window an order must be placed (Order at least) and how many days ahead buyers can book.\n6. Optionally add What buyers should know, such as "We text when we\'re 10 minutes away." It shows at the cart and on the receipt.\nThe card lists anything that stops checkout from offering delivery, such as a zone with no postal codes or no delivery windows.\nAt the cart, the buyer enters their postal code and sees the fee, or why delivery isn\'t available, such as an order below the zone\'s minimum. Checkout charges the fee as the order\'s shipping and asks for an address in your country only. If the address the buyer then enters is outside all of your zones, the order is flagged and you\'re notified, so you can contact the buyer or refund the delivery.'
4626
4647
  },
4627
4648
  {
4628
4649
  path: '/commerce-and-bookings/commerce/pickup-and-local-delivery',
@@ -4631,6 +4652,13 @@ export const DOCS_SECTION_INDEX = [
4631
4652
  anchor: '#queue',
4632
4653
  text: 'The Pickup & delivery card on the Orders page lists what needs doing, soonest first:\n| Tab | What\'s in it |\n| -- | -- |\n| To prepare | Pickup orders you haven\'t marked ready. |\n| Ready for pickup | Pickup orders waiting to be collected. |\n| To deliver | Local deliveries, by delivery time. |\n| Out for delivery | Deliveries your driver has taken out. |\n| Delivery failed | Deliveries that couldn\'t be completed, to send out again. |\nPick a location at the top of the card to see only that location\'s orders. Each row has its next step as a button, and Open shows the whole order. The same steps are in the order\'s dialog.\n| Step | What happens |\n| -- | -- |\n| Mark ready | The buyer gets the Order ready for pickup email with the location, your pickup hours and instructions. Not ready yet takes it back. |\n| Picked up | The order is fulfilled and delivered, and the buyer gets a short confirmation. |\n| Out for delivery | The buyer gets the Order out for delivery email with their delivery time. |\n| Delivered | The order is fulfilled and delivered, and the buyer gets the Order delivered email. |\n| Couldn\'t deliver | The delivery moves to Delivery failed, with an optional note. Send it out again when you\'re ready. |\nEach email is sent once per step, and each can be turned off on the Customer notifications card. When text messages are available, buyers can add a mobile number at the cart to get these updates by text as well. Picked up and delivered orders count as fulfilled for your reports, outbound webhooks and accounting, exactly like shipped ones.\nThe buyer\'s order status page shows where to pick up, the pickup hours, or the delivery time, and each step as it happens.'
4633
4654
  },
4655
+ {
4656
+ path: '/commerce-and-bookings/commerce/pickup-and-local-delivery',
4657
+ title: 'Pickup & local delivery',
4658
+ heading: 'Ask Aglyn AI',
4659
+ anchor: '#ask-aglyn-ai',
4660
+ text: 'You can ask Aglyn Assist to set up pickup or delivery, such as offer local pickup at our Austin shop, weekdays 9 to 5 or deliver to 78701 and 78702 for $5, free over $75, weekday mornings. The plan card lists each change, and Confirm plan saves it.\n- Pickup is turned on for one of your inventory locations, found by its name, city or street. Aglyn AI never adds a location: add it first, then ask. Without a location, it turns on the store-wide Offer free local pickup choice.\n- Local delivery uses postal-code zones. Aglyn AI turns delivery on only when checkout can offer it: a country, at least one zone and at least one delivery window. Distance zones need your store placed on the map, so you set those up yourself.\n- It uses only the fees and times you give.\n- Changes work as soon as they are saved, and cost no AI credits.\n- Only an admin or editor on the site can ask Aglyn AI for these changes. An author can still make them on the card.'
4661
+ },
4634
4662
  {
4635
4663
  path: '/commerce-and-bookings/commerce/pickup-and-local-delivery',
4636
4664
  title: 'Pickup & local delivery',
@@ -5037,6 +5065,13 @@ export const DOCS_SECTION_INDEX = [
5037
5065
  anchor: '#zones-and-rates',
5038
5066
  text: 'The Shipping card, in the store\'s settings, prices every parcel: group the countries you ship to into zones, then give each zone one or more rates.\n1. Under Zones, select Add zone, enter a Zone name and its Countries as two-letter codes, such as US, CA, or for everywhere else.\n2. Under Rates, select Add rate, choose its Zone, give it a Name buyers see (a rate without one is dropped at checkout), and choose its Type and price.\n3. Optionally turn on Offer free local pickup.\n4. Check the Coverage line, which names any destination no rate reaches, then select Save shipping settings.\nA zone owns countries; is the rest of the world. A rate belongs to one zone and prices a parcel in one of four ways:\n| Rate type | What the shopper pays |\n| -- | -- |\n| Flat | One price. |\n| Free over subtotal | One price, or nothing once the cart reaches the subtotal you set. |\n| Subtotal tiers | The price of the first tier the cart\'s subtotal fits under. |\n| Weight tiers | The price of the first tier the cart\'s weight fits under. Weight is each variant\'s weight times its quantity. |\nLocal pickup adds a free collection choice beside your rates. It does not widen where you ship: a destination no rate reaches is still refused. To let buyers choose which location to collect from, with pickup hours and a ready-for-pickup email, turn on pickup for the location instead: see Pickup & local delivery.\nCheckout charges only the rates of the zone the destination falls in, and narrows the address it collects to that destination, so a shopper cannot pick another zone\'s cheaper rate. The destination coverage rules explain what your zones make checkout ask and refuse.'
5039
5067
  },
5068
+ {
5069
+ path: '/commerce-and-bookings/commerce/shipping',
5070
+ title: 'Shipping',
5071
+ heading: 'Ask Aglyn AI',
5072
+ anchor: '#ask-aglyn-ai',
5073
+ text: 'You can ask Aglyn Assist to set up shipping in plain words, such as free shipping over $50, otherwise $5 flat in the US, add $15 express to Canada or stop shipping to the UK. The plan card lists each change, and Confirm plan saves it.\n- Aglyn AI saves exactly what this card saves: a zone with its countries, and a flat, free-over-subtotal, subtotal-tier or weight-tier rate in it. A zone or rate you already have is changed in place, found by its name.\n- It uses only the prices you give. A rate you do not price is not added; Aglyn AI asks instead.\n- If the change leaves some destinations with no rate, the build says so, as the Coverage line does.\n- Carrier rates need a carrier account, so you set those up yourself.\n- Changes work as soon as they are saved, like a save on this card. They cost no AI credits.\n- Only an admin or editor on the site can ask Aglyn AI for these changes. An author can still make them on the card.'
5074
+ },
5040
5075
  {
5041
5076
  path: '/commerce-and-bookings/commerce/shipping',
5042
5077
  title: 'Shipping',
@@ -5798,14 +5833,14 @@ export const DOCS_SECTION_INDEX = [
5798
5833
  title: 'Custom fields',
5799
5834
  heading: '',
5800
5835
  anchor: '',
5801
- text: 'Custom fields\nA contact carries a fixed set of properties — name, email, tags, notes, and the CRM\'s own owner, lifecycle stage and company; a company its domain, address and industry; a deal its amount, stage and close date; a lead the person and their company as text. Custom fields add the properties your business describes each of them by: an annual revenue, a tier, a renewal date, a VIP checkbox, a link to a profile.\nA field is defined once for the whole organization, for one kind of record — see fields per record. It then appears on every record of that kind, as an optional column on that kind\'s list, and on the REST API; a contact field is also a destination a form field can save into. Definitions are shared across every site in the organization, like the records themselves; the values a site records on a contact are that site\'s own view of the person.\nPlan availability Custom fields are part of the CRM, included from Starter. On Free the Fields section is shown locked, with the rest of the CRM. See What each plan includes.'
5836
+ text: 'Custom fields\nA contact carries a fixed set of properties — name, email, tags, notes, and the CRM\'s own owner, lifecycle stage and company; a company its domain, address and industry; a deal its amount, stage and close date; a lead the person and their company as text. Custom fields add the properties your business describes each of them by: an annual revenue, a budget in euros, a tier, a renewal date, a VIP checkbox, a link to a profile.\nA field is defined once for the whole organization, for one kind of record — see fields per record. It then appears on every record of that kind, as an optional column on that kind\'s list, and on the REST API; a contact field is also a destination a form field can save into. Definitions are shared across every site in the organization, like the records themselves; the values a site records on a contact are that site\'s own view of the person.\nPlan availability Custom fields are part of the CRM, included from Starter. On Free the Fields section is shown locked, with the rest of the CRM. See What each plan includes.'
5802
5837
  },
5803
5838
  {
5804
5839
  path: '/content-and-data/crm/custom-fields',
5805
5840
  title: 'Custom fields',
5806
5841
  heading: 'Define a field',
5807
5842
  anchor: '#define-a-field',
5808
- text: 'Open CRM → Fields, pick the tab for the record the field describes — Contacts, Companies, Deals or Leads — and choose New field.\n- Label — how the field reads everywhere it shows.\n- Key — derived from the label as you type (Annual revenue becomes annualrevenue); edit it to choose your own. A key starts with a letter and uses lowercase letters, digits and underscores, up to 40 characters. Values are stored under the key, so it cannot change once the field exists — a rename is a new field and a retirement of the old one.\n- Type — Text, Number, Date, Choice, Checkbox or Link. Every value is read by its type, so the type is fixed once the field exists.\n- Choices — for a Choice field, one per line. A stored value has to be one of them.\n- Required on the … form — the record\'s page will not save the field empty. It does not make a website form field required; that is set on the form itself.\nEach tab is the console\'s list table: it pages, sorts by Field, Key or Type, filters by Type and Required from its Filters panel, and searches a field\'s name and key. It opens in the order fields appear on a record and in the list\'s columns, numbered under Order; the arrows on each row move a field up or down. The order is the record\'s, not a view of the list, so the arrows are live only while the list shows it — with a sort, a filter or a search in force they wait, and say Clear sorting and filters to reorder.\nHow many records carry a value under each field is not counted. That would read every record in the organization each time the page opened, so the list says so rather than showing a number it cannot keep true.'
5843
+ text: 'Open CRM → Fields, pick the tab for the record the field describes — Contacts, Companies, Deals or Leads — and choose New field.\n- Label — how the field reads everywhere it shows.\n- Key — derived from the label as you type (Annual revenue becomes annualrevenue); edit it to choose your own. A key starts with a letter and uses lowercase letters, digits and underscores, up to 40 characters. Values are stored under the key, so it cannot change once the field exists — a rename is a new field and a retirement of the old one.\n- Type — Text, Number, Date, Choice, Checkbox, Link or Currency. Every value is read by its type, so the type is fixed once the field exists.\n- Choices — for a Choice field, one per line. A stored value has to be one of them.\n- Currency — for a Currency field, the currency every amount in it is in: USD, EUR, GBP and the other currencies a deal\'s amount offers. It starts at USD and is fixed once the field exists — see currency fields.\n- Required on the … form — the record\'s page will not save the field empty. It does not make a website form field required; that is the Required? switch on the field\'s input in the Besigner.\nEach tab is the console\'s list table: it pages, sorts by Field, Key or Type, filters by Type and Required from its Filters panel, and searches a field\'s name and key. It opens in the order fields appear on a record and in the list\'s columns, numbered under Order; the arrows on each row move a field up or down. The order is the record\'s, not a view of the list, so the arrows are live only while the list shows it — with a sort, a filter or a search in force they wait, and say Clear sorting and filters to reorder.\nHow many records carry a value under each field is not counted. That would read every record in the organization each time the pa'
5809
5844
  },
5810
5845
  {
5811
5846
  path: '/content-and-data/crm/custom-fields',
@@ -5819,14 +5854,21 @@ export const DOCS_SECTION_INDEX = [
5819
5854
  title: 'Custom fields',
5820
5855
  heading: 'Where values show',
5821
5856
  anchor: '#where-values-show',
5822
- text: '- A contact\'s page carries its fields in the Properties card, under More fields after the built-in properties, with one control per field — a text box, a number box, a date picker, a choice list, a checkbox or a link box. The card\'s one Save, in its header, writes the profile and only the fields you changed; clearing a control clears the value. With no field defined, there is no More fields at all.\n- The contacts list offers one optional column per field. The columns show the value as it reads — a date as a day, a checkbox as Yes or No, a link as a link. They do not sort; each is a field in the table\'s Filters panel — see Filters on the Contacts list.\n- A lead\'s page carries its fields in the Details card, under More fields after the profile and saved with it by the same Save in the card\'s header. The New lead drawer offers the same controls, so a lead can be entered complete. A converted lead\'s are read-only with the rest of the record. The leads list offers one optional column per field.\n- A company\'s page and a deal\'s list their fields under More fields, after the built-in properties; Edit changes them.\n- Exports and the API carry the values under their keys.\nA value belongs to the site that recorded it. Two sites in one organization that both know a person each see their own values, never each other\'s.'
5857
+ text: '- A contact\'s page carries its fields in the Properties card, under More fields after the built-in properties, with one control per field — a text box, a number box, a date picker, a choice list, a checkbox, a link box or an amount box with the currency beside it. The card\'s one Save, in its header, writes the profile and only the fields you changed; clearing a control clears the value. With no field defined, there is no More fields at all.\n- The contacts list offers one optional column per field. The columns show the value as it reads — a date as a day, a checkbox as Yes or No, a link as a link, an amount as money ("€1,250.00"). They do not sort; each is a field in the table\'s Filters panel — see Filters on the Contacts list.\n- A lead\'s page carries its fields in the Details card, under More fields after the profile and saved with it by the same Save in the card\'s header. The New lead drawer offers the same controls, so a lead can be entered complete. A converted lead\'s are read-only with the rest of the record. The leads list offers one optional column per field.\n- A company\'s page and a deal\'s list their fields under More fields, after the built-in properties; Edit changes them.\n- Exports and the API carry the values under their keys.\nA value belongs to the site that recorded it. Two sites in one organization that both know a person each see their own values, never each other\'s.'
5858
+ },
5859
+ {
5860
+ path: '/content-and-data/crm/custom-fields',
5861
+ title: 'Custom fields',
5862
+ heading: 'Currency fields',
5863
+ anchor: '#currency-fields',
5864
+ text: 'A Currency field holds an amount of money — a budget, a contract value, a price quoted — in the one currency the field was made with. Every value in the field is in that currency, so its column on a list reads as one currency throughout.\n- Typing an amount. The box takes the amount as you would write it — 1250.50, $1,250.50, 1,250 — with the currency shown beside it. Symbols, codes and thousands separators are ignored; more decimals than the currency has are rounded (19.995 USD is $20.00). A negative amount is allowed, for a discount or a credit.\n- How it reads. Everywhere a value shows — a record\'s page, a list column — it is formatted as money in your browser\'s locale.\n- How it is stored. As a whole number of the currency\'s smallest unit — cents for USD, yen for JPY — the way a deal\'s amount is. That is the number the REST API reads and writes under the field\'s key: send 125050 for $1,250.50, or send the amount as text ("1250.50") and it is read as dollars.\n- Filtering contacts. A contact currency field\'s filter asks equals an amount, typed as you would type it, or is not empty.\n- Import and export. A file carries the amount as a plain number in the field\'s currency — 1250.5 — and an import reads it back the same way. The Fields export lists each currency field\'s currency.\nA field\'s currency cannot be changed once it exists, because its values are counts of that currency\'s smallest unit. To track a second currency, add a second field.\nThere is no organization-wide currency setting, so a new Currency field always starts at USD; pick another before you create it.'
5823
5865
  },
5824
5866
  {
5825
5867
  path: '/content-and-data/crm/custom-fields',
5826
5868
  title: 'Custom fields',
5827
5869
  heading: 'Save a form field into a custom field',
5828
5870
  anchor: '#save-a-form-field',
5829
- text: 'On a form\'s own page (Forms → the form), Saves to contact fields lists every field the published design declares, with a choice beside each. Pick a custom field and every submission\'s answer to that form field is stored under it on the contact the submission creates or updates.\nAnswers arrive as text and are converted by the field\'s type:\n| Field type | What is stored |\n| Text, Link | The trimmed answer. A Link has to be an http(s) URL, or nothing is stored. |\n| Number | The number. An answer that is not one number is dropped rather than stored as text. |\n| Date | The date, as an ISO 8601 stamp, whichever way the visitor typed it. |\n| Choice | The answer, only when it is one of the field\'s choices exactly. |\n| Checkbox | true or false, from what a ticked or unticked box sends. |\nAn answer left blank writes nothing — a submission never clears a value you set by hand. A mapping onto a retired field writes nothing either.\nMappings are kept by field name across publishes: redrawing the form and publishing a new version does not lose them. A field renamed on the canvas is a new field and starts unmapped; a field removed takes its mapping with it.\nThe sender\'s name and email are recognized from the field name — see who a submission is from — and never need mapping.'
5871
+ text: 'On a form\'s own page (Forms → the form), Saves to contact fields lists every field the published design declares, with a choice beside each. A field is listed by the Field name of the element a visitor answers with — an Input, Select, Radio Group, Checkbox or Rating (see Field types) — and several Checkboxes sharing one Field name are one field. Pick a custom field and every submission\'s answer to that form field is stored under it on the contact the submission creates or updates.\nAnswers arrive as text and are converted by the field\'s type:\n| Field type | What is stored |\n| Text, Link | The trimmed answer. A Link has to be an http(s) URL, or nothing is stored. |\n| Number | The number. An answer that is not one number is dropped rather than stored as text. |\n| Date | The date, as an ISO 8601 stamp, whichever way the visitor typed it. |\n| Choice | The answer, only when it is one of the field\'s choices exactly. |\n| Checkbox | true or false, from what a ticked or unticked box sends. |\n| Currency | The amount, read in the field\'s currency — "1,250.50" or "$1,250.50". An answer that is not one amount is dropped. |\nAn answer left blank writes nothing — a submission never clears a value you set by hand. A mapping onto a retired field writes nothing either.\nMappings are kept by field name across publishes: redrawing the form and publishing a new version does not lose them. An element whose Field name you change on the canvas is a new field and starts unmapped; a field removed takes its mapping with it.\nThe sender\'s name and email are recognized from the field name — see who a submission is from — and never need mapping.'
5830
5872
  },
5831
5873
  {
5832
5874
  path: '/content-and-data/crm/custom-fields',
@@ -5840,7 +5882,7 @@ export const DOCS_SECTION_INDEX = [
5840
5882
  title: 'Custom fields',
5841
5883
  heading: 'Over the API',
5842
5884
  anchor: '#over-the-api',
5843
- text: 'The /v1/contacts, /v1/companies, /v1/deals and /v1/leads resources each carry custom, an object keyed by field key — {} on a record that has none, so a client can index it without a guard. Each resource is judged against the definitions of its own record: a company body is validated against the company fields, whatever a contact field of the same key holds.\n- POST and PATCH accept custom. Values are converted by type exactly as a form answer is.\n- A PATCH merges the keys it sends and keeps the rest; send null under a key to clear it.\n- A key that is not a field of that record, a field that is retired, or a value the type cannot hold is refused with 400 validationfailed and named in fields as custom. — nothing is stored from that request.'
5885
+ text: 'The /v1/contacts, /v1/companies, /v1/deals and /v1/leads resources each carry custom, an object keyed by field key — {} on a record that has none, so a client can index it without a guard. Each resource is judged against the definitions of its own record: a company body is validated against the company fields, whatever a contact field of the same key holds.\n- POST and PATCH accept custom. Values are converted by type exactly as a form answer is. A currency field\'s value is a whole number of its currency\'s smallest unit (125050 is $1,250.50), and text is read as an amount ("1250.50"); a response carries the stored number.\n- A PATCH merges the keys it sends and keeps the rest; send null under a key to clear it.\n- A key that is not a field of that record, a field that is retired, or a value the type cannot hold is refused with 400 validationfailed and named in fields as custom. — nothing is stored from that request.'
5844
5886
  },
5845
5887
  {
5846
5888
  path: '/content-and-data/crm/custom-fields',
@@ -5854,7 +5896,7 @@ export const DOCS_SECTION_INDEX = [
5854
5896
  title: 'Custom fields',
5855
5897
  heading: 'Export your fields',
5856
5898
  anchor: '#export-fields',
5857
- text: 'Export… at the top of the Fields section writes every custom field you defined as a file — its name, key, the record it describes, its type, its choices, whether it is required, its position and whether it is retired — through the export dialog: a record of your setup, to document it or to rebuild it elsewhere. Fields are defined here, so the file is never imported. Their values travel with each record\'s own export.'
5899
+ text: 'Export… at the top of the Fields section writes every custom field you defined as a file — its name, key, the record it describes, its type, a currency field\'s currency, its choices, whether it is required, its position and whether it is retired — through the export dialog: a record of your setup, to document it or to rebuild it elsewhere. Fields are defined here, so the file is never imported. Their values travel with each record\'s own export.'
5858
5900
  },
5859
5901
  {
5860
5902
  path: '/content-and-data/crm/custom-fields',
@@ -6197,7 +6239,7 @@ export const DOCS_SECTION_INDEX = [
6197
6239
  title: 'CRM',
6198
6240
  heading: 'What\'s in the CRM area',
6199
6241
  anchor: '#whats-in-the-crm-area',
6200
- text: '| Section | Address | What lives there |\n| Contacts | /crm/contacts | Every person your site may see, as a list with Owner and Stage columns, filters and search; a person\'s own page is /crm/contacts/{id}. import and export, bulk actions, saved views and the timeline live here too. |\n| Leads | /crm/leads | People a site has captured but not yet qualified — a status, an owner and notes on each, and a conversion into a contact, a company and a deal. CSV import and export too. |\n| Companies | /crm/companies | The organizations your contacts belong to, keyed by domain — a captured contact is linked to the company at their email domain on its own; a company\'s page is /crm/companies/{id}. import and export and bulk actions too. |\n| Deals | /crm/deals | The sales pipeline — open deals by stage, with an amount, an owner and an expected close, as a board or a table with export and bulk actions; a deal\'s page is /crm/deals/{id}. |\n| Tasks | /crm/tasks | Calls, emails, meetings and to-dos by due date, each linked to the contact, company or deal it is for, with export and bulk actions. |\n| Reports | /crm/reports | New contacts over time, sources and the lifecycle funnel, conversion by source, the lead funnel, the open pipeline and its forecast, won and lost, activity by teammate, and the task load — every table exportable as CSV. |\n| Fields | /crm/fields | The custom fields on a contact — text, number, date, choice, checkbox or link — which a form field can save into. |\n| Settings | /crm/settings | What the CRM does on its own for every site in the workspace — whether a company is created from a captured contact\'s work email domain — and the email templates your team sends from a record. |\nThree things cut across the sections rather than having one of their own. Saved views keep a l'
6242
+ text: '| Section | Address | What lives there |\n| Contacts | /crm/contacts | Every person your site may see, as a list with Owner and Stage columns, filters and search; a person\'s own page is /crm/contacts/{id}. import and export, bulk actions, saved views and the timeline live here too. |\n| Leads | /crm/leads | People a site has captured but not yet qualified — a status, an owner and notes on each, and a conversion into a contact, a company and a deal. CSV import and export too. |\n| Companies | /crm/companies | The organizations your contacts belong to, keyed by domain — a captured contact is linked to the company at their email domain on its own; a company\'s page is /crm/companies/{id}. import and export and bulk actions too. |\n| Deals | /crm/deals | The sales pipeline — open deals by stage, with an amount, an owner and an expected close, as a board or a table with export and bulk actions; a deal\'s page is /crm/deals/{id}. |\n| Tasks | /crm/tasks | Calls, emails, meetings and to-dos by due date, each linked to the contact, company or deal it is for, with export and bulk actions. |\n| Reports | /crm/reports | New contacts over time, sources and the lifecycle funnel, conversion by source, the lead funnel, the open pipeline and its forecast, won and lost, activity by teammate, and the task load — every table exportable as CSV. |\n| Fields | /crm/fields | The custom fields on a contact — text, number, date, choice, checkbox, link or currency — which a form field can save into. |\n| Settings | /crm/settings | What the CRM does on its own for every site in the workspace — whether a company is created from a captured contact\'s work email domain — and the email templates your team sends from a record. |\nThree things cut across the sections rather than having one of their own. Saved view'
6201
6243
  },
6202
6244
  {
6203
6245
  path: '/content-and-data/crm/overview',
@@ -6820,7 +6862,7 @@ export const DOCS_SECTION_INDEX = [
6820
6862
  title: 'Build a data model',
6821
6863
  heading: 'Define the model',
6822
6864
  anchor: '#define-the-model',
6823
- text: '1. In Data, create a dataset and open the schema dialog.\n2. Add typed fields — text, number, date, reference, page address, and more.\n3. Save. The model is stored on the dataset. Every write validates records against it — the console, the REST API, a bound form and an automation step — and stores each value as its field\'s type. A record with a value that doesn\'t fit is not written.\nDisplay name vs reference ID\nEvery field has two names:\n- Display name — the human label shown in the record editor, table headers, and anywhere the field appears. Rename it any time.\n- Reference ID — the stable key used in bindings ({{item.referenceid}}), form field mappings, and CSV import/export.\nWhen you create a field, the Reference ID auto-fills from the display name (for example, Roast preference → roastpreference). Edit it in the same dialog to set your own — handy when you want a short, code-friendly key that differs from the label. Once the field is created the ID is fixed: records, bindings, and forms all point at it, so it can\'t change without orphaning that data. Pick it deliberately, then rename the display name freely afterward.\nPage address fields {#page-address-fields}\nA Page address field holds a record\'s own segment of its address when the dataset has a record template: kitchen-remodeling, roof-repair. Pick Page address in the field\'s type list. Its values are lowercase letters and numbers joined by hyphens, up to 64 characters.\n- Fill in from names a text field, such as Name, that an empty address is made from. It fills in once, when a record is first saved without one, and a record keeps its address when it\'s renamed, so a live page never moves.\n- Whatever writes the record — the console, an import, the REST API, a form or an automation — the address is filled in the same'
6865
+ text: '1. In Data, create a dataset and open the schema dialog.\n2. Add typed fields — text, number, date, reference, image, page, page address, and more.\n3. Save. The model is stored on the dataset. Every write validates records against it — the console, the REST API, a bound form and an automation step — and stores each value as its field\'s type. A record with a value that doesn\'t fit is not written.\nDisplay name vs reference ID\nEvery field has two names:\n- Display name — the human label shown in the record editor, table headers, and anywhere the field appears. Rename it any time.\n- Reference ID — the stable key used in bindings ({{item.referenceid}}), form field mappings, and CSV import/export.\nWhen you create a field, the Reference ID auto-fills from the display name (for example, Roast preference → roastpreference). Edit it in the same dialog to set your own — handy when you want a short, code-friendly key that differs from the label. Once the field is created the ID is fixed: records, bindings, and forms all point at it, so it can\'t change without orphaning that data. Pick it deliberately, then rename the display name freely afterward.\nPage address fields {#page-address-fields}\nA Page address field holds a record\'s own segment of its address when the dataset has a record template: kitchen-remodeling, roof-repair. Pick Page address in the field\'s type list. Its values are lowercase letters and numbers joined by hyphens, up to 64 characters.\n- Fill in from names a text field, such as Name, that an empty address is made from. It fills in once, when a record is first saved without one, and a record keeps its address when it\'s renamed, so a live page never moves.\n- Whatever writes the record — the console, an import, the REST API, a form or an automation — the address is fille'
6824
6866
  },
6825
6867
  {
6826
6868
  path: '/content-and-data/datasets/model-builder',
@@ -6997,6 +7039,13 @@ export const DOCS_SECTION_INDEX = [
6997
7039
  anchor: '#show-events-on-a-screen',
6998
7040
  text: 'Events reach visitors through the Event List canvas element (Data display category) — drop it on any page in the Besigner and set:\n- Heading — a title above the list; empty hides it.\n- Show — Upcoming (default) or Past events.\n- Max items — how many to render (default 10).\nUpcoming lists the next events by start time; past lists the most recent first. The list is served through the public events API and cached briefly at the CDN, so a newly published event can take about a minute to appear.'
6999
7041
  },
7042
+ {
7043
+ path: '/content-and-data/events/overview',
7044
+ title: 'Events Calendar',
7045
+ heading: 'Ask Aglyn AI',
7046
+ anchor: '#ask-aglyn-ai',
7047
+ text: 'Aglyn AI can add events for you, such as add our autumn sourdough workshops, and a site started with AI for a business that holds events adds its first three. The events are listed on the page you name, or a page about them the request makes; if neither exists, an Events page at /events is added to your site\'s menu to list them. Each event gets a title, a start and end in your business\'s time zone, a place, an organizer and a description, and a stock photo as its cover, copied into your media library. A page section that shows them gets the Event List.\nEvents Aglyn AI adds are published, the same as Set published, when you have the admin or editor role on the site, so they show on your site straight away. With the author role they are saved as drafts, and the job says so. Edit, unpublish or delete them on the Events page like any other event. Adding events needs the Event Calendar add-on.'
7048
+ },
7000
7049
  {
7001
7050
  path: '/content-and-data/events/overview',
7002
7051
  title: 'Events Calendar',
@@ -7030,7 +7079,7 @@ export const DOCS_SECTION_INDEX = [
7030
7079
  title: 'Forms & Lead Capture',
7031
7080
  heading: 'Build a form',
7032
7081
  anchor: '#build-a-form',
7033
- text: '1. Drop form components onto a page in the Besigner (fields, submit button).\n2. Configure the fields and the submit behavior.\n3. Publish — the form posts to Aglyn\'s submit API.\nYou can also describe the form you need and have Aglyn AI build it as a draft on the Forms page, with its fields, marketing consent and routing agreeing with each other. See Generate a form from a brief.\nPer-visitor rate limit Submissions are capped at 10 per minute per site, per visitor address. A visitor over the limit gets a short retry delay, not a permanent block. It\'s per address, so one spammer can\'t lock out everyone else — but bulk-importing through your own public form will trip it. Use datasets for imports instead.\nThat per-address limit is one of several protections in front of your form — see Spam and abuse protection.\nPlace a saved form on a page {#place-a-saved-form}\nA form built on the Forms page goes on a page through a Form element: drop one in the Besigner and pick the form under Form. The page then draws that form\'s fields, and its button text, Success message, After submit outcome and styling come from the form itself, so editing them on the form changes every page that places it.\nPicking the form clears the button text, message and caption the element started with (the Contact Section block\'s Send message, for example), so they can\'t hide the form\'s own. To change one of them on one page only, set it on the placed element after picking the form, or under Change it on this page only. That replaces just the setting you changed; anything you leave empty still follows the form.\nSaved forms per site\nEach plan includes a number of saved forms per site:\n| Plan | Saved forms per site |\n| Free | 1 |\n| Starter | 5 |\n| Pro | 25 |\n| Business | 100 |\n| Scale, Advanced, Agency | 500 |\n| E'
7082
+ text: '1. In the Besigner, open the element picker\'s Forms group and drop a Form onto the page — or the ready-made Contact Form or Contact Section, which arrive with name, email and message fields already in them.\n2. With the Form selected, add a field preset per question: Text field, Email field, Message field, Dropdown field, Radio choice field, Checkbox or Rating field. Each preset is built from separate elements — a Form Control holding a Form Label and the input itself — so you can select and change any piece of it. Field types lists every element.\n3. Give each input a Field name, set the Form\'s Submit label and After submit, and style the pieces with the Styles panel (see Style a field).\n4. Publish — the form posts to Aglyn\'s submit API.\nYou can also describe the form you need and have Aglyn AI build it as a draft on the Forms page, with its fields, marketing consent and routing agreeing with each other. See Generate a form from a brief.\nPer-visitor rate limit Submissions are capped at 10 per minute per site, per visitor address. A visitor over the limit gets a short retry delay, not a permanent block. It\'s per address, so one spammer can\'t lock out everyone else — but bulk-importing through your own public form will trip it. Use datasets for imports instead.\nThat per-address limit is one of several protections in front of your form — see Spam and abuse protection.\nPlace a saved form on a page {#place-a-saved-form}\nA form built on the Forms page goes on a page through a Form element: drop one in the Besigner and pick the form under Form. The page then draws that form\'s fields, and its button text, Success message, After submit outcome and styling come from the form itself, so editing them on the form changes every page that places it.\nPicking the form clears the button t'
7034
7083
  },
7035
7084
  {
7036
7085
  path: '/content-and-data/forms/overview',
@@ -7044,14 +7093,14 @@ export const DOCS_SECTION_INDEX = [
7044
7093
  title: 'Forms & Lead Capture',
7045
7094
  heading: 'Field types',
7046
7095
  anchor: '#field-types',
7047
- text: 'Each Form Field has a type that controls what visitors see and what is submitted:\n| Type | Visitor sees | Submitted value |\n| Text (default) | Single-line input | The text |\n| Email | Email input | The address |\n| Multiline | Multi-row text area | The text |\n| Dropdown | Select menu | The chosen option |\n| Radio choice | One radio button per option | The chosen option |\n| Checkboxes | One checkbox per option | All ticked options, joined with , |\n| Star rating | Five stars | The number of stars (e.g. 4) |\nDropdown, radio, and checkbox fields take their choices from the field\'s Options setting — enter one choice per line (or separate them with commas). Blank entries are ignored. The Required? switch works per type: a required checkbox group needs at least one box ticked.\nLabels and placeholders\nEvery field has a Label — the visible name of the input, and the one screen readers announce. A field can also carry a Placeholder: a gray example inside the empty input, such as you@company.com or "Tell us about your setup". Set one and the label moves above the box so both are readable at once; leave it empty and the label keeps its floating behavior.\nA placeholder is a hint, never a substitute for the label — it vanishes the moment a visitor starts typing, and a field labeled only by its placeholder is unusable with a screen reader. Text, email, and multiline fields show it inside the input; a dropdown displays it until a choice is made; radio, checkbox, and rating fields ignore it. Clearing the setting removes the hint.\nExample: a quick survey\nBuild a feedback survey with four fields:\n1. A Star rating field named satisfaction, labeled "How satisfied are you?".\n2. A Radio choice field named visit-frequency with options First time, Monthly, Weekly.\n3. A Checkboxes field named top'
7096
+ text: 'A field is not one element but a few, each one you can select, move and style on its own. The picker\'s presets put them together for you; the table lists every piece, all in the element picker\'s Forms group:\n| Element | What it is | Its settings |\n| Form Control | One field\'s frame. It holds the field\'s label, its input and any help text, and ties the label to the input. | Full width?, Required? (adds an asterisk to the label) |\n| Form Label | The words that name a field, above its input. | Text |\n| Input | A box a visitor types in. | Field name, Maps to schema field, Type (Text, Email, Phone, Link or Number), Placeholder, Required?, Several lines? (a message box instead of one line), Full width?, Accessible label |\n| Helper Text | A line of guidance under a field. | Text |\n| Select | A dropdown. It holds Select Options; a visitor picks one. | Field name, Maps to schema field, Placeholder, Required?, Full width?, Accessible label |\n| Select Option | One choice in a Select. | Text, Value (what is sent; left empty, the Text is sent) |\n| Checkbox | A tick box. | Field name, Maps to schema field, Value (what a tick sends, such as Yes), Required? |\n| Radio Group | A set of Radios; a visitor picks one. | Field name, Maps to schema field, In a row? |\n| Radio | One choice in a Radio Group. | Value, Required? |\n| Choice Label | The words beside a Checkbox or Radio placed inside it. Clicking the words ticks the box. | Text |\n| Rating | Stars a visitor picks. | Field name, Maps to schema field, Stars (how many to show) |\nWhat each one sends:\n| Element | Submitted value |\n| Input | What the visitor typed |\n| Select | The chosen option\'s Value (or its Text) |\n| Radio Group | The chosen Radio\'s Value |\n| Checkbox | Its Value when ticked, nothing when not |\n| Rating | The number of st'
7048
7097
  },
7049
7098
  {
7050
7099
  path: '/content-and-data/forms/overview',
7051
7100
  title: 'Forms & Lead Capture',
7052
7101
  heading: 'After submit',
7053
7102
  anchor: '#after-submit',
7054
- text: 'The form\'s After submit setting controls what a successful submission does:\n| Outcome | What the visitor sees |\n| Show the success message (default) | The form is replaced by your Success message |\n| Redirect the visitor | The browser navigates to a page you pick (rename-safe — slug changes never break it) or, with no page picked, to a Redirect URL (a same-site path like /thanks or an https URL; anything else is ignored) |\n| Reveal a hidden element | An element you pick from the canvas — hidden on the published page until then — appears in place of the form |\nFor the reveal outcome, drop the follow-up content (a thank-you block, a download link, an embedded video) anywhere on the page, then select it as the Element to reveal. It stays hidden for visitors until the form is submitted; in the Besigner it stays visible so you can keep editing it. If a redirect target can\'t be resolved (the page was deleted, the URL was rejected), the form falls back to the success message.\nExample: grow an email list from a signup form\nCombine an outcome with a conditional automation:\n1. Add the Marketing consent field from Forms in the Besigner\'s element picker: a Checkboxes field named marketingConsent, labeled Marketing emails, with one option, Email me news and offers. If you reword the option, keep it free of commas: the Options setting starts a new box at every comma.\n2. On the form\'s own page, pick marketingConsent as the Marketing consent field, so a tick is recorded as the person\'s consent.\n3. Set After submit to Redirect the visitor and pick your /thanks page.\n4. On Automation → Actions, add an action on formSubmission with the condition "A field is not empty" → marketingConsent and the step Enroll in a list, picking your email audience.\nVisitors who tick the box are added to the '
7103
+ text: 'The form\'s After submit setting controls what a successful submission does:\n| Outcome | What the visitor sees |\n| Show the success message (default) | The form is replaced by your Success message |\n| Redirect the visitor | The browser navigates to a page you pick (rename-safe — slug changes never break it) or, with no page picked, to a Redirect URL (a same-site path like /thanks or an https URL; anything else is ignored) |\n| Reveal a hidden element | An element you pick from the canvas — hidden on the published page until then — appears in place of the form |\nFor the reveal outcome, drop the follow-up content (a thank-you block, a download link, an embedded video) anywhere on the page, then select it as the Element to reveal. It stays hidden for visitors until the form is submitted; in the Besigner it stays visible so you can keep editing it. If a redirect target can\'t be resolved (the page was deleted, the URL was rejected), the form falls back to the success message.\nExample: grow an email list from a signup form\nCombine an outcome with a conditional automation:\n1. Add the Marketing consent preset from Forms in the Besigner\'s element picker: a Choice Label reading Email me news and offers holding one unticked Checkbox whose Field name is marketingConsent. Reword the Choice Label\'s Text as you like; a tick sends the Checkbox\'s Value. Keep it the only Checkbox with that Field name, because several boxes under one name are a question with several answers, not an opt-in.\n2. On the form\'s own page, pick marketingConsent as the Marketing consent field, so a tick is recorded as the person\'s consent.\n3. Set After submit to Redirect the visitor and pick your /thanks page.\n4. On Automation → Actions, add an action on formSubmission with the condition "A field is not empty" → ma'
7055
7104
  },
7056
7105
  {
7057
7106
  path: '/content-and-data/forms/overview',
@@ -7228,6 +7277,41 @@ export const DOCS_SECTION_INDEX = [
7228
7277
  anchor: '#related',
7229
7278
  text: '- Self-hosting — the full runbook, including which addresses this install calls its own and the reverse-proxy rules.\n- Environment variables — the per-variable reference for everything on this page.\n- Custom Domains — what a site owner sees at the other end of all this.'
7230
7279
  },
7280
+ {
7281
+ path: '/developers/order-webhooks',
7282
+ title: 'Order webhooks',
7283
+ heading: '',
7284
+ anchor: '',
7285
+ text: 'Order webhooks for developers\nA store\'s managers add an endpoint under Settings → Order webhooks in the Products hub, choose its events, and copy its signing secret — see Order webhooks for that side and the list of events. This page is for whoever builds the endpoint.'
7286
+ },
7287
+ {
7288
+ path: '/developers/order-webhooks',
7289
+ title: 'Order webhooks',
7290
+ heading: 'What your endpoint receives',
7291
+ anchor: '#what-your-endpoint-receives',
7292
+ text: 'A POST with a JSON body:\ndata.order is the order in the same shape the API returns for GET /v1/sites/{siteId}/orders/{orderId}. Money is in whole cents. Three headers come with it:\n| Header | What it holds |\n| Aglyn-Event | The event, e.g. order.paid. |\n| Aglyn-Event-Id | The event\'s id. It is the same on every retry, so store it and ignore an id you have already handled. |\n| Aglyn-Signature | t= ,v1= . |'
7293
+ },
7294
+ {
7295
+ path: '/developers/order-webhooks',
7296
+ title: 'Order webhooks',
7297
+ heading: 'Check the signature',
7298
+ anchor: '#check-the-signature',
7299
+ text: 'The signature is the HMAC-SHA256, in hex, of the timestamp, a period, and the raw request body, keyed with your signing secret. Check it against the raw body before parsing it, and refuse a timestamp more than five minutes old:'
7300
+ },
7301
+ {
7302
+ path: '/developers/order-webhooks',
7303
+ title: 'Order webhooks',
7304
+ heading: 'Answer quickly, and retries',
7305
+ anchor: '#answer-quickly-and-retries',
7306
+ text: 'Answer with any 2xx status within 8 seconds. Anything else — another status, a redirect, a timeout — is a failed attempt, and the event is sent again after 30 seconds, 2 minutes, 10 minutes, 30 minutes, 1 hour, 6 hours and 12 hours: eight attempts over about a day. If the last one fails, the site\'s managers are told. An event can arrive more than once, and events about one order can arrive out of order, so use Aglyn-Event-Id to skip repeats and the order\'s status rather than the arrival order.'
7307
+ },
7308
+ {
7309
+ path: '/developers/order-webhooks',
7310
+ title: 'Order webhooks',
7311
+ heading: 'Related',
7312
+ anchor: '#related',
7313
+ text: '- Order webhooks — adding an endpoint and the events'
7314
+ },
7231
7315
  {
7232
7316
  path: '/developers/plugins/building-feature-plugins',
7233
7317
  title: 'Building feature plugins',
@@ -8593,6 +8677,13 @@ export const DOCS_SECTION_INDEX = [
8593
8677
  anchor: '#docs-build',
8594
8678
  text: 'apps/docs is a standalone Docusaurus package. It is not part of docker compose; you build and publish it separately if you want your own documentation site. Skip this whole section if you do not.\nEvery value below is read at build time by docusaurus build, from that build\'s environment. They are not container runtime environment, and they are not NEXTPUBLIC — Docusaurus is not Next. Set them before the build, not after; the values are baked into the static output.\n| Variable | Unset means |\n| DOCSGATRACKINGID | No analytics tag is loaded at all |\n| DOCSERRORBEACONENDPOINT | The browser error beacon installs no handlers |\n| DOCSSTATUSTARGETS | /status probes nothing and says so |\n| DOCSSTATUSFALLBACKURL | /status names no independent monitor to fall back to |\n| DOCSURL | The canonical origin is https://docs.aglyn.com |\n| DOCSORGANIZATIONNAME | The footer copyright reads Aglyn LLC, followed by Aglyn\'s trademark attribution. Setting it replaces the name and drops the attribution — a rebranded build must not claim our marks. |\nThe rule to hold on to for the first three: unset means off, never ours. They previously defaulted to Aglyn\'s GA4 property, Aglyn\'s error collector and Aglyn\'s production health endpoints — so a published build reported your readers to us and told them our uptime was yours, which is a false all-clear during your own outage.\nDOCSSTATUSTARGETS is a comma-separated list of name|label|origin|description|path entries. A name and an origin are required; the description may be omitted and an empty label falls back to the name, so console||https://console.example.com is a valid entry:\nThe fifth field is the health path to probe, and defaults to /api/health. Point a target at a subsystem endpoint when the aggregate is not the signal you want a visitor to see —'
8595
8679
  },
8680
+ {
8681
+ path: '/developers/self-hosting',
8682
+ title: 'Self-hosting',
8683
+ heading: 'Maintenance scripts',
8684
+ anchor: '#maintenance-scripts',
8685
+ text: 'Dataset filter terms {#dataset-filter-terms}\nDataset filters and search need no database index, so there is nothing to deploy for them. Records keep their filter terms in two fields every write keeps current: filterValues, one value per filterable field, and filterKeys, the words a contains or a search looks for. Records written before a field existed are found by the filters that read it only once those fields are stamped onto them. Stamp them once per project:\nIt uses Application Default Credentials (gcloud auth application-default login), is safe to re-run, and --org= limits it to one organization. Run it again after a site changes a field\'s type or options in the schema dialog: a schema change does not rewrite records, so until a record is edited or re-stamped its filter terms follow the old model.'
8686
+ },
8596
8687
  {
8597
8688
  path: '/developers/self-hosting',
8598
8689
  title: 'Self-hosting',
@@ -9069,6 +9160,13 @@ export const DOCS_SECTION_INDEX = [
9069
9160
  anchor: '#the-app-bar',
9070
9161
  text: '- Site switcher (left) — jump between the sites you belong to, search them by name with Find site…, or create a new one.\n- Breadcrumbs — show the current site\'s display name and where you are.\n- Page switcher — a searchable dropdown for hopping between pages without leaving the editor: your recent pages by default, or type to find any page or layout in the site by name. View all pages opens the full list.\n- Version dropdown (right, near your avatar) — pick or schedule a version to view.\n- Notifications — the bell shows an unread badge and drops down your 10 most recent notifications (form submissions, bookings, invoices, team changes), split across an Inbox tab (unread) and an Archive tab (already read). Mark all read clears the inbox, the gear opens your notification preferences, and View all opens the full paginated feed. The badge turns red while an unread critical notification is waiting, and amber for an unread warning. Each notification is colored the way the feed colors it (below).\n- Account menu — your avatar opens it. The header shows your name and email with a gear to Manage Account, and the first row below repeats that destination as a labeled Manage account — a gear is not discoverable as a name. Then come Manage Team, Billing and Support, which appear only on a page that names a workspace and only for members whose role can reach those pages; Staff console (Aglyn staff only); a Documentation link that opens this docs site in a new tab; and Report an issue, directly under Documentation because "the docs didn\'t answer it" is the step before reporting it. Report an issue opens a form over the page you\'re on rather than navigating away — the page you were looking at is the most useful thing the report carries — and unlike the rows above it, it needs no particul'
9071
9162
  },
9163
+ {
9164
+ path: '/getting-started/console-tour',
9165
+ title: 'The console tour',
9166
+ heading: 'Choose a workspace',
9167
+ anchor: '#choose-a-workspace',
9168
+ text: 'If you belong to more than one organization, signing in opens Workspaces: one card per workspace, with its name, its workspace address underneath, and Open, which takes you to its sites. With just one workspace you skip this page and go straight in.\n- Order — the cards are in name order, A to Z, with any workspaces you pinned first.\n- Pin — the pin in a card\'s top corner keeps that workspace at the front of the list. Click it again to unpin. Pins are saved to your account, so they follow you to every device and browser, and nobody else sees them. If you leave a workspace, its pin simply stops counting.\n- Search — finds a workspace by the start of any word in its name or its address: rea and roll both find Ready To Roll.\n- Filters — narrows the cards by Plan (Free, Starter, Pro and so on), by Your role in that workspace (Owner, Admin, Editor or Viewer), or by Pinned. Each filter in force shows as a chip above the cards; remove a chip to drop it.\nThe search and the filters cover every workspace you belong to, not only the cards on the current page. The pager at the foot of the list turns through the matches, five at a time.\nThe workspace switcher in the app bar lists your workspaces in the same order, pinned first, and marks each pinned one with a pin. Type in its search box to find one by name or address.'
9169
+ },
9072
9170
  {
9073
9171
  path: '/getting-started/console-tour',
9074
9172
  title: 'The console tour',
@@ -9137,7 +9235,7 @@ export const DOCS_SECTION_INDEX = [
9137
9235
  title: 'Create a site',
9138
9236
  heading: 'Create your first site',
9139
9237
  anchor: '#create-your-first-site',
9140
- text: '1. Sign in to the console.\n2. Open the site switcher in the app bar (top-left) and choose Create site.\n3. Give it a name. Aglyn generates a working subdomain immediately, so the site has a real address from the first moment — you can attach a custom domain later.\nWhen you can use Aglyn AI, the new site opens on Start your site, which asks how you want to start: Start from the starter site, or Start with AI, which plans your pages from a few questions — see Generate a website from a prompt. Choosing the starter site, skipping or closing the window all give the site the starter described below. Choosing Start from the starter site publishes it at once, and the console says so: Your site is live, with the site\'s address, View your site and Edit your pages. Until you choose, the site\'s address shows a short coming soon page with its name, kept out of search results.\nEvery other new site starts with the starter straight away. The starter is a complete website, published and open to search engines from the first visit:\n- a Home page at the site root with the sections an ordinary business site has — a hero with your site\'s name, what you offer, an about section, a photo gallery, testimonials, frequently asked questions, a call to action and a working contact form. Each section says how to make it yours, and the photos are placeholders to swap for your own under Media;\n- a shared header and footer layout every page you add renders inside, with your site\'s name, search, a light/dark switch and a Contact button. It is the site\'s one shared layout on the Free plan;\n- a theme (colors and fonts) under Setup → Theme, and a title, description and sharing image under Setup → SEO.\nOpen the Home page from Pages to make it your own: once you publish your changes it is your home page like '
9238
+ text: '1. Sign in to the console.\n2. Choose Create site on the All Sites page, or in the site switcher in the app bar (top-left). With no workspace yet, Create site on the empty console sets your workspace up first, then opens the same window in it.\n3. Give it a name. Aglyn suggests a subdomain from it and checks that it is free as you type, so the site has a real address from the first moment — you can attach a custom domain later.\nWhen you can use Aglyn AI, Create site opens Start your site, which asks for the name and address and how you want to start: Start from the starter site, or Start with AI, which plans your pages from a few questions — see Start a new site with AI. Nothing is created until you choose: Start from the starter site or Skip creates the site with the starter described below and publishes it at once, and the console says so: Your site is live, with the site\'s address, View your site and Edit your pages. Closing the window creates nothing.\nOtherwise Create site asks for the name and address and creates the site with the starter straight away. The starter is a complete website, published and open to search engines from the first visit:\n- a Home page at the site root with the sections an ordinary business site has — a hero with your site\'s name, what you offer, an about section, a photo gallery, testimonials, frequently asked questions, a call to action and a working contact form. Each section says how to make it yours, and the photos are placeholders to swap for your own under Media;\n- a shared header and footer layout every page you add renders inside, with your site\'s name, search, a light/dark switch and a Contact button. It is the site\'s one shared layout on the Free plan;\n- a theme (colors and fonts) under Setup → Theme, and a title, description and sh'
9141
9239
  },
9142
9240
  {
9143
9241
  path: '/getting-started/create-a-site',
@@ -9228,7 +9326,7 @@ export const DOCS_SECTION_INDEX = [
9228
9326
  title: 'Build & publish a survey',
9229
9327
  heading: '1. Create the dataset',
9230
9328
  anchor: '#1-create-the-dataset',
9231
- text: 'Datasets belong to your organization, so every site can share them. Open the organization Data page (or any site\'s Data page — both edit the same data).\n1. Choose Add dataset. In the New dataset dialog give it a Name (say Survey responses) and a comma-separated list of Fields (satisfaction, visit, topics, comments) — at least one, or Create stays disabled. Create it.\n2. Select your new dataset in the Dataset dropdown and open Schema. The Schema dialog lists each field with its display name, generated field id, and a type chip.\n3. Use Add field / Edit to type the fields properly:\n- satisfaction → type Integer. A form stores every value as text, so the rating lands as "4"; the Data page\'s = filter still matches it as the number 4.\n- visit → type Text (one radio choice).\n- topics → type Text (ticked checkboxes arrive joined with , ).\n- comments → type Text.\n4. Save schema.\nEach field\'s Display name is what you see in dialogs and table headers; the field id next to it (a slug generated once from the display name) is the stable key records store values under — the key {{item.fieldId}} bindings reference, and what a form field\'s Maps to schema field picker stores. Renaming the display name later never changes the id.\nModel first A clean schema now makes everything downstream typed: the record editor renders the right input per field and imports are validated. Form submissions are the exception — they are stored as text without validation, so a submitted value can disagree with its field\'s type. See the datasets deep-dive for the full type system.'
9329
+ text: 'Datasets belong to your organization, so every site can share them. Open the organization Data page (or any site\'s Data page — both edit the same data).\n1. Choose Add dataset. In the New dataset dialog give it a Name (say Survey responses) and a comma-separated list of Fields (satisfaction, visit, topics, comments) — at least one, or Create stays disabled. Create it.\n2. Select your new dataset in the Dataset dropdown and open Schema. The Schema dialog lists each field with its display name, generated field id, and a type chip.\n3. Use Add field / Edit to type the fields properly:\n- satisfaction → type Integer. A form stores every value as text, so the rating lands as "4"; the Data page\'s = filter still matches it as the number 4.\n- visit → type Text (one radio choice).\n- topics → type Text (ticked checkboxes arrive joined with , ).\n- comments → type Text.\n4. Save schema.\nEach field\'s Display name is what you see in dialogs and table headers; the field id next to it (a slug generated once from the display name) is the stable key records store values under — the key {{item.fieldId}} bindings reference, and what the Maps to schema field picker on a form\'s input stores. Renaming the display name later never changes the id.\nModel first A clean schema now makes everything downstream typed: the record editor renders the right input per field and imports are validated. Form submissions are the exception — they are stored as text without validation, so a submitted value can disagree with its field\'s type. See the datasets deep-dive for the full type system.'
9232
9330
  },
9233
9331
  {
9234
9332
  path: '/guides/build-and-publish-a-survey',
@@ -9242,14 +9340,14 @@ export const DOCS_SECTION_INDEX = [
9242
9340
  title: 'Build & publish a survey',
9243
9341
  heading: '3. Insert a Form from the element picker',
9244
9342
  anchor: '#3-insert-a-form-from-the-element-picker',
9245
- text: 'With the page open, add the form:\n1. In the Elements panel choose Add Element (or right-click a node and pick Add element). The Choose element picker opens, grouped by category.\n2. Expand the Forms group. It contains the Form container, the Form Field element, and a ready-made Contact Form preset.\n3. Insert a Form. Then, with the Form selected, add one Form Field child per question (the picker\'s Form Field preset drops a field with sensible defaults).'
9343
+ text: 'With the page open, add the form:\n1. In the Elements panel choose Add Element (or right-click a node and pick Add element). The Choose element picker opens, grouped by category.\n2. Expand the Forms group. It holds the Form container, the ready-made field presets (Text field, Email field, Message field, Dropdown field, Radio choice field, Checkbox, Rating field, Helper Text), the Contact Form and Marketing consent presets, and the separate elements those presets are built from.\n3. Insert a Form. Then, with the Form selected, insert one preset per question:\n- a Rating field for satisfaction,\n- a Radio choice field for how often they visit,\n- a Form Control holding three Checkbox presets, for what to improve,\n- a Message field for comments.'
9246
9344
  },
9247
9345
  {
9248
9346
  path: '/guides/build-and-publish-a-survey',
9249
9347
  title: 'Build & publish a survey',
9250
9348
  heading: '4. Configure the fields',
9251
9349
  anchor: '#4-configure-the-fields',
9252
- text: 'Select each Form Field and set its properties in the inspector:\n| Property | What it does |\n| Field name | The key the value is stored under in submissions (and in the inbox copy). |\n| Maps to schema field | Which of the dataset\'s schema fields this value is stored under. The dropdown lists the fields of the dataset chosen on the Form (see step 5) and stores the stable field id, so renaming the field later never breaks the mapping. Left on None, the value matches a dataset field by name instead. |\n| Label | The visible input label ("How satisfied are you?"). |\n| Placeholder | An optional gray hint inside the empty input ("you@company.com"). It is not a label — it disappears as soon as someone types, so always keep Label set. Radio, checkbox, and rating fields ignore it; a dropdown shows it until a choice is made. Clear it to remove the hint. |\n| Type | Text (default), Email, Multiline, Dropdown, Radio choice, Checkboxes, or Star rating. |\n| Options | Choices for dropdown, radio, and checkbox fields — one per line or comma-separated. Ignored by other types. |\n| Required? | Whether the field must be filled; a required checkbox group needs at least one box ticked. |\nPick the dataset first "Maps to schema field" lists the fields of whichever dataset the Form is pointed at — set the Form\'s Write to dataset (step 5) before mapping the fields, or the dropdown reads No dataset selected on the form.\nFor this survey:\n1. satisfaction — Type Star rating, label "How satisfied are you?". The five stars submit their count (4), which the form stores as text.\n2. visit — Type Radio choice, Options First time, Monthly, Weekly.\n3. topics — Type Checkboxes, Options Products, Support, Pricing. Visitors can tick several; the submission joins them with , .\n4. comments — Type Multiline for free'
9350
+ text: 'Each preset is a few separate elements: a Form Control frame holding a Form Label (the visible question) and the element the visitor answers with — a Rating, a Radio Group of Radios, Checkboxes or an Input. Select a piece in the canvas or the Hierarchy and set it in the inspector:\n| Setting | On | What it does |\n| Text | Form Label | The question the visitor reads ("How satisfied are you?"). |\n| Field name | Rating, Radio Group, Checkbox, Input, Select | The key the answer is stored under in submissions (and in the inbox copy). |\n| Maps to schema field | Rating, Radio Group, Checkbox, Input, Select | Which of the dataset\'s schema fields this answer is stored under. The dropdown lists the fields of the dataset chosen on the Form (see step 5) and stores the stable field id, so renaming the field later never breaks the mapping. Left on None, the answer matches a dataset field by its Field name instead. |\n| Value | Radio, Checkbox | What is sent when this choice is picked or ticked. |\n| Text | Choice Label | The words beside a Radio or Checkbox; clicking them ticks it. |\n| Placeholder | Input, Select | An optional gray hint inside the empty input ("you@company.com"). It is not a label — it disappears as soon as someone types, so keep the Form Label. |\n| Required? | Input, Select, Checkbox, Radio | Whether it must be answered before the form sends. |\nPick the dataset first "Maps to schema field" lists the fields of whichever dataset the Form is pointed at — set the Form\'s Write to dataset (step 5) before mapping the fields, or the dropdown reads No dataset selected on the form.\nFor this survey:\n1. Rating field — Form Label "How satisfied are you?"; select the Rating and set Field name satisfaction and Maps to schema field Satisfaction. The stars submit their count (4).\n2. Ra'
9253
9351
  },
9254
9352
  {
9255
9353
  path: '/guides/build-and-publish-a-survey',
@@ -9291,7 +9389,7 @@ export const DOCS_SECTION_INDEX = [
9291
9389
  title: 'Launch a coming-soon page',
9292
9390
  heading: '1. Build the coming-soon page',
9293
9391
  anchor: '#1-build-the-coming-soon-page',
9294
- text: 'Create the page first; you\'ll point your domain at it in step 2.\n1. Go to Pages → New page. Title it Coming soon. Give it any slug for now — coming-soon is fine — you\'ll change it to / in the next step.\n2. Open it in the Besigner and put the essentials on it. A coming-soon page that only says "coming soon" wastes the visit. Aim for:\n- What\'s coming, and roughly when. One sentence and a month beats a countdown timer you\'ll have to move.\n- A notify-me form — see below.\n- How to reach a human. An email address or a contact link; people who arrive early are often the ones who most want to talk to you.\n- Links out — your documentation, your changelog, your social accounts, wherever you already post. These give an early visitor somewhere to go instead of bouncing.\n3. Publish the page.\nThe notify-me form\nAdd a Form from the element picker with a single Form Field of type Email, and set the Form\'s Success message to something that confirms the signup ("Thanks — we\'ll email you when we open"). The Forms & lead capture page covers the form elements and every field property in full; the only thing that matters here is that you give the field a Field name you\'ll recognize later, such as email.'
9392
+ text: 'Create the page first; you\'ll point your domain at it in step 2.\n1. Go to Pages → New page. Title it Coming soon. Give it any slug for now — coming-soon is fine — you\'ll change it to / in the next step.\n2. Open it in the Besigner and put the essentials on it. A coming-soon page that only says "coming soon" wastes the visit. Aim for:\n- What\'s coming, and roughly when. One sentence and a month beats a countdown timer you\'ll have to move.\n- A notify-me form — see below.\n- How to reach a human. An email address or a contact link; people who arrive early are often the ones who most want to talk to you.\n- Links out — your documentation, your changelog, your social accounts, wherever you already post. These give an early visitor somewhere to go instead of bouncing.\n3. Publish the page.\nThe notify-me form\nAdd a Form from the element picker\'s Forms group, and drop a single Email field preset into it: a Form Label and an Input whose Type is Email. Set the Form\'s Success message to something that confirms the signup ("Thanks — we\'ll email you when we open"). The Forms & lead capture page covers the form elements and every setting in full; the only thing that matters here is that the Input\'s Field name is one you\'ll recognize later. The preset names it email.\nTo put the address box and the button on one line, select the Form and set Styles → Flexbox & Grid → Flex direction to Row — see Style a field.'
9295
9393
  },
9296
9394
  {
9297
9395
  path: '/guides/coming-soon-launch',
@@ -9312,7 +9410,7 @@ export const DOCS_SECTION_INDEX = [
9312
9410
  title: 'Launch a coming-soon page',
9313
9411
  heading: '4. Collect the signups',
9314
9412
  anchor: '#4-collect-the-signups',
9315
- text: 'Every form submission is filed in your Inbox under the form\'s name, on every plan. That alone is enough to email people on launch day.\nTo get a list you can actually query, point the form at a dataset:\n1. Create a dataset on the organization Data page → Add dataset, called Launch signups, with a field for the address — email.\n2. Back in the Besigner, select the Form container and set Write to dataset to Launch signups in the Attributes panel.\n3. Select the email Form Field and set Maps to schema field to email.\nThat mapping is what makes the record land, and it\'s worth doing explicitly. The picker stores the dataset field\'s stable Reference ID, so renaming the field later never breaks it.\nLeft on None (match by field name), the value falls back to matching a dataset field whose Reference ID — the snakecase key beside each field in the Schema dialog, not its Display name — is identical to the form field\'s Field name. So a form field named email lands in a dataset field whose Reference ID is email with no mapping at all, while one named Your email silently doesn\'t.\nValues that match nothing are dropped from the record without failing the submission, and the same is true of a deleted dataset or an exceeded record quota — the append is best-effort by design, so a data-store problem never costs you a signup. The inbox copy always keeps everything, which is why it\'s the thing to check if a record looks wrong.\nThe survey walkthrough covers datasets, schema types and the form pickers in much more depth.'
9413
+ text: 'Every form submission is filed in your Inbox under the form\'s name, on every plan. That alone is enough to email people on launch day.\nTo get a list you can actually query, point the form at a dataset:\n1. Create a dataset on the organization Data page → Add dataset, called Launch signups, with a field for the address — email.\n2. Back in the Besigner, select the Form container and set Write to dataset to Launch signups in the Attributes panel.\n3. Select the email field\'s Input and set Maps to schema field to email.\nThat mapping is what makes the record land, and it\'s worth doing explicitly. The picker stores the dataset field\'s stable Reference ID, so renaming the field later never breaks it.\nLeft on None (match by field name), the value falls back to matching a dataset field whose Reference ID — the snakecase key beside each field in the Schema dialog, not its Display name — is identical to the Input\'s Field name. So an Input named email lands in a dataset field whose Reference ID is email with no mapping at all, while one named Your email silently doesn\'t.\nValues that match nothing are dropped from the record without failing the submission, and the same is true of a deleted dataset or an exceeded record quota — the append is best-effort by design, so a data-store problem never costs you a signup. The inbox copy always keeps everything, which is why it\'s the thing to check if a record looks wrong.\nThe survey walkthrough covers datasets, schema types and the form pickers in much more depth.'
9316
9414
  },
9317
9415
  {
9318
9416
  path: '/guides/coming-soon-launch',
@@ -9326,7 +9424,7 @@ export const DOCS_SECTION_INDEX = [
9326
9424
  title: 'Launch a coming-soon page',
9327
9425
  heading: '6. Verify it actually worked',
9328
9426
  anchor: '#6-verify-it-actually-worked',
9329
- text: 'Three things a crawler reads, and how to read them yourself. Run these against your real domain.\nrobots.txt — visit https://your-site/robots.txt, or:\nHidden looks like this — note that no sitemap is named:\nVisible looks like this:\nThe page\'s robots meta — open the page, View source, and search for robots. Or:\nA hidden page returns . A visible page returns nothing at all — no robots meta means "index me", which is the default.\nThe sitemap — visit https://your-site/sitemap.xml. While the site-wide switch is on it is an empty ; once you launch it becomes a sitemap index naming one child sitemap per section of your site. To count the URLs you are actually submitting, follow the index into its children:\nIt should be 0 while the site-wide switch is on, and after launch it should match your public pages. Any page you expect to see and don\'t is a page still set to Unlisted.\nGive it a few minutes These three files are cached for about five minutes. If a change hasn\'t shown up, wait a beat and re-run rather than changing another setting.'
9427
+ text: 'The SEO check card, at the top of Setup → SEO, reads your site the way a search engine does. Select Run the check (or Check again) and read the first lines of the result:\n- Launch status says whether the site is open to search engines. Hidden means the site-wide switch is still on: search engines are asked to stay away and the sitemap lists no pages. Open to search engines gives the number of pages listed for them.\n- Search engines are discouraged, in red under the score, is the same switch, still on. Go back to step 5.1.\n- A note that published pages are kept out of search names each page still set to Unlisted. Set its Visibility to Public (step 5.2) and check again.\n- The Checked pages table lists every page search engines can find. Your real home page should be the one at /, not Coming soon.\nWhen the status reads open to search engines, no page is named as kept out of search, and the table holds every page you expect, the launch is done.\nIt answers at once; search engines take longer The check reads your settings as saved, so it reflects a change the moment you make it. What search engines are served catches up within about five minutes, and getting listed again takes days — see the caution above.'
9330
9428
  },
9331
9429
  {
9332
9430
  path: '/guides/coming-soon-launch',
@@ -9403,7 +9501,7 @@ export const DOCS_SECTION_INDEX = [
9403
9501
  title: 'Datasets & schema deep-dive',
9404
9502
  heading: 'Display names vs field ids',
9405
9503
  anchor: '#display-names-vs-field-ids',
9406
- text: 'A dataset field has two names, and the distinction matters everywhere:\n- The display name is what you type in the schema dialog and what table headers and record editors show. Rename it freely.\n- The reference id is the stable key. It auto-fills from the display name when you create the field (Visit frequency → visitfrequency), and the schema dialog lets you edit it right there to set your own — for example a short, code-friendly key that differs from the label. Once the field is created the id is fixed and never changes. Records store values keyed by reference id — it\'s the key you use in {{item.referenceid}} bindings and what a form field\'s Maps to schema field picker stores.\nThe schema dialog shows both — each field row reads Display name · fieldId. The Reference ID input sits directly under Display name in the field editor; it follows the name as you type until you edit it, then keeps your value. The dataset itself likewise has a Singular name and a Plural name; the plural is the dataset\'s display name — the label its entry shows in "Write to dataset" and repeatable pickers (which store the dataset\'s id underneath, so renames never break the bindings).'
9504
+ text: 'A dataset field has two names, and the distinction matters everywhere:\n- The display name is what you type in the schema dialog and what table headers and record editors show. Rename it freely.\n- The reference id is the stable key. It auto-fills from the display name when you create the field (Visit frequency → visitfrequency), and the schema dialog lets you edit it right there to set your own — for example a short, code-friendly key that differs from the label. Once the field is created the id is fixed and never changes. Records store values keyed by reference id — it\'s the key you use in {{item.referenceid}} bindings and what the Maps to schema field picker on a form\'s input stores.\nThe schema dialog shows both — each field row reads Display name · fieldId. The Reference ID input sits directly under Display name in the field editor; it follows the name as you type until you edit it, then keeps your value. The dataset itself likewise has a Singular name and a Plural name; the plural is the dataset\'s display name — the label its entry shows in "Write to dataset" and repeatable pickers (which store the dataset\'s id underneath, so renames never break the bindings).'
9407
9505
  },
9408
9506
  {
9409
9507
  path: '/guides/datasets-and-schema',
@@ -9445,7 +9543,7 @@ export const DOCS_SECTION_INDEX = [
9445
9543
  title: 'Datasets & schema deep-dive',
9446
9544
  heading: 'Everything that writes records',
9447
9545
  anchor: '#everything-that-writes-records',
9448
- text: '| Writer | How it behaves |\n| Console — Add record / record editor | Typed inputs per field; validated and quota-checked. |\n| Console — Import records | Bulk CSV/JSON with validation, upsert, and quota math. |\n| Forms — the Form element\'s Write to dataset | Appends on each submission. The dataset is bound by id (a dropdown; legacy forms still match by name) and each form field can map to a schema field by id via Maps to schema field, with name-matching as the fallback — so renames never lose data. Best-effort (quota-full submissions keep only the inbox copy). See the survey guide. |\n| Automations — the Write to a dataset step | Appends a record from a workflow/action run. |\n| Automations — the Update a dataset record step | Updates a matching record (by email) or appends when none matches. |\nAutomation steps live in the Do list of an action — see workflows & actions.'
9546
+ text: '| Writer | How it behaves |\n| Console — Add record / record editor | Typed inputs per field; validated and quota-checked. |\n| Console — Import records | Bulk CSV/JSON with validation, upsert, and quota math. |\n| Forms — the Form element\'s Write to dataset | Appends on each submission. The dataset is bound by id (a dropdown; legacy forms still match by name) and each element a visitor answers with (an Input, Select, Radio Group, Checkbox or Rating) can map to a schema field by id via Maps to schema field, with name-matching on its Field name as the fallback — so renames never lose data. Best-effort (quota-full submissions keep only the inbox copy). See the survey guide. |\n| Automations — the Write to a dataset step | Appends a record from a workflow/action run. |\n| Automations — the Update a dataset record step | Updates a matching record (by email) or appends when none matches. |\nAutomation steps live in the Do list of an action — see workflows & actions.'
9449
9547
  },
9450
9548
  {
9451
9549
  path: '/guides/datasets-and-schema',
@@ -9664,6 +9762,90 @@ export const DOCS_SECTION_INDEX = [
9664
9762
  anchor: '#related',
9665
9763
  text: '- Members-only areas\n- Commerce end to end\n- CRM\n- Site protection & error pages'
9666
9764
  },
9765
+ {
9766
+ path: '/guides/newsletter-sign-up-band',
9767
+ title: 'Build a newsletter sign-up band',
9768
+ heading: '',
9769
+ anchor: '',
9770
+ text: 'Build a newsletter sign-up band\nThis walkthrough builds a full-width "Get product updates" band from parts you already have. Each part does one job:\n- A saved form collects the address. It holds two elements, an Input and a Button, and it is set up as a sign-up form, so submitting it records the person\'s opt-in.\n- A live audience picks up everyone who submits that form.\n- A reusable component draws the band and places the form in it. Every page that shows the band uses this one component.\nEverything is done by clicking. Every color, gap and corner comes from your theme through the Besigner\'s Styles panel, so the band follows your theme, and you never type code.'
9771
+ },
9772
+ {
9773
+ path: '/guides/newsletter-sign-up-band',
9774
+ title: 'Build a newsletter sign-up band',
9775
+ heading: 'Why not the Newsletter signup block?',
9776
+ anchor: '#why-not-the-newsletter-signup-block',
9777
+ text: 'The Newsletter signup element in the Commerce group is one fixed piece: a heading, a small outlined field and a primary button. It works, but it cannot look like your design. Building the band from separate elements gets you:\n- Your design. The field and the button are separate elements, each with the whole Styles panel, at every screen size.\n- One place to change it. Change the component once and every page that uses it updates. The same goes for the form.\n- Theme colors and spacing. Every color picker offers your theme\'s colors, and every spacing field offers its spacing steps, so the band follows a theme change, or another site\'s theme, with nothing to re-pick.\n- An audience by rule. The audience fills itself from the form\'s submissions.\nWhat the block does that this does not The block sends a confirmation email when the site asks new subscribers to confirm. A saved sign-up form records the opt-in at once and sends no confirmation. If your site requires confirmation, keep using the block for now.'
9778
+ },
9779
+ {
9780
+ path: '/guides/newsletter-sign-up-band',
9781
+ title: 'Build a newsletter sign-up band',
9782
+ heading: '1. Create the saved form',
9783
+ anchor: '#1-create-the-saved-form',
9784
+ text: '1. Open your site\'s Forms tab and choose Create Form.\n2. In Create new form, enter a Display name: Product updates. Choose Next.\nYou land on the form\'s own page. Remember the display name. The audience in step 5 finds people by it, so renaming the form later means updating the audience too.'
9785
+ },
9786
+ {
9787
+ path: '/guides/newsletter-sign-up-band',
9788
+ title: 'Build a newsletter sign-up band',
9789
+ heading: '2. Add an Input and a Button',
9790
+ anchor: '#2-add-an-input-and-a-button',
9791
+ text: 'Choose Edit in besigner on the form\'s page. The form\'s own design opens with an empty Form at its root. Select the Form, choose Add Element, and from the Forms group insert an Input. Then, from the Input group, insert a Button after it.\nSelect the Input and set its Attributes:\n| Attribute | Value | Why |\n| Field name | email | The key the address is stored under. |\n| Type | Email | The browser checks it is an address, and phones show the email keyboard. |\n| Placeholder | you@company.com | The gray hint inside the empty field. |\n| Required? | On | No empty sign-ups. |\n| Size | Small | 40px tall, to sit beside the button. |\n| Accessible label | Email address | The field\'s name for screen readers, since the band shows no label above it. |\nSelect the Button and set its Text to Subscribe and its Type to Submit. A Submit button inside a form is the form\'s button: the Form\'s own built-in button steps aside, and this one sends the address.\nFinally select the Form itself and set Success message to Thanks — you\'re on the list. No spam, ever. It replaces the form after a successful sign-up.'
9792
+ },
9793
+ {
9794
+ path: '/guides/newsletter-sign-up-band',
9795
+ title: 'Build a newsletter sign-up band',
9796
+ heading: '3. Style the form with the Styles panel',
9797
+ anchor: '#3-style-the-form-with-the-styles-panel',
9798
+ text: 'Each element is styled on its own, in the Styles tab. Pick colors from the theme colors each color picker offers and spacing from the theme\'s spacing steps. See Responsive styling.\nThe Form: stacked on phones, one line from tablet up. Select the Form and open Flexbox & Grid:\n1. With the toolbar\'s breakpoint picker on Fluid Responsive (every screen size), set Flex direction to column, Justify content to center and Gap to Small. Leave Align items unset, so the field and button stretch to full width on a phone.\n2. Switch the breakpoint picker to SM – Tablet. The panel now reads Styling breakpoint: SM. Set Flex direction to row and Align items to center. From tablet width up, the field and button share one line.\n3. Back on Fluid Responsive, in Sizing, set Width to 100 %.\nSee Style per breakpoint.\nThe Input: a white field with no outline. Select the Input:\n- Colors: Background Color = common.white, Text Color = grey.900.\n- Borders & Shadows: Border Color = common.white, so the outline disappears into the field, and Corner Radius = Slightly rounded.\n- Sizing: at SM – Tablet, Width = 320 px. On phones it stays full width.\nThe outline you see is the Input\'s own border, so Border Color and Corner Radius change it directly. A focus ring still appears while someone types.\nThe Button: dark, with a lighter shade on hover. Select the Button:\n- Colors: Background Color = grey.900, Text Color = common.white.\n- In the spacing ring, Padding: Top and Bottom Extra small, Left and Right Medium.\n- Switch the state chips from Default to Hover, and set Background Color = grey.800. Switch back to Default. See Style hover, focus and other states.\nWhen the form looks right, publish it from the top-right save button → Save & publish, or from the form page\'s Versions card. See Versions.'
9799
+ },
9800
+ {
9801
+ path: '/guides/newsletter-sign-up-band',
9802
+ title: 'Build a newsletter sign-up band',
9803
+ heading: '4. Make it a sign-up form',
9804
+ anchor: '#4-make-it-a-sign-up-form',
9805
+ text: 'On the form\'s page, in the CRM routing card:\n1. Leave Also create a lead from the address someone gives this form off. A newsletter reader is a subscriber, not a sales lead.\n2. Turn on This is a sign-up form: submitting it subscribes the person.\n3. Leave Marketing consent field on None. Its help text now reads "Not needed on a sign-up form: submitting it is the opt-in."\n4. Choose Save.\nEvery submission now:\n- creates or updates the person in Contacts,\n- records their marketing consent for this site, and\n- makes them at least a Subscriber. A lead or customer who signs up keeps their stage.\nNormally submitting a form is never consent, and a person opts in only by ticking a box. The switch is the one exception, and you choose it, form by form, for a form whose only purpose is subscribing. That is why the band\'s copy says plainly what the person is signing up for.\nSites in a consent group If your site shares a consent group, a sign-up form records the opt-in for this site alone.'
9806
+ },
9807
+ {
9808
+ path: '/guides/newsletter-sign-up-band',
9809
+ title: 'Build a newsletter sign-up band',
9810
+ heading: '5. Create the live audience',
9811
+ anchor: '#5-create-the-live-audience',
9812
+ text: '1. Open your site\'s Emails tab → Audiences and choose Create audience. Name it Product updates and create it.\n2. On the audience\'s page choose Edit list.\n3. Set Membership to Live — keeps growing.\n4. Set People from to Form submissions, and Submitted form to Product updates, the form\'s display name from step 1.\n5. Choose Save. The This audience box reads Submitted any of: Product updates.\nThe audience refreshes about every fifteen minutes. Its chip reads Rule · not yet evaluated until the first refresh. After that, everyone who has submitted the form is on it. Submitted form matches the form\'s display name exactly (ignoring case), so if you rename the form, update the audience too.\nThe Consent column on a live audience The members table shows the consent recorded on the membership. A live audience never writes consent onto its members, because matching a rule is not an opt-in. So its rows read No basis on record even for people who signed up.\nTheir opt-in is on their contact (step 8), and that is what a campaign checks before it sends. See Lists built from a rule.'
9813
+ },
9814
+ {
9815
+ path: '/guides/newsletter-sign-up-band',
9816
+ title: 'Build a newsletter sign-up band',
9817
+ heading: '6. Build the band as a reusable component',
9818
+ anchor: '#6-build-the-band-as-a-reusable-component',
9819
+ text: '1. Open Components → Create Component. Under Where will you use it? choose On pages, name it Newsletter band, and choose Next. Then Open Besigner.\n2. Give it two text properties so each page can change the words. Choose File → Properties… → Add property:\n| Name | Type | Label | Default |\n| heading | Text | Heading | Get product updates |\n| description | Text | Description | New features, guides, and early-access news — straight to your inbox. No spam. |\nChoose Save properties.\n3. Build the band from the Choose element picker:\n- a Section: the band itself. Set its Accessible label to Newsletter sign-up so screen readers can find it.\n- inside it, two Typography elements:\n- The first one\'s text is the heading property. Use the text field\'s {} button and pick heading from its Properties group. Set Variant to Heading 4 and Component to h2.\n- The second one\'s text is the description property, picked the same way, with Variant set to Body 1.\nSee Insert a variable.\n- a Form, from the Forms group. Pick Product updates under Form. The band now draws that form\'s field and button, styled as you styled them.\n4. Style the Section:\n- Colors:\n- Background Fill = Linear gradient. Set the Angle to 243, and bind its two color stops to the theme\'s Secondary and Primary colors. See Gradient backgrounds.\n- Text Color = common.white. The heading and copy inside inherit it.\n- Flexbox & Grid: Flex direction column, Align items center, Gap Small.\n- Typography: Text Alignment center.\n- In the spacing ring, Padding: Top and Bottom Huge, Left and Right Medium.\nBecause the gradient\'s stops are theme colors, each site that places the band shows it in that site\'s own colors.\n5. Give the two Typography elements a little polish:\n- The heading: Typography → Font Weight = Bold.\n- The description: Opacity '
9820
+ },
9821
+ {
9822
+ path: '/guides/newsletter-sign-up-band',
9823
+ title: 'Build a newsletter sign-up band',
9824
+ heading: '7. Place the band on your pages',
9825
+ anchor: '#7-place-the-band-on-your-pages',
9826
+ text: 'On any page, choose Add Element. Your saved components are under Your components. Insert Newsletter band.\nWith it selected, the Attributes panel shows Heading and Description, with the defaults as their starting text. Change them on this page, or leave them to follow the component. Then publish the page. See Publish & roll back.\nTo change the band everywhere, edit the component, never one page\'s copy. See Change it on this page only for the rare page that needs to differ.'
9827
+ },
9828
+ {
9829
+ path: '/guides/newsletter-sign-up-band',
9830
+ title: 'Build a newsletter sign-up band',
9831
+ heading: '8. Check it on the live site',
9832
+ anchor: '#8-check-it-on-the-live-site',
9833
+ text: 'Open the published page. On a wide screen the field and button share a row. On a phone they stack at full width:\nSign up with an address of your own, then open CRM → Contacts and the contact. Check two things:\n- The Stage chip reads Subscriber.\n- In the Relationship card, Marketing email reads Opted in · recorded with the date. Its timeline shows Submitted "Product updates".\nWithin about fifteen minutes the address also appears on the Product updates audience. It is ready for your next email campaign.'
9834
+ },
9835
+ {
9836
+ path: '/guides/newsletter-sign-up-band',
9837
+ title: 'Build a newsletter sign-up band',
9838
+ heading: 'Troubleshooting',
9839
+ anchor: '#troubleshooting',
9840
+ text: '| What you see | Why, and what to do |\n| The audience stays empty | Wait for the fifteen-minute refresh. Then check that Submitted form matches the form\'s Display name exactly. A rename breaks the match. |\n| The contact has no opt-in | The sign-up switch was off, or not saved, when they submitted. Turn it on and Save. It applies to new submissions, not past ones. |\n| The field and button stack on a wide screen | Flex direction row is set at the wrong breakpoint. Select the saved form\'s Form, switch the breakpoint picker to SM – Tablet, and check Flexbox & Grid. Then publish the form. |\n| Two buttons show | The Button\'s Type is not Submit. Only a Submit button replaces the form\'s built-in one. |\n| The band shows the wrong colors | Its gradient stops are bound to your theme\'s Primary and Secondary colors. Change them in the theme, not in the band. |\n| A gray outline shows around the field | Set the Input\'s Border Color to the same color as its Background Color. |'
9841
+ },
9842
+ {
9843
+ path: '/guides/newsletter-sign-up-band',
9844
+ title: 'Build a newsletter sign-up band',
9845
+ heading: 'Related',
9846
+ anchor: '#related',
9847
+ text: '- Forms: the field elements, placing a saved form on a page and CRM routing\n- Reusable components: properties and publishing\n- Responsive styling: per-breakpoint styles, states, spacing steps and gradient backgrounds\n- Email campaigns: email lists and asking subscribers to confirm\n- Build & publish a survey, a sibling walkthrough with a form that writes to a dataset'
9848
+ },
9667
9849
  {
9668
9850
  path: '/guides/run-an-agency-workspace',
9669
9851
  title: 'Run an agency workspace',
@@ -9753,14 +9935,14 @@ export const DOCS_SECTION_INDEX = [
9753
9935
  title: 'Service and location pages from a dataset',
9754
9936
  heading: '1. Model the data',
9755
9937
  anchor: '#1-model-the-data',
9756
- text: 'On the Data page, create a dataset called Services and give it the fields a service page shows. For example:\n| Field | Type | Used for |\n| Name | Text | The page heading and its name in the browser tab |\n| Summary | Text | The intro paragraph, and the search description |\n| Photo | Text | The hero image (a media library image or a URL) |\n| Category | Text | Grouping related services |\n| Page address | Page address | The service\'s own segment of its address |\nThe Page address field is what gives each record a page. Its type is Page address, and its values are lowercase words joined by hyphens: kitchen-remodeling, roof-repair. You can type each one, but you don\'t have to. Set the field\'s Fill in from to the Name field, and every record gets an address made from its name when it\'s added. A record keeps its address when it\'s renamed, so a live URL never moves under someone who bookmarked it.\nAlready have records? The record template settings below can add the field for you and give every existing record an address in one step.\nAdd a record per service. Make sure the dataset is shared with the site that will show it (Sharing on the dataset); a site only serves records of datasets shared with it.'
9938
+ text: 'On the Data page, create a dataset called Services and give it the fields a service page shows. For example:\n| Field | Type | Used for |\n| Name | Text | The page heading and its name in the browser tab |\n| Summary | Text | The intro paragraph, and the search description |\n| Photo | Image | The hero image, chosen from your media library |\n| Category | Text | Grouping related services |\n| Page address | Page address | The service\'s own segment of its address |\nThe Page address field is what gives each record a page. Its type is Page address, and its values are lowercase words joined by hyphens: kitchen-remodeling, roof-repair. You can type each one, but you don\'t have to. Set the field\'s Fill in from to the Name field, and every record gets an address made from its name when it\'s added. A record keeps its address when it\'s renamed, so a live URL never moves under someone who bookmarked it.\nAlready have records? The record template settings below can add the field for you and give every existing record an address in one step.\nAdd a record per service. For the Photo, press Choose from media in the record editor and pick the picture; see Image fields.\nMake sure the dataset is shared with the site that will show it (Sharing on the dataset); a site only serves records of datasets shared with it.'
9757
9939
  },
9758
9940
  {
9759
9941
  path: '/guides/service-and-location-pages-from-a-dataset',
9760
9942
  title: 'Service and location pages from a dataset',
9761
9943
  heading: '2. Design the template',
9762
9944
  anchor: '#2-design-the-template',
9763
- text: 'Create a page for the design. Its own name and address don\'t matter much, because once it\'s a template it no longer answers at its own address. Design it like any page. Wherever a record\'s value belongs, write {{item.field}}, the same tokens a repeat uses:\n- a heading of {{item.name}}\n- a paragraph of {{item.summary}}\n- an image whose source is {{item.photo}}\n- a reference goes one hop further: {{item.crewlead.name}}\nA repeat on the template can list the routed record\'s neighbors. A Stack that repeats over Services with the filter category == {{item.category}} lists the other services in the same category. The filter fills in from the page\'s record, and the copies fill in from their own rows.'
9945
+ text: 'Create a page for the design. Its own name and address don\'t matter much, because once it\'s a template it no longer answers at its own address. Design it like any page. Wherever a record\'s value belongs, press the {} insert binding button in that field and pick the record\'s field, the same bindings a repeat uses. Each shows as a pill naming the field:\n- a heading bound to Name\n- a paragraph bound to Summary\n- an Image whose Image source is bound to Photo\n- a reference goes one hop further: the Crew lead\'s Name\nA repeat on the template can list the routed record\'s neighbors. A Stack that repeats over Services with the filter category == {{item.category}} lists the other services in the same category. The filter fills in from the page\'s record, and the copies fill in from their own rows.'
9764
9946
  },
9765
9947
  {
9766
9948
  path: '/guides/service-and-location-pages-from-a-dataset',
@@ -9774,7 +9956,7 @@ export const DOCS_SECTION_INDEX = [
9774
9956
  title: 'Service and location pages from a dataset',
9775
9957
  heading: '4. Link to the pages',
9776
9958
  anchor: '#4-link-to-the-pages',
9777
- text: 'On your Services listing page (an ordinary page at /services, say), repeat a card over the Services dataset. Each repeated row carries its record\'s page as {{item.url}}, so a button or link with the address {{item.url}} goes to that service\'s page. The canvas previews the real links.\nIf the dataset has a field of its own called url, {{item.url}} keeps meaning that field.'
9959
+ text: 'On your Services listing page (an ordinary page at /services, say), repeat a card over the Services dataset. Each repeated row carries its record\'s page as its url, so a button or link whose External URL is bound to it with the {} button goes to that service\'s page. The canvas previews the real links.\nBuilt each service as an ordinary page instead of from a template? Give the dataset a Page field, pick each service\'s page in its record, and bind the card button\'s External URL to that field with the {} button; see Page fields.\nIf the dataset has a field of its own called url, {{item.url}} keeps meaning that field.'
9778
9960
  },
9779
9961
  {
9780
9962
  path: '/guides/service-and-location-pages-from-a-dataset',
@@ -10628,7 +10810,7 @@ export const DOCS_SECTION_INDEX = [
10628
10810
  title: 'Actions builder',
10629
10811
  heading: 'Triggers',
10630
10812
  anchor: '#triggers',
10631
- text: 'Beyond server events (form submissions, page views, sign-ins, leads, bookings), actions can fire on visitor behavior in the page:\n- Scroll depth — the visitor scrolls past a percentage.\n- Scroll to / element visible — a CSS-selected element enters the viewport.\n- Element click — a CSS-selected element is clicked.\n- Exit intent — the pointer leaves toward the top of the window.\n- Time on page — a dwell-time threshold passes.\n- Page visit — the page loads.\nPage triggers can be limited to certain paths (/pricing, /blog/), and a Frequency setting controls re-fires: every matching pageview, once per session, once per visitor, or with a cooldown (a minimum number of minutes between fires for the same browser).\nEvery switched-on automation listening for an event runs when it fires, however many the site has — a site with an auto-reply for each of a dozen forms runs every one whose conditions match.\nCRM events {#crm-events}\nSix server events come from the CRM — two about contacts, three about deals and one about tasks — and a seventh, New lead, from its leads. Pick one and the Filter field\'s helper text lists the keys below, so a condition such as lifecycleStage equals customer or source equals booking can be written without leaving the editor.\n| Event | Fires when | Keys in scope for filters and conditions |\n| Contact created (contactCreated) | A capture on your site makes a new contact: a form submission, a member sign-up, a newsletter subscription, an order or a booking from an address your workspace did not already hold. A repeat visit by somebody already on the list is recorded as an interaction and does not fire it. | contactId · email · name (empty when the capture had none) · source (form, member, newsletter, order or booking) · hostId · lifecycleStage (the stage the ca'
10813
+ text: 'Beyond server events (form submissions, page views, sign-ins, leads, bookings), actions can fire on visitor behavior in the page:\n- Scroll depth — the visitor scrolls past a percentage.\n- Scroll to / element visible — an element you pick enters the viewport.\n- Element click — an element you pick is clicked.\n- Exit intent — the pointer leaves toward the top of the window.\n- Time on page — a dwell-time threshold passes.\n- Page visit — the page loads.\nPointing at an element {#pick-element}\nA trigger or step that works on one element — element visible, element click, show or hide, a class, an attribute, scroll to, play a video, sticky nav — has a Pick element button. It opens your site\'s page in a window. Choose the Page, move over the page until the element you want is outlined, and click it. The chip beside the button then names what you picked, and × on the chip clears it. When the trigger is limited to one page, the picker opens that page first.\nThe picker opens the published site, so publish a new element before you pick it. An element in your header or footer is the same element on every page, so you can pick it on any of them.\nFor an advanced case, such as every element carrying a class your theme adds, Use a custom selector takes a CSS selector instead. It replaces the picked element.\nPage triggers can be limited to certain paths (/pricing, /blog/), and a Frequency setting controls re-fires: every matching pageview, once per session, once per visitor, or with a cooldown (a minimum number of minutes between fires for the same browser).\nEvery switched-on automation listening for an event runs when it fires, however many the site has — a site with an auto-reply for each of a dozen forms runs every one whose conditions match.\nCRM events {#crm-events}\nSix server events c'
10632
10814
  },
10633
10815
  {
10634
10816
  path: '/marketing-and-automation/workflows-and-actions/actions-builder',