== Changelog ==

Gather Grove Forms: releases older than those listed in readme.txt.

= 1.14.0 =
* Housekeeping: this plugin's text can now be translated. Its wording had never been collected into a translation file, so translators had no way to reach it. Nothing changes on your site if you use it in English.

= 1.13.6 =
* Housekeeping: fixes a WordPress notice that could appear in your admin after updating to WordPress 6.7 or later. Nothing changes on your site.

= 1.13.5 =
* Housekeeping: **bundles Gather Grove Core 0.41.0.** Brings the shared code behind the app-style member experience (add-to-home-screen and class reminders on a phone) up to date, so this plugin is never the one holding a site on an older version. Nothing changes on your site.

= 1.13.4 =
* Housekeeping: **bundles Gather Grove Core 0.35.0.** Adds the tick box that lets you mark a page you built yourself as part of your members' area — it appears in the Gather Grove box when editing a page. Nothing else changes on your site.

= 1.13.3 =
* Housekeeping: **bundles Gather Grove Core 0.34.0.** Brings this plugin onto the same shared Gather Grove code the rest of the suite runs, so every plugin agrees on which version it ships. Nothing changes on your site: this is the groundwork behind the shared member controls, and nothing here uses it yet.

= 1.13.2 =
* Housekeeping: **bundles Gather Grove Core 0.32.0.** Adds the shared "when did this member last do anything, anywhere in the suite" record, which the whole suite reads from one place — so a member who stopped booking classes but works through lessons every day is not mistaken for someone who has drifted away. Nothing changes on your site today; this is groundwork for the follow-up and re-engagement features.
* Until now this plugin bundled Core 0.31.2, so that record was missing on a site running it without Gather Grove Booking (which already ships 0.32.0). All plugins now offer the same version.

= 1.13.1 =
* Fixed: **a dark studio now gets dark cards.** If your studio uses a dark colour scheme — a dark page with light text — the cards drawn on top of it stayed white, so light text landed on white and panels and inputs were hard or impossible to read. Cards, panels and borders now follow your page, in your own colour rather than a flat grey. Studios with a light colour scheme see no change at all.
* Also picks up the shared security hardening released in Gather Grove Core since this plugin last bundled it: secret values are masked out of debug logs, and the REST nonce is only ever attached to same-origin requests.

= 1.13.0 =
* Fixed: **a multi-step form showed a dead "Next" button beside "Submit" on its final page.** Clicking it did nothing, because there was nowhere left to go — the button was supposed to be hidden and was being drawn anyway. The same fault put a stray "Back" button on the first page, where there is nothing to go back to. Both are now hidden as intended, so each page of a multi-step form offers only the buttons that actually lead somewhere. This affected Elementor-built sites in particular, and only multi-step forms — single-page forms were never affected.
* Added: another Gather Grove plugin can now fill in answers a form already knows. A form on a page is the same for every visitor, so a question whose answer is already on file — the name of the child a waiver is about, the email of the parent who is signed in — still had to be typed out by hand every time, which is both tedious and the most common way the wrong name ends up on the right form. A sibling plugin can now supply those answers as the page is built, and the person can still change anything they disagree with. Gather Grove Booking uses this to address a family agreement to the specific child it concerns. Note that a filled-in answer is a convenience and not a verification — the person can edit it before sending, so which member of a household a submission is *about* continues to be established separately and cannot be changed from the browser.

= 1.12.2 =
* Fixed: **repeater answers were missing from notification emails.** A repeater collects a list of rows — children on an enrolment application, guests on an RSVP, line items on an order — and `{field:your-key}` printed nothing at all for one, so a real application arrived reading "Children:" followed by blank space. Nothing was ever lost: every answer was stored on the entry the whole time and visible in Entries. It was the email that could not see through a row. Repeater answers now print in full, each row showing its sub-question labels and answers, and a choice inside a row prints the label the person saw rather than the value stored behind it. The same fix applies to the automatic email you get when you have not written your own message, which previously left those questions blank too.

= 1.12.1 =
* Security: **CSV exports of entries are now safe to open in spreadsheet apps.** A value a visitor typed into a form that began with `=`, `+`, `-` or `@` could be treated as a live formula by Excel, Google Sheets or LibreOffice when a studio opened the export — a spreadsheet-injection risk. Such values are now written so they always display as plain text. Your data is unchanged; a cell that starts with one of those characters simply shows it literally.

= 1.12.0 =
* Added: every submission now records the exact version of the form it was made against. Until now a form had no history — edit a question, a clause or a consent option, and every submission you had already collected quietly started reading as though it had been made against the new wording. For a contact form that does not matter. For anything someone agrees to — a waiver, a liability agreement, a photo-consent choice, a policy acknowledgement — it meant that a year later, asked what a particular person actually agreed to, there was no way to know. Now there is: each entry names the wording it was submitted under, and that wording is kept, so editing your form can never change what an earlier submission means. The stored copy is shared between every submission made against the same wording, so a form with thousands of responses stores one copy, not thousands.
* Added: `{field:your-key:label}` in notification emails, which prints the answer the way the person filling in the form saw it, rather than the value stored behind it. Choice questions store a short internal value, so a confirmation email could tell a parent "Photo permission: limited" when what they had actually picked was "Internal use only". Use `{field:key}` where you want the stored value and `{field:key:label}` where a person is going to read it. It works with the existing fallback syntax (`{field:key:label|Not answered}`), and on a question with no set choices it simply prints the answer, so it is safe to use anywhere.
* Added: another Gather Grove plugin can now tell a form who the person in front of it is. A form embedded on a page is the same for every visitor, so until now nothing could say "this particular copy of the form is for this particular person" — which is why a family agreement had to ask for a child's name as ordinary typed text, with nothing linking the finished form back to that child. A sibling plugin can now attach that information while the page is being built, and confirm it again when the form is sent. Gather Grove Booking 1.108.0 is the first to use it, to send a form link addressed to one member of a household.
* Added: the wording an entry was submitted against can now be read by the rest of the Gather Grove suite, not only stored. A plugin building a permanent copy of something someone signed — a PDF filed to their account, for instance — can ask for the exact wording that submission was made under, rather than reading whatever the form says today. That distinction is the entire point: rendering the live form would mean editing a clause quietly rewrites what a copy says a family agreed to.

= 1.11.0 =
* Added: a **Content** question type — a block of text you write, placed between the questions. Headings, paragraphs, lists, links and emphasis all work. It is the piece long agreements needed: a waiver clause, a policy section or an explanation can now sit directly above the question it governs, instead of being crammed into a step description or a line of help text. It asks nothing and stores nothing, so it never appears in your entries, your exports or a personal-data request — it is there to be read. It can be shown or hidden by the same conditional rules as any other question, and a step made only of content still gets its own screen.
* Added: an editor for the new Content question — a formatting toolbar for headings, bold, italic, links and lists, and a Preview button so you can read the block back the way the people filling in your form will see it.

= 1.10.3 =

= 1.10.2 =
* Changed: re-vendors gather-grove-core 0.22.0. The previously vendored copy (0.19.0) shipped without core's `assets/` directory, so if Forms' copy won the newest-copy-wins arbitration on a site, the shared Admin Shell's own CSS/JS 404'd. The vendored copy now carries core's assets, so that can never happen. The plugin-local design-token mirror was refreshed against the same core release (no visible color changes — it was already current).

= 1.10.1 =
* Fixed: the shared design tokens derived the pale "soft" tint of your primary color from the site's Elementor *secondary* color instead of from the primary itself. On themes where the secondary is its own hue rather than a lighter shade of the primary, every soft primary fill across the Gather Grove suite — type badges, @mention highlights, notice backgrounds — rendered primary-colored text on that unrelated color, sometimes near-unreadable (coral text on a gold pill, for instance). The tint is now derived from the resolved primary color itself, the same way the other derived shades already were.

= 1.10.0 =
* Added: two read-only lookup seams other Gather Grove plugins can verify a submission through — `gather_grove/forms/entry_lookup` (by the entry's public uuid, so it works for guests) and `gather_grove/forms/entry_search` (by the submitter's email or account, optionally narrowed to where the form was filled in). Neither returns drafts, spam, or trashed entries. Built for Gather Grove Booking's pre-booking intake forms, where a booking must not complete until the form is genuinely submitted.
* Added: the on-page form now announces a successful submission with a browser event (`gg-forms:submitted`) carrying which form and which entry — so another plugin's script (Booking's intake step) can react without guessing.

= 1.9.1 =

= 1.9.0 =
* Added: a **Payments** screen under Forms → Settings. Enter your Stripe key and webhook signing secret, copy the webhook URL to register, and see in plain words whether the site can currently take a payment *and* record it — the second of those fails silently otherwise, which is the expensive one. Stored keys are shown masked and never written back into the page. If you also run Gather Grove Booking, its Stripe key is used automatically and the screen tells you so.
* Added: **take payment when a form is submitted.** Turn on Payment in the form's settings, set a price, and optionally point it at a number question so "how many spaces?" multiplies the fee. The submitter is sent to Stripe's own checkout page to pay — no card details ever touch your site. The submission is saved and your notifications sent *before* they go to Stripe, so a declined card or an abandoned checkout still leaves you the application to follow up on. Payments only count as complete when Stripe confirms them via webhook, never on the strength of the browser coming back. Bank-transfer and other delayed payment methods are handled too — those settle days after checkout, and the fee is recorded when the money actually arrives. Needs a Stripe account; if you also run Gather Grove Booking, your existing Stripe keys are used automatically.
* Added: a file upload question can now accept more than one file. Set "Number of files" on the question and people can attach several at once — pick them in one go or add them one at a time — with each file listed and removable on its own. Previously every upload question took exactly one file, so asking for "up to five photos" meant five separate questions.
* Added: "Maximum total size" on file questions, a combined budget across every file attached to that one question. Files upload one at a time, so this is a storage limit rather than a request limit — a 75 MB total works fine on a server that would refuse a 75 MB upload.
* Changed: the per-file size ceiling is now 25 MB (was 10 MB), and the default combined budget is 75 MB. Both are still capped by whatever your host actually allows.
* Fixed: an entry that captured several files on one question only ever showed the last of them in the admin. The others were stored safely and were never lost — they simply had nowhere to appear.
* Fixed: notification emails printed a file question's internal reference instead of the filename, which told the reader nothing. They now name the attached file(s).

= 1.8.4 =
* Fixed: when a form is set to inherit your site's colours, buttons now use your colour on hover too. The hover and dark-accent shade was fixed to the Gather Grove green rather than derived from your palette, so an inheriting form could show your brand colour on a button and Grove green the moment you moused over it. The same applied to the soft accent wash. Both are now mixed from whichever colour your form actually resolved to.

= 1.8.3 =
* Fixed: a form placed inside anything that loads its content on demand — an Elementor popup, a modal, an off-canvas panel, an AJAX-loaded tab — was completely inert. Every control rendered correctly and nothing responded, because the frontend script only ever looked for forms once, the moment the page finished loading; a form whose markup arrived later was never hooked up. Forms are now also detected when they appear after page load, so a popup form behaves exactly like an inline one. Inline forms are unaffected, and a form is still only ever initialised once.

= 1.8.2 =

= 1.8.1 =
* Fixed: the plugin could not load at all on PHP 8.1 — a return type introduced with file uploads in 1.7.0 is only valid from PHP 8.2, so a site on 8.1 (which this plugin declares support for) hit a fatal error on activation.

= 1.8.0 =

= 1.7.0 =
* New field type: File upload. Attach a photo or document to a submission — the file is uploaded as soon as it is picked (with progress and a Remove button), so submitting stays instant. Per-field limits on accepted types and maximum size. Uploads are stored **outside the Media Library**, **encrypted at rest** (AES-256-GCM) under randomised filenames, and served only through a permission-checked endpoint. That last part matters more than it sounds: the usual trick of dropping an `.htaccess` in the folder does nothing on nginx, which ignores it — so on a great many WordPress hosts the "protected" folder isn't. Here the bytes on disk are ciphertext, so a server that serves them hands over noise and a stolen backup contains noise, with no server configuration required on your part. Attached files show up on the entry in the Entries screen with a download link, and a single "Copy to Media Library" button publishes one when the owner wants to — a testimonial photo, say. The plugin also tests the directory over real HTTP rather than assuming, and warns you only in the genuinely risky case — a server with no OpenSSL support (so nothing could be encrypted) that is also serving the folder. Every upload is validated on extension, declared type, and magic bytes (a PHP file renamed to .jpg is rejected); executable and SVG uploads are never accepted. Files attached to a submission are erased with it on a GDPR erasure request, and files whose form was never submitted are reclaimed automatically within a day.

= 1.6.0 =

= 1.5.0 =

= 1.4.0 =

= 1.3.6 =
* Confirmation messages now render as HTML in both render modes (classic and conversational), so a success message can carry a real link or emphasis. The message was already server-sanitized with `wp_kses_post` in anticipation of this; the frontend switches the confirmation slot from `textContent` to `innerHTML` behind that boundary (scripts and event-handler attributes never reach the browser). Plain-text messages render exactly as before.

= 1.3.5 =
* Fix: a first-ever activation with no other Gather Grove plugin active no longer fatals. `GG_Core_Loader`'s `plugins_loaded:0` boot hook never ran during the activation request (the plugin file loads after `plugins_loaded`), leaving core classes unloaded when `Activator::activate()` ran. The plugin now boots the winning core copy imperatively when `GG_Core_Loader::offer()` runs after `plugins_loaded` (idempotent; no-op otherwise). Guarded by `CoreActivationBootGuardTest`.
* Fix: on block themes the public form's runtime config (`window.ggFormsClassic` / `ggFormsConversational`) was localized too late — from the shortcode render — so the bundle printed without it and the form's conditional logic, calculations, save-and-resume, and AJAX submit/confirmation all silently no-op'd. The config is now localized when the bundle is registered (`wp_enqueue_scripts`), so it's always present before the script runs.

= 1.3.4 =
* Admin Shell detection now uses the gather-grove-core host signal (`Bootstrap::is_booted()`) instead of a `class_exists()` check. Since the Admin Shell moved into core — which every Gather Grove plugin bundles — the old check always reported "present," so Forms could not tell whether a shell host was actually active. No change to the unified menu you see. Re-vendors core 0.19.0.
* **Requires WordPress 6.8+** (the bundled Action Scheduler 4.0.0, shared across the Gather Grove suite, requires it).

= 1.3.3 =
* The plugin logger now delegates to the shared gather-grove-core logger (`GatherGrove\Core\Support\Logger`) instead of a per-plugin copy. Same `[GG Forms]` log prefix and the same no-PII policy; errors and warnings are now always logged (debug/info still only under WP_DEBUG). Re-vendors core 0.16.0.

= 1.3.2 =
* The REST API's permission + error-response helpers now come from the shared gather-grove-core package (`GatherGrove\Core\REST\Auth` + `Errors`) instead of a per-plugin copy. Forms led the reference implementation; it's now canonical and shared across the suite. No change to the API on the wire — same `gg_forms_*` error codes, same HTTP statuses. Re-vendors core 0.15.0.

= 1.3.1 =
* The Elementor widget's Palette control now comes from the shared gather-grove-core Kit trait (`GatherGrove\Core\Elementor\Kit\PaletteControls`, ADR 0001 payload 3c follow-on e) instead of a per-plugin copy. The choices (Inherit / Gather Grove default / Grove / Stone / River / Hearth) and the resulting styling are unchanged; the control is now canonical and shared with Booking.

= 1.3.0 =

= 1.2.0 =
* Brand palettes now come from the shared gather-grove-core package (`GatherGrove\Core\Brand\Palettes`, ADR 0001 payload 3b) instead of a per-plugin `PalettePresets` copy. The four named palettes (Grove / Stone / River / Hearth), the per-placement Inherit / Gather Grove default / named-preset compose model, and the render output are unchanged — the data + logic are now canonical and shared with Booking. Vendors core 0.5.0.

= 1.1.1 =
* Re-vendors gather-grove-core 0.4.1, which brands the unified Gather Grove admin (Dashboard / Integrations host pages + the at-a-glance widget) with the studio palette. No Forms-side behaviour change.

= 1.1.0 =
* Brand StyleBridge now comes from the shared gather-grove-core package (`GatherGrove\Core\Brand\StyleBridge`, ADR 0001 payload 3a) instead of a per-plugin copy — the studio brand cascade is unchanged, but the logic is now canonical and shared across Gather Grove plugins. Vendors core 0.4.0.

= 1.0.0 =
* First stable release. Classic and conversational (one-question-at-a-time) render modes, selectable per form, with welcome and outcome screens.
* Elementor Pro widget set with full Style controls and the Gather Grove appearance model (Inherit vs Gather Grove default, with opt-in Kit-armor).
* Ecosystem integrations via the `gather_grove/forms/integrations` filter: Booking ("Create Booking"), Notion Sync, and Companion adapters, plus Stripe and Google Sheets.
* Activity foundation — entry context round-trip and the `gather_grove/activity` surface.
* Consumes the shared gather-grove-core package via GG_Core_Loader (ADR 0001 Phase 3): Forms vendors its own core copy and the unified Admin Shell host comes up from the highest core version present across active Gather Grove plugins. Alongside Booking (or any sibling), Forms registers as a top-level module in the unified "Gather Grove" admin.

= 0.1.1 =
* Adopt the gather-grove-core admin-chrome theming.

= 0.1.0 =
* Phase 0 — Foundations. Plugin scaffolding, database schema, service container, lifecycle hooks. No user-facing features yet.
