== Changelog ==

Full release history for Tickets & Passes for WooCommerce. The three most recent releases are also listed in readme.txt.

= 1.2.2 =
* New: every row on the Tickets, Timeslot Tickets and Passes dashboards has a "Download" action, which hands you the same printable PDF the holder gets from My Account - their ticket or pass with its QR code on it. A customer who cannot find their email can now be helped from the screen you are already looking at, without resending anything. Guest passes get their own, on the row under the pass they belong to.
* The action only appears on rows whose QR code was actually issued, rather than being offered on every row and failing on the click. The PDF is drawn the first time it is asked for and kept, so a second download of the same ticket is immediate.

= 1.2.1 =
* Front end assets now load only where they are used: nothing on ordinary pages, the product page stylesheet only when a product shows its details list or start date picker, and each My Account tab's stylesheet and script only on that tab. Other My Account pages get just the two menu icons inline.
* Fixed the Cart and Checkout blocks running a ticket's "Valid from" and "Valid to" (and a pass's names) together on one line on Storefront and any other theme that drops WooCommerce's general stylesheet - the rule is now carried by the blocks' own stylesheets.
* The Timeslot Ticket calendar no longer restyles every air-datepicker on the page, only its own.
* The product page cards work on dark themes: the sunk strips, error washes and calendar hover cells are now mixed from the shop's chosen background colour instead of being fixed light tones, the Timeslot calendar's text colours follow the settings instead of being fixed dark greys, and the product details list ("Maximum uses", "Date") now wears the same colours as the picker beside it instead of always being white.
* Product page fields and buttons reset the padding, shadows and margins themes commonly put on every input, button, label and list item, so the cards look the same across themes without custom CSS.
* New: the Tickets, Timeslot Tickets and Passes dashboards have a "Download CSV" button. It exports every row the current search and status filter match - not just the page on screen - as plain text, with the holder, product, order, validity window and check-in count on each row. Passes also carry the buyer, the holder name and their guest passes. Cells that would otherwise be read as a spreadsheet formula are neutralised.
* Fixed the CSV exports emitting a PHP 8.4 deprecation notice, which on a site with display_errors on was written into the downloaded file. Quotes are now escaped by doubling, as RFC 4180 requires, rather than with a backslash no spreadsheet reads.
* Fixed the scanner's "Enter a code by hand" returning a sample result instead of really checking the code in, on any device without a camera - which is exactly the desk the feature exists for. A typed code now always goes to the server; the sample result is only for the Check In button when no code is waiting.
* Security: the sales window ("Purchasable between") is now enforced when an item is added to the cart, not only by hiding the buy button, on all three product types. The window's last day is now included in full.
* Security: a pass profile photo can no longer be replaced with a hand-built request once one has been uploaded, matching what the customer is told.
* Security: the admin "Resend" buttons send to the account the ticket or pass belongs to, taken from the database row rather than from the request.
* Security: a customer's billing name is escaped before it is placed into the order confirmation and resend emails, so a name containing a link cannot render as one.
* Security: the analytics CSV export neutralises cells that begin with =, +, - or @, so a customer name cannot become a live spreadsheet formula.
* Security: a guest pass scanned at the plain check-in URL now requires its parent pass to exist, exactly as the /guest URL does.
* Security: Basic Auth credentials arriving as PHP_AUTH_USER/PHP_AUTH_PW (some hosts never expose an Authorization header) are now treated as an outside caller and refused while "Enable API" is off.
* Fixed timeslot capacity being enforced only against live reservations at add-to-cart, and only against "sold >= capacity" at order completion: a line of three could be issued with one seat left, and with reservations off nothing was checked until after payment. Sold tickets, live reservations and the line's own quantity are now all counted, and an elapsed timeslot is refused at add-to-cart instead of after payment.
* Fixed recurring timeslots landing on the wrong weekday in most years. Week numbers now resolve as ISO-8601 weeks.
* Fixed recurring timeslot series stopping after their first N weeks instead of rolling forward N weeks ahead of today, as the setting says.
* Fixed the "Delete Reservation / Delete Orderline, WC Statuses" multi-selects never saving; the cron always used the defaults.
* Fixed a manually added timeslot under a recurring rule being retired by the next scheduled run when it sat outside the rule's week window.
* Fixed a one-week recurring rule (start week equal to end week) being silently dropped on save.
* Fixed the front-end timeslot date picker selecting the wrong day in browsers west of UTC.
* Fixed the pass roster being checked only after the item was already in the cart: an incomplete roster left an unnamed line behind. Every person is now validated before the cart is touched, and a rejected row is reported instead of silently dropped.
* Fixed resetting or cancelling a single timeslot ticket re-keying the order line's remaining tickets under the plain ticket key, which hid them from the emails and from a later cancel.
* Fixed a QR colour that was not a six-digit hex value causing a fatal error on product save, on QR preview and on order completion. Colours are validated on save and the QR renderer accepts #rgb and #rrggbb.
* Fixed the QR label text being stored HTML-encoded, so "&" printed as "&amp;" inside the QR image.
* Fixed reinstating a refunded-then-completed pass leaving its guest passes cancelled, so My Account minted a new set and the guest codes already handed out stopped working.
* Fixed a gifted pass whose recipient account could not be created being inserted with no owner.
* Fixed the dashboards showing the whole table's page count while searching (the Passes dashboard counted guest passes too), rows being listed oldest-first within each page, order links 404ing under HPOS, and the Passes dashboard fatalling when a buyer's account had been deleted.
* Fixed the yearly analytics counting the following year's 1 January into the selected year, the CSV export fatalling when the range had no check-ins, and the product filter showing at most ten products per type.
* Fixed the Scanner / API settings screen reporting the 202 and 200 colour fields as "406", and a blank colour leaving the scanner's result banner with no background.
* Fixed the timeslot ticket "Add to Calendar" link being sent with both the API and scanner switched off, when the address it points to does not exist, and calendar events landing off by the site's UTC offset.
* Fixed the QR-code table being injected into plain-text emails and the customer greeting being sent in the admin's copy of a new-order email.
* Fixed the ticket PDF printing raw database timestamps where the pass PDF prints the shop's date format.
* Fixed the settings screens' content rendering outside the WordPress page wrapper.
* Fixed the profile photo upload updating the database when the file could not be written (hiding the upload button for good), an Imagick failure returning a bare 500, a GD build without WebP support fatalling on a WebP upload, PNG transparency turning black, and an oversize upload reporting "not an image".
* Fixed the order actions metabox only appearing with HPOS order storage.
* Fixed the pass reset writing a duplicate order-line meta row on every reset, and the pass cancel not stamping its "updated" column.
* Fixed the My Account passes list having no defined order.
* Fixed the nano id generator's masked mode reading past its random buffer, and `true` being treated as 'balanced'.
* Fixed the admin product-tab assets loading on every post and page editor rather than only on products.
* Text: "Resetted Anunalpass", "Ticket has successfully been resent" on the Passes dashboard, and the timeslot dashboard appending an ellipsis to every product name.
* Security: a gifted pass that creates an account for its recipient no longer emails a password. The email carries a one-time "choose your password" link instead, the same mechanism as "Lost your password?".
* Scanner: a code can now be typed or pasted from the menu, for a desk without a camera or a code the camera will not read. A refusal stays on screen for six seconds instead of two and a half, and any result can be tapped away.
* Dashboards: Cancel, Reset and Remove photo ask for confirmation first; Resend now says "Sent" on the button when the email went out; rows whose order has since been deleted are listed instead of silently dropped.
* Timeslot product page: says "no upcoming timeslots" instead of rendering nothing, and the cart's "Reservation Time Left" reads "5 mins" rather than a raw (sometimes negative) number of seconds.
* My Account: the Guest Pass button is hidden when the product grants none; the passes and tickets tabs list up to 200 items instead of 20.
* Email settings save now works with the visual editor switched off or on its "Text" tab.
* Colour reset buttons on the product QR tabs repaint the preview card immediately.
* The four QR tabs on a pass product no longer share duplicate field ids, so each label focuses its own field.
* A resend whose subject exceeds 150 characters is trimmed instead of silently not sent.
* Faster admin dashboards and timeslot product pages: indexes added on the created and timeslot start columns (database version 1.0.2, applied on the next load).
* Removed the unused media-library scripts from the General and Pass settings screens, the stray Settings-API nonce fields printed outside any form, and the pass product stylesheet from every non-pass page.
* Uninstall with TPFW_REMOVE_ALL_DATA now also removes the plugin's product settings and order-line ids.
* New: tickets and timeslot tickets can be transferred to another customer from their dashboards. The Transfer button asks for the new holder's email address or user ID (they need an account on the site), moves the ticket to that account, emails them the QR code with the resend template, and adds a note to the original order naming both parties and the admin who did it.
* Scanner: the result notice now slides in with a plain ease-out instead of a bounce.
* Internal: the Ticket Settings and Pass Settings product tabs (Product Note, Access & Usage, Check-in Rules, Sales Window, Validity Window) are one renderer and one save handler on the product-type base instead of two copies; the pass profile-photo settings moved into the Pass Settings save, and its compression method is validated against the libraries the server actually has.
* Dashboards: the Tickets, Timeslot Tickets and Passes screens can now be sorted by column, filtered by status (Unused, Partial, Used, Expired, Not valid yet, Cancelled; Active, Expired, Not valid yet, Cancelled for passes), and rows can be cancelled or reset in bulk with a checkbox column. The Passes search also matches holder names.
* Scanner: a flashlight button appears on phones whose camera supports one.
* Customers checking their own ticket in from My Account now respect its validity window; only staff may check in outside it.
* Timeslot reservations on refunded or trashed orders are released instead of being re-examined every minute for ever.
* Internal: the three dashboard screens are one shared implementation (menu, assets, list table, row actions, bulk actions, one script and one stylesheet) instead of three copies; the six settings tabs share one page shell and, for the three product-type tabs, one save handler and one script; the three product types share one QR writer and one manual check-in handler. About 2,400 lines of duplicated code removed.
* Internal: the ticket and timeslot ticket reset/cancel helpers are one implementation instead of four copies, with a test covering the order-line renumbering they share.
* Fixed the check-in scanner page triggering a "Function print_emoji_styles is deprecated" notice. The page asked WordPress for every registered stylesheet and script instead of naming its own, which also pulled in the assets of every other active plugin.
* Security: an uploaded pass profile photo now has to look like a JPEG, PNG or WebP to both of the checks it goes through, rather than only to the second one.
* Security: the QR preview endpoint validates the posted logo id as an attachment id instead of passing the raw value on.
* Fixed cancelling a pass leaving its guest passes' QR images on disk, still reachable through the signed links that had been emailed out. They are deleted with the pass now.
* Fixed the thank-you page and My Account order view hiding order line details belonging to other plugins.
* Fixed a deprecation notice on PHP 8.1 and newer when another plugin adds an order line detail with no key.
* A check-in of an unrecognised type is now refused outright rather than proceeding with no rules to check against.
* Internal: reservation and pass writes use $wpdb->query() rather than asking a result set back from an UPDATE or DELETE, and the remaining loose in_array() comparisons are strict.
* Developer note: `TPFW_Ticket_Dashboard`, `TPFW_Timeslot_Ticket_Dashboard` and `TPFW_Pass_Dashboard` now extend `TPFW_Dashboard`; their list tables extend `TPFW_Dashboard_Table`. The per-screen `tpfwParams*Dashboard` script objects are replaced by one `tpfwParamsDashboard`, and row-action buttons carry `data-kind`/`data-action` instead of per-type classes. The settings classes extend `TPFW_Settings_Tab` (`TPFW_Type_Settings_Tab` for Ticket, Timeslot Ticket and Pass) and localize `tpfwParamsSettingsTab`; `theme_settings_page()`/`theme_settings_init()` are gone. The product classes' `ajax_checkin_*_callback()` methods delegate to `TPFW_Product_Type::ajax_checkin_callback()`.
* Developer note: `TPFW_Functions::get_pass_user()` returns `sSetPasswordURL` instead of `sNewUserPassword`, and `gifted_pass_email_new_user_replacement()` takes that URL as its last argument.
* Developer note: `TPFW_Functions::get_api_settings_options()` now back-fills empty colour keys with the defaults and accepts `true` to return the defaults; new helpers `is_within_sales_window()`, `is_valid_ymd()`, `get_order_edit_url()` and `local_to_ics_utc()`. `cancel_entry()` on the ticket and timeslot classes now returns `bStatus => true` on success, as documented.

= 1.2.0 =
* The plugin now runs on PHP 8.0 and WordPress 6.5, down from PHP 8.1 and WordPress 6.8. Nothing was given up to reach them: the bundled QR code and PDF libraries moved to versions that still support PHP 8.0, and the codes they draw are identical to the ones before.
* Security: QR codes, pass profile photos and ticket PDFs are no longer reachable at a public URL. They are stored in a folder with a random name and delivered through the plugin, which checks on every request that the caller either holds a signed link from their own email or is signed in as the person the ticket belongs to. Nothing to configure - no .htaccess editing, and it works the same on Apache, nginx and IIS.
* Responses are marked private and per-visitor, so a page cache or CDN can never hand one customer's ticket to the next visitor. Images are still cached by the customer's own browser, so nothing gets slower.
* Upgrading brings your existing files with it. Every QR code, guest pass, ticket PDF, preview and profile photo already issued is moved into the new protected folder during the update, so the links customers are already holding keep working.
* Removed the "Profile Photo Upload Path" box from Pass settings. Photos are kept in the plugin's own protected folder along with everything else, so there is no longer a path to choose. A folder someone deliberately set before this update is still used.
* Fixed the QR code preview going blank on the ticket, timeslot ticket, pass and guest pass product tabs. The image was being drawn correctly and then asked for at an address the plugin turned down, so the panel showed nothing.
* Fixed a new pass profile photo, and a freshly saved QR preview, still showing the picture they replaced. Both are written to the same address as the old one, and the browser had been told to keep that address for a year without ever checking back. It checks now, and is told "unchanged" without downloading anything when nothing has.

= 1.1.0 =
* Internal clean-up: the pass, ticket and timeslot ticket product types now share one implementation of their QR design panels, QR previews, duration fields and order handling instead of three to four separate copies. Around 800 lines of duplicated code are gone; nothing changes in what a shop manager or customer sees.
* Fixed: clearing a QR label text no longer silently deletes the stored label colour on pass, guest pass and ticket products. The colour now follows its own field.

**Developer note:** the public methods `tpfw_woocommerce_order_completed_pass_callback`, `tpfw_woocommerce_order_cancelled_pass_callback`, `tpfw_woocommerce_order_completed_ticket_callback`, `tpfw_woocommerce_order_cancelled_ticket_callback`, `tpfw_woocommerce_order_completed_timeslot_ticket_callback` and `tpfw_woocommerce_order_cancelled_timeslot_ticket_callback` are renamed to `order_completed()` / `order_cancelled()` on their product classes. Code calling `remove_action()` (or calling these directly) with the old names must be updated. The QR preview AJAX endpoints now answer with `sPreviewURL` instead of the per-type `s*PreviewURL` keys.

= 1.0.8 =
* Fixed recurring timeslots being built twice and expired reservations being cleared twice on every scheduled run. On a site selling timeslot tickets the plugin started two copies of its scheduler, so every hourly and every minute job ran through twice.
* Fixed the profile photo upload failing with a blank page on servers that have only one of the two supported image libraries installed. It now says which compression method the product is set to and that the server cannot provide it.
* Fixed the dates on order lines going unlabelled on the thank-you page and in My Account. A second, shorter list of labels was applied there, and it did not cover the customer-chosen start date, a fixed start date or "Valid to" - those lines showed a bare date. All screens now read the same list.
* Faster Tickets tab in My Account. The page counted each ticket's check-ins with its own database query, so a customer holding a full page of tickets paid for twenty extra queries to open the tab. It now counts them all in one go.
* Faster Passes tab in My Account. Every pass card loaded its whole order from the database and then used nothing from it.
* Settings tabs in wp-admin are now ordinary links. They can be middle-clicked, opened in a new tab, and they still work if a script on the page fails.
* PDF generation can no longer fetch files from other servers. Every image in a ticket or pass PDF is embedded in the PDF itself, so nothing needed fetching, and the setting that allowed it is now off.
* The profile photo upload no longer sends your account id and order id with the file. Neither was used to decide anything - who owns the pass is checked against your logged-in session - so they are simply gone.
* Removed around 450 lines of code that nothing called, including an empty stylesheet that was loaded on every wp-admin screen and a set of unused report queries.

= 1.0.7 =
* Reworked check-in. Ticket, timeslot ticket, pass and guest pass all ran their own copy of the same check-in, which is how they came to disagree with each other and with the documented API. They now share one implementation: a refused check-in answers 202 for every type, as the API reference on the Scanner / API settings screen has always said it does.
* Fixed the scanner drawing a green tick on a refused scan. A ticket that was already used, on cooldown, outside its dates or being scanned at another door answers 202, and the check-in page read anything in the 200s as a success - door staff were shown a tick and let the person through.
* Scanning a guest pass now applies the guest pass cooldown rather than the parent pass's.
* Faster check-ins and a faster history list. A scan counts a code's previous uses in the database instead of fetching every one of them, the history drawer fetches its holder names in one query rather than one per row, and the stats tables gained the index that list sorts on.
* Faster Analytics screen. The three charts and the CSV export each read the check-ins with their own near-identical query, one of which re-read the same table as a subquery just to apply the product filter. They now share one query, and the export looks up every buyer and product in one go instead of once per row.
* Faster ticket, timeslot ticket and pass dashboards. Each row on a page looked its product up on its own, and the pass dashboard looked its buyer up on its own as well; a page of rows now costs a couple of queries rather than a couple per row.
* Faster timeslot ticket product page. Every timeslot on the page ran two full table reads and two settings lookups to work out how many places were left. The page now counts all timeslots at once, which shows most on products with a long list of timeslots.
* Fixed a QR code changing appearance when a ticket, timeslot ticket or pass was reset. The four places that redrew a code each read its colour settings separately, and an unset colour came back random rather than the shipped default.
* Reviewed the whole plugin against the wordpress.org plugin guidelines: the profile photo upload now reads image dimensions through WordPress's own wp_getimagesize() instead of a silenced PHP call, a misspelled internal hook callback name was corrected, and the last undocumented functions in the PHP and JavaScript received their doc comments.
* Redesigned the product details list and the start date picker on the front end. Both now use one card design shared by tickets, timeslot tickets and passes, so a shop selling more than one product type shows one consistent block. The picker also states the validity window the chosen start date produces.
* Rebuilt the person fields on a pass product page as a roster: one row per person, the party size stepper in the block header, initials once a person is named, an email toggle per row, and a "named so far" counter.
* Tickets and passes can now let the customer choose when their validity starts, within a range you set on the product, or start from a fixed date you pick instead. The chosen date is checked against the range again when the item is added to the cart, so a date outside it cannot be posted through.
* "Valid from" and "Valid to" are now the wording everywhere - on the product page, in the cart, at checkout, in the emails, on the PDF and in My Account - and the date the customer picked is shown alongside the validity window it produces.
* Renamed "Max Users" to "Max Uses" on all three product types. It has always been the number of times a code may be scanned, not a number of people.
* Added date picker customization to the Ticket settings screen: hint text and colors for accent, text, border, background, hint, day names and the month/year title, matching what Timeslot Ticket already had.
* Rebuilt the timeslot picker on a timeslot ticket product page on the front end. Timeslots are grouped under the day they run on, each one states its time, how long it lasts and how many places are left, and a sold out timeslot says so instead of being silently unclickable.
* Rebuilt the Timeslots card on the timeslot ticket product settings tab as a schedule rather than a list of forms. Timeslots are grouped under the date they share, each row shows when it runs, a capacity meter with the places sold and whether it is upcoming, full or past, and a Past / Upcoming / All filter with a running total of places sold sits above and below the list.
* Recurring timeslots now read as the rule they are - "Every Monday, 10:00-11:00, weeks 30-52, 12 places each" - with the six fields that encode it folded away behind the row, and the timeslots the rule has generated listed underneath when it is opened.
* Added a reset button to every color row on the Ticket, Timeslot Ticket, Pass and Scanner / API settings screens, and to the QR code colors on the ticket, timeslot ticket and pass product settings tabs, which puts the shipped default color back.
* Reordered the cards on the pass product settings tab so the two short cards sit side by side, and the duration fields there now show their explanation under the field instead of in a help tip.
* Tidied up the product settings tabs in wp-admin: labels above their fields, one left edge for labels, fields and descriptions, and more room above each label. The timeslot ticket product tabs now use the same cards as the ticket and pass tabs, and their duration fields explain themselves under the field instead of in a help tip.
* Order lines on the thank-you page and in My Account now name their dates. The purchase stored them under its own internal keys, so a ticket listed a bare date with no label at all. The customer-picked start date is also printed in the shop's own date format now, so it no longer sits beside "Valid to" in a different format.
* Renamed the sales window label from "Available to buy" to "Purchasable between".
* Fixed recurring timeslots landing on the wrong dates. A rule was turned into dates from its week numbers without deciding which year those weeks belonged to, so a rule set up late in the year generated its timeslots twelve months out and the day it ran on was missing from the front-end picker. Changing a rule's weeks now also retires the timeslots it generated under the old ones.
* Fixed the "Create recurring timeslots" button appearing to do nothing. It looked the product up by a value of the wrong type, matched no rule and returned silently.
* Fixed the end of a sales window being accepted before its start on all three product types.
* Fixed the columns of a newly added timeslot row not lining up with the rows already there.
* Fixed the Ticket settings screen not saving. A missing semicolon meant the whole script threw before the save button was wired up.

= 1.0.6 =
* Added a per-product note for tickets, timeslot tickets and passes. The note is set on the product's settings tab and follows the purchase through to the order emails, the resend emails, the PDF, the order details on the frontend and the My Account tickets and passes tabs.
* Added an editor for the WooCommerce completed order email, so the text that goes out beside the QR codes can be written from the email settings screen like the order confirmation text. It supports the same tags: {{site_name}}, {{site_login}}, {{site_url}}, {{myaccount_url}}, {{customer_name}} and {{product_note}}.
* All email types now ship with default text and placeholders. Resend and gifted pass emails previously sent nothing at all until the templates were filled in by hand.
* The email settings screen now shows the default template when a field has not been customised, instead of an empty box.
* Reworded the default order confirmation text so it no longer says the QR codes are below it. The codes are not issued until the order is completed, so that email has nothing to show yet.
* Added cancel and refresh buttons to the QR check-in scanner.
* Added navigation icons to the My Account tickets and passes tabs.
* Renamed "Customer Note" to "Product Note" on the ticket, timeslot ticket and pass settings tabs, and moved the help tip in front of the field so the note card lines up with every other card.
* Fixed the order confirmation text never being sent: the whole block was skipped whenever the order had no QR codes yet, which is every order that has not been completed.
* Fixed "Valid From" and "Valid To" sharing a line in the mini cart.
* Fixed the ticket, timeslot ticket and pass dashboards printing an empty "0 items" line above the page title, by no longer registering pagination before the item count is known.
* Fixed the first dashboard column ("User ID") losing its centring. WordPress renders that column as a table header cell, which the centring rule did not cover.
* Fixed the date picker being cut off inside the product settings boxes in wp-admin, and made it scroll itself into view when opened.
* Rewrote readme.txt. The description now explains the three product types, the scanner and the Scanner role in plain language, the installation guide is cut down to installing the plugin, enabling the product types and the scanner, and finding both afterwards, and the email settings section now mentions the completed order template added in this release.
* Split "Enable API" and "Enable built-in scanner" into two independent switches. The check-in page at /check-in/ no longer needs the API turned on, and turning the API on is now only about letting an outside app authenticate against the endpoints. The scan result colors show while either one is on.
* Added an API endpoint reference to the Scanner / API settings screen, alongside a note on when a standalone native scanner app is a better fit than the built-in check-in page.

= 1.0.5 =
* Removed the Event Calendar block. It did not work reliably, and it will return once it can be rebuilt properly.
* Updated the readme.txt screenshot list to match the screenshots currently available.

= 1.0.4 =
* The ticket and pass PDF stylesheets are handed to the PDF renderer through its own stylesheet API, so the plugin no longer writes a <style> block into any markup it produces.

= 1.0.3 =
* Settings are now sanitized per field rather than by a single catch-all callback: textareas keep their line breaks, colour fields are validated as HEX, and the email templates keep the markup they are meant to carry.
* Fixed the Scanner / API settings screen registering the wrong option groups, which left it printing a nonce for a group that was never registered.
* Every value the ticket, timeslot ticket and pass dashboards output is now escaped as it is echoed.
* The ticket and pass PDF styles moved out of inline <style> blocks into their own stylesheets.
* The JavaScript variables this plugin puts on the page now carry the tpfw prefix, and every option name is written out in full so it can be found by a search.
* Corrected the misspelled "generel" in the shared settings option name and everything built from it.

= 1.0.2 =
* Every name this plugin registers or stores now carries the four character `tpfw` prefix: PHP classes, functions and constants, options, database tables, product and order line meta keys, the three product types, the Scanner role and the My Account endpoints.
* Scripts are now loaded in the footer.
* Fixed the timeslot date picker not appearing on the product page with block themes.
* Updated bundled ApexCharts to 6.9.0 and Air Datepicker to 3.6.0.
* Documented bundled third-party libraries and their sources in the readme.

= 1.0.1 =
* All backend pages added by this plugin are now prefixed with tpfw, so they cannot collide with pages added by other plugins.

= 1.0.0 =
* Initial release.

