= 4.7.0 =
Correctness and load. Three settings that had never done anything now work, the
slot generator stopped re-querying the database once per candidate time, and the
booking day lock has one implementation again instead of two that had drifted.

* Added a configurable 90-day online booking horizon, enforced in the calendar,
  AJAX/REST availability and every customer booking write path.
* Store the visitor's validated IANA time zone and show a companion local time
  for Zoom and Google Meet appointments on review and confirmation screens.
* Completed keyboard focus management across the booking wizard and its modal
  dialogs, including focus return, Escape-to-close and live step announcements.
* Webhooks now support multiple independently signed endpoints with per-endpoint
  event subscriptions. Added payment captured, refund issued, customer created,
  gift-card redeemed and automation-triggered events.
* Expanded Pro Automations with payment/refund triggers, signed-webhook actions
  and internal booking notes.
* Moved uninstall cleanup into Freemius's `after_uninstall` callback so release
  packages no longer ship an `uninstall.php` entry point.
* Added a reproducible Terser build, asset manifest, dependency-free regression
  tests, PHP linting configuration and GitHub Actions release checks.
* Split the booking frontend into a first-step CSS core, a lazy later-step CSS
  flow, a lazy calendar/availability engine and a lazy payment-provider module.
  The production loader keeps RTL and final cascade overrides intact and no
  longer sends WordPress admin-only polish rules to booking-page visitors.
* Fixed the CSS splitter treating the letters "ai" inside `main` and
  `container` as an AI feature selector, which moved first-paint width rules
  into the lazy chunk and squeezed service cards into a narrow column.
* Made frontend splitting deterministic across LF and CRLF checkouts, refreshed
  every manifest checksum/byte count, and removed the superseded monolithic JS,
  CSS, RTL CSS and their orphaned translation catalogs from release packages.
* Removed translated-button-text branching from the booking wizard, added an
  explicit checkout-state attribute, and completed the maintained locale
  catalogs for the upload and service/time selection status messages.
* Free packages now declare the non-premium Freemius flags explicitly and omit
  every Pro implementation file; Pro packages retain the premium SDK flags.
* Reconciled every static `frontend.js` message into POT/PO/JSON catalogs,
  rebuilt all seven binary MO catalogs, and changed translation coverage to
  report only non-empty translated entries. Untranslated strings intentionally
  fall back to English instead of being counted as 100% translated.

* Fixed per-service **Buffer before**, **Buffer after** and **Minimum lead time**
  doing nothing at all. The three columns have been editable in Services, saved,
  exported to CSV and exposed over REST since 4.2, but no availability, slot
  generation or conflict code ever read them. A salon that set "15 minutes after"
  on a colour service to allow for cleanup was still offered back-to-back times,
  while the settings screen reported the value as saved. Both slot generators and
  all three server-side validators in the booking creator now widen the occupied
  window by the buffers on each side: an existing appointment reserves the buffers
  its own service asked for, and the appointment being booked reserves its own.
  Availability on sites that had configured buffers will legitimately tighten
  after this update -- that is the setting finally taking effect.
* Fixed the Setup Wizard's **Minimum advance notice (hours)** having no effect.
  It wrote yatoon_min_advance_hours and nothing read it; the slot generator was
  reading yatoon_manage_min_hours_before instead, which is the cutoff for changing
  or cancelling an appointment that already exists. Two unrelated policies shared
  one control and the visible one was inert. They are now separate settings. Sites
  that never touched the wizard inherit the value that was actually in effect, so
  nothing changes for them; a site that did set a value gets a one-time notice
  explaining that it is now live, because near-term times will stop being offered.
* Fixed the advance-notice window being enforced only in the picker. Nothing on
  the write path checked it, so a direct POST or REST call could book a time five
  minutes out, or in the past. All three booking validators now check it.
* Fixed the booking day lock existing twice. 4.7.0's "lock every calendar day a
  booking touches, including the days in between" fix went into
  YATOON_Booking_Lock, but the front-end booking path called a private copy in
  the AJAX controller that still locked only the first and last day. The copy is
  now a thin adapter over the shared class.
* Fixed Vagaro mode taking no calendar lock. Square can safely go unlocked because
  Square owns the calendar and rejects conflicts itself, but the Vagaro
  integration is a one-way push that never turns a booking down, so Vagaro sites
  had neither a local lock nor a remote arbiter and two simultaneous customers
  could both be written and both be pushed. Vagaro now locks and blocks overlaps
  exactly as Local mode does.
* Added a Site Health check for advisory locks. GET_LOCK is the only thing making
  "check the slot, then write the booking" a single step, and several situations
  remove it silently: a managed database that disables it, a multi-writer cluster
  where locks do not span nodes, a drop-in that routes reads to a replica. None of
  this was visible from the admin before. Tools > Site Health now says so plainly,
  Yatoon screens carry a warning, and a booking refused for this reason is logged
  and tells the customer to call the salon rather than looping them on "try again".
* Performance: the slot generator no longer queries per candidate time. Group
  sessions, shared resources, staff time off and connected-calendar busy periods
  are gathered once for the day and every candidate is answered from memory. A
  ten-hour day at fifteen-minute granularity ran well over a hundred queries per
  staff member, and close to a thousand under "Any staff"; it is now a handful,
  regardless of how many times a day contains. YATOON_Resources gains
  day_planner() and plan_allows() for this, with identical capacity arithmetic.
* Performance: the eleven feature-module switches are primed in one read instead
  of eleven. They are stored with autoload = false, which is correct, but
  enabled() runs at include time on every request, so a site without a persistent
  object cache paid eleven uncached queries on every page view -- front page,
  wp-admin, admin-ajax, REST and cron alike.
* Performance: the booking page primed one option row per service to read option
  groups. A catalogue of 200 services meant 200 separate uncached queries on every
  render; they are now fetched together.
* Performance: booked-slot lookups moved from DATE(start_time) = ? to an overlap
  window, which can use the (staff_id, start_time, status) index and also catches
  an appointment that began the previous evening.
* Staff portal sessions moved from transients to their own table. A persistent
  object cache running an LRU eviction policy can drop a transient at any moment,
  which showed up as a stylist being signed out mid-shift at random with nothing
  in any log to explain it. Transients remain the fallback where the table cannot
  be created, and tokens issued before the update keep working until they expire.

* Save the booking and its replacement options in one checked transaction; roll back on write failure.
* Use the actual booked duration, including add-ons, when checking reschedule availability for every service segment.
* Lock every calendar day touched by a booking, including intervening days.
* Add focus containment, Escape handling and focus return to the remove-appointment dialog.
* Include CLI release checks, storage failure tests, a reproducible asset builder and separate editable CSS components.
All changes since the last public release, 4.6.2, are included here.

* Booking summary: separate service information and Edit/Remove actions; responsive controls, wrapping names and accessible focus styles.
* Booking recovery: handle offline, timeout and malformed responses without endless loading or silent step skipping; recoverable read-only retries.
* Customer changes: shared appointment locks, cancellation/reschedule cutoffs and finished-status guards across manage links and customer portal; calendar locks around portal availability checks and mutations.
* Cancellation: validate explicit service ID lists, check database failures, and queue customer notifications rather than blocking the response.
* Security hardening: whitelist OTP channels, add IP-wide verification quotas, bound OTP expiry, and escape dynamic summary/slot/error content.
* Preserve Google location preview, improved option disclosure cards, Professional / Confirm labels, design-upload fixes, and Free/Pro entitlements.
* Rebuild production JS, CSS, RTL and translation catalogs. Display version 4.7.0; existing database schema 4.6.4 is unchanged (upgrades from 4.6.2 include the bundled schedule migration).
* Fixed the Edit Service Save button silently wiping a service's cover image. The database update's format array had one fewer entry than its data array, so every field after it shifted one column - image_url landed on the format meant for a numeric column and was cast to an integer before the query ran, turning any photo URL into 0. WordPress then treats that '0' as empty, so the booking page fell back to the plain letter placeholder even though the image was uploaded, previewed correctly in the modal, and reported as saved. Any service saved through that screen while the bug was present has 0 stored for its image - reopen the service and re-save the cover image once to restore it.
* Fixed a total that includes an option priced by design being shown as if it were the final price. A $45 fill-in plus "Standard Nail Art (Price varies by design)" added zero for the nail art and then printed "$45.00" on the summary, in the cart, at checkout, on the confirmation page, in the confirmation email and in the customer portal - a customer had every reason to read that as the price. Those amounts now show as "$45.00+", and every total is followed by one line saying it is a starting price and that items priced by design are quoted in salon. The test for "varies" is the same one the option card already uses, so a price shown as "Price varies" when it was picked also marks the totals it feeds into; a normally priced add-on such as French Tips is unaffected.
* Step 3 no longer jumps to the date picker the moment a staff card is tapped. Choosing a person is confirmed with Continue again, as it was before 4.6.2. On a grid of small photos a mis-tap is easy, and auto-advancing turned it into being carried onto the next step before you could see who you had hit - Back plus a re-tap to undo. Step 2's single-choice auto-advance is unchanged.
* Fixed a Square day with a multi-employee booking on it reporting "No available times" for a service + add-on. Square hands one customer from one employee to the next inside a single booking (Yoyo 2:00-3:15, then Jen 3:15-4:45). The add-on double-check summed EVERY segment of such a booking and marked that whole block busy for EVERY employee named in it, so Yoyo looked occupied from 2:00 to 4:45 PM and her real 3:15/3:30/3:45/4:00 openings - which Square itself had just returned - were all deleted. Each segment is now charged to its own employee at its own offset. The same employee with two separate services was never affected because that path does not run this filter, which is why one service plus an add-on failed while two services succeeded on the same day.
* Fixed the Continue button on step 2 going dead after jumping back to Options from the progress bar. The jump cleared the chosen options without repainting the step, so the option cards kept their checkmarks while the widget believed nothing was selected. Re-picking could not fix it either: the main option is a radio that is already checked, so tapping it fires no change event. Step 2 now keeps the selection and reloads like every other backwards path, and it repairs itself if the cards and the stored selection ever disagree.
* Rebuilt assets/js/yatoon-booking-bundle.min.js, which is what the booking page actually loads outside SCRIPT_DEBUG. It was last built before the previous release's frontend changes, so several shipped fixes were not reaching visitors.
* Refactored the 3,000-line booking endpoint into a dedicated booking-creation application service; the AJAX controller is now a small compatibility adapter.
* Migrated weekly business hours and per-staff time off from wp_options into the structured yatoon_schedules table. Weekly schedules support multiple working intervals per day, providing the storage foundation for staggered processing-time schedules.
* Added a safe, retryable migration with a pre-migration snapshot, verified InnoDB transactions, an explicit seven-day completion marker, batched staff time-off conversion, and an authoritative legacy fallback when a table write fails.
* Fix: customer cancellation now settles its loading state on every response, times out after 30 seconds, and refreshes full and partial cancellations with a cache-busting URL.
* Fix: cancellation emails and integration callbacks run through the existing durable job queue after the booking update, with WP-Cron fallback. Mail failures can retry without holding the customer page open.
* Improve: compact option disclosure cards with selected summaries, large tap targets, keyboard support, and contextual clear buttons; required/single/multiple rules are unchanged.
* Improve: customer booking steps now use Professional and Confirm. Internal staff identifiers and admin labels remain compatible.
* Add: compact Google Maps location preview and directions link on both booking confirmation templates, using the configured business address.
* Build: regenerate production JavaScript, bundle, final CSS, RTL and asset hashes. The internal schema marker remains 4.6.4; upgrades from 4.6.2 run the bundled migration.
* Fixed the Edit Service Save button silently wiping a service's cover image (a database format-array misalignment cast the image URL to 0). Re-save the cover image once on any service edited while the bug was present.
* Refactored booking creation into a dedicated application service.
* Moved weekly availability and staff time off from wp_options to a structured schedule table with safe automatic migration. The storage and server-side validation support multiple daily work intervals; the current settings screen still manages one opening window with one optional break.

= 4.6.2 =
* BREAKING CHANGE - fonts: remote Google Fonts loading was removed for privacy and GDPR reasons and was NOT replaced with self-hosted font files. The Brand & Colors font setting now only adds the chosen family name to the CSS font stack, so it has a visible effect only where the active theme, a child theme, or another plugin already serves that font locally; otherwise the booking page falls back to the system font. A site that was relying on Yatoon to fetch Inter, Poppins, Roboto, Montserrat, Lato, or Playfair Display will look different after updating. This is a deliberate behaviour change, not a fix, and the only way to restore the old appearance is to host the font yourself. The setting screen now says all of this in place of the previous wording.
* New - no-show tracking and automatic deposits (Pro), the feature the Add-ons screen and the upgrade prompts have advertised since 4.5 and that had no implementation behind it at all: the "No-show Tracking" menu item simply opened the General settings tab. Yatoon now counts how many times a customer has been marked No Show inside a window you choose (3 in 12 months by default) and either requires a deposit on their next booking or flags them for staff, with a screen listing every flagged customer and a one-click permanent exemption for anyone marked no-show by mistake. Customers are matched by the email address or phone number on the appointment - the same weak link the rest of the plugin uses - so someone booking under two different addresses counts as two people; the screen says so. Requiring a deposit reuses the amount and gateway already configured under Payments, and warns you when no gateway is configured and therefore nothing can actually be charged. The rule attaches nothing to the booking path while it is switched off.
* Fixed a brand new Pro install hiding roughly half of what was just paid for. The runtime profile is picked while the plugin file is still loading, before the licence state is knowable, so every fresh install landed on the lean "local" profile - which leaves Reports, Orders & Invoices, Shared resources, Staff x Location rules, Group sessions, the Operations centre, the REST API and the AI assistant switched off, with no menu entry anywhere to suggest they existed. A licensed Pro site is now promoted once to the complete profile as soon as the licence can be read, and a site that upgrades to Pro later is promoted then. Sites where an administrator has already chosen a profile are never overridden.
* Added a visible way to find switched-off modules on any profile: the Feature Modules menu entry now carries a count of what is disabled, and Yatoon admin screens show a dismissible notice naming each switched-off module with a direct link to its switch. Previously the only route was the admin search box, which requires already knowing the feature exists.
* Fixed the plugin never loading its own translations. The package ships seven compiled catalogs in /languages and called load_plugin_textdomain() zero times. WordPress 6.7+ can register them from the plugin header, which hid the problem in development, but this plugin supports WordPress 5.8 and nothing registered them there - so on 5.8 through 6.6 the admin stayed English in every locale. The loader now runs on 'init' on WordPress 6.7+ and on 'plugins_loaded' below it, matching each version's requirement.
* Fixed the Feature Modules runtime building translated strings while the plugin file was still loading, which both triggers WordPress 6.7's "translation loaded too early" warning and freezes the text domain as untranslated for the rest of the request. The runtime module lists no longer contain translated labels at all.
* Replaced the two file-level phpcs:disable directives in the settings template with one ignore per statement, each stating its reason. The first had no matching phpcs:enable, so it silenced database sniffs across the remaining 2,800 lines of the file, including code written years later.
* Added bin/release-checks.php, a pre-release assertion script covering the failure modes this release ran into twice: a manage-token query that forgets the expiry column, a ".min" asset that is not actually minified, a concatenated bundle that was not rebuilt after its inputs changed, a PHP parse error, and a missing direct-access guard. Run it with `php bin/release-checks.php`; any failure exits non-zero and explains why that assertion exists.
* Corrected several readme claims that overstated what ships. Vagaro is described as a one-way import plus booking creation rather than synchronization, because Yatoon sends Vagaro no reschedules and no cancellations, receives no Vagaro webhook and runs no scheduled re-pull. Square point of sale is described as recording a Square POS or Tap to Pay payment status, because there is no cart, retail checkout, cash drawer, or Terminal API. The REST integration now lists its actual routes and states that there is no availability endpoint and no published reference. The Bricks, Beaver Builder and Divi modules are described as shortcode adapters and noted as being present in the free plugin too, not Pro-only.
* Expanded the External Services disclosure into a per-service list giving the hostname contacted, what is sent, when it is sent, and both the privacy policy and terms for each provider - including the OpenAI, Anthropic, Apple, Cloudflare Turnstile and Zoom endpoints that were previously not listed at all.
* Fixed the booking form jumping up and down when moving from services or options to the next step by coalescing competing scroll targets into one stable position.
* Fixed every button colour, font and radius set under Button Labels, Fonts & Colours being ignored on the booking page. The template skins (.yatoon-template-beauty/clean/luxury, and the default is beauty) style the same buttons with !important at a higher specificity, so a bare class override lost the cascade no matter which stylesheet loaded last - a merchant could set the ADD colour, see it in the admin live preview, and still get the template's pink gradient live. Affected ADD, Continue, Confirm and Add Guest; hover states and the leftover coloured glow now follow the chosen colour too.
* Reclaimed the large empty band above "Your appointments" at the top of the booking form. The step indicator is hidden on step 1 but was reserving its full 84px height there, so every visitor paid 84px of dead space on the screen where booking converts, to protect against a layout shift that only occurs when a saved session resumes past step 1. The reserve is now a 10px spacer (8px under 640px).
* Fixed the Free-plan staff limit so up to two staff members can be created and enforced that limit on the server.
* Localized booking prices and dates, improved phone-error accessibility, and prevented iOS form zoom.
* Hardened recurring manage-link expiry, large-option autoloading, release asset validation, and card-on-file authorization checks.
* Added and hardened import/migration support for moving from Fresha, Booksy, Vagaro, Square, or generic CSV exports.
* Pro: keep a card on file after explicit cancellation-policy consent and charge missed appointments or late cancellations when enabled.

= 4.6.1 =
* Fixed the booking form jumping up and down when moving from services or options to the next step by coalescing competing scroll targets into one stable position.
* Localized booking prices and dates, improved phone-error accessibility, removed remote font loading, and prevented iOS form zoom.
* Hardened recurring manage-link expiry, card-on-file authorization, large-option autoloading, and release asset validation.
* Extended one-time AI consent, sensitive-data screening, and the site-wide provider budget to the customer-portal reschedule/cancel assistant; completed a systematic gettext pass across settings, portals, operational tools, provider errors, and notification defaults.
* Hardened client-IP rate limits with an opt-in trusted-proxy allowlist; forwarded headers remain ignored by default.
* Added an explicit uninstall data policy: appointments, customers, services, staff, settings, and integration data are preserved unless permanent deletion was deliberately enabled.
* Fixed network activation on WordPress Multisite so every existing site receives the complete Yatoon schema before migrations run.
* Added explicit customer consent and sensitive-data screening before frontend AI requests can reach a configured third-party provider.
* Added idempotent booking contact indexes and reduced the durable job queue's fallback poll from every minute to every five minutes while retaining prompt single-run jobs.
* Hashed OTP codes, limited failed attempts, stripped uploaded-image metadata by re-encoding, and translated direct JSON/error responses.
* New: client Look History. The client profile now has a place to log what color, style, or product a visit used, with an optional photo, tied to that client and (when logged from a booking) that appointment automatically.
* New: keep a card on file. Customers can save a card when they book, after agreeing to your cancellation policy — the exact wording they agreed to is stored with the card, with the date. Cards are held by Stripe; nothing in your database can be used to reconstruct a card number.
* New: charge for missed appointments and late cancellations, as a fixed amount or a percentage of the booking. Manual by default, with an option to charge automatically.
* New: move in from Fresha, Booksy, Vagaro or any system that exports a CSV. Customers, appointment history, remaining package visits and gift card balances all come across, with a preview before anything is written and every import reversible.
* Staff Portal sign-in — PIN, Google, and email/text-message codes — is now set up directly from the employee editor instead of a separate Identity screen, and setting a PIN no longer reloads the page.
* Fixed a site activated through WP-CLI or another headless/staging tool never getting past the licensing library's one-time connect-or-skip prompt: 10 admin pages returned a bare "Sorry, you are not allowed to access this page" until that prompt was seen in a browser.
* Fixed the Settings page itself being able to disappear from the admin menu on some installs, from the plugin registering its other pages before its own Settings page instead of first.
* Fixed a JavaScript error on every Settings tab except General, and on five locked feature-preview pages, from a script reading a Deposit/Prepay control that only exists on the General tab.
* Fixed the setup wizard creating a duplicate "My Appointments" customer page and silently switching every customer-facing link to it, instead of reusing the page the plugin already creates automatically on activation.
* Fixed the Clients screen showing "No clients yet" directly under a heading that said how many customers you have — three of the five sort columns used SQL the database rejects.
* Fixed the month view of the booking date picker, which threw a JavaScript error and never rendered.
* Fixed five Settings sub-pages (SMS, Google Calendar, Deposit & Prepay, No-show Tracking, Waitlist) rendering their controls without the script driving them.
* Fixed a fatal error on every fresh install from the salon-operations dashboard loading on a profile switch it did not belong to.
* Fixed double-booking on customer self-service: rescheduling and changing services now take the same per-day lock new bookings already used.
* Added rate limiting to the booking endpoint, per visitor and per contact detail.
* Fixed appointment times shown in Zoom invitations, confirmation emails, admin notifications and waitlist notices, which were shifted by the site's UTC offset.
* API credentials are no longer silently stored in plain text when a server cannot encrypt; saving now fails with a clear notice instead.
* Reference-photo uploads now verify the chosen service actually accepts them, instead of only checking the site-wide switch.
* Push notifications no longer send customer names, services or appointment times to an external relay.
* Escaped staff names in the booking form, added accessible names to form controls, translated 60+ booking-flow strings, raised touch targets to 44x44, and fixed a text colour below the accessibility contrast floor.
* Availability lookups now cache within a request: a multi-location, multi-service search dropped from hundreds of database queries to a handful.
* Free and Pro no longer drift on cancelled-appointment workload counting, webhook health checks, or the Reviews builder widget.

= 4.6.0 =
* Added a polished local discovery storefront, favorites sync, quick rebooking, verified review trust signals, privacy-safe booking-funnel analytics, timed waitlist claim links, and an installable customer PWA.
* Balanced the mobile whitespace above the Your appointments card and shortened guest sign-in guidance across the booking flow.
* Added a fast, free-tier-friendly frontend AI mode with conditional availability checks, shorter prompts, bounded retries, provider-aware failover, answer caching, and clickable local-menu fallback instead of a dead-end busy message.
* Added configurable frontend AI performance and cache controls plus a clearer progress state for slower provider responses.
* Fixed multi-service owner and customer emails so every selected variation and add-on is listed with its segment duration.
* Added salon address, phone, website, manage/reschedule/cancel, and calendar links to customer confirmations, including sites with older saved email templates.
* Clarified optional guest checkout and removed repeated sign-in prompts from intermediate booking steps.
* Corrected email and SMS duration for combined services and add-ons.
* Fixed multi-service Square time checks so selected add-ons and total duration match final confirmation.
* Added better Step 5 spacing and sticky-header-safe mobile progress scrolling.
* Restored desktop hover opening for the booking sign-in menu and stopped failed AI provider calls from consuming the customer's longer usage allowance.
* Added automatic model/provider failover for temporary AI overloads and rate limits, without exposing raw technical provider errors to customers.
* Replaced the browser-native booking sign-in control with a stable button menu, removing the duplicate triangle and unreliable open/close behavior seen in Chrome.
* Restored the booking sign-in menu as a tidy desktop overlay that no longer expands the whole appointment banner.
* Styled Google, Facebook, and email as consistent full-width boxed sign-in actions.
* Keeps current Gemini, OpenAI, and Claude choices while restoring the complete original working model set, compatibility-first defaults, and provider-agnostic runtime fallback.
* Increased wide-screen booking typography so the expanded layout remains readable and visually balanced.
* Added a wider, balanced booking layout for large desktop screens while preserving responsive laptop and mobile behavior.
* Removed the booking page's wide-then-shrink first-paint jump and fixed delayed AI Feature Switch checkmarks.
* Made hidden optional modules searchable with direct enable-feature guidance.
* Added secure booking-homepage customer sign-out, responsive Growth Modules forms, and clearer AI settings discovery.
* Refined the customer sign-in banner with a branded Google button, clear appointment-management copy, and a login-aware My Appointments action.
* Fixed Rank Math breadcrumb JSON-LD items that omitted the Google-required name field.
* Added Google, email-code, and SMS-code customer sign-in with verified Square Customer ID linking for phone-only profiles.
* Added customer self-service service changes with fresh staff/time availability checks for eligible unpaid single-service appointments.
* Hardened Square appointment ownership checks and local reschedule availability across breaks, resources, time off, and external calendars.
* Added native Brizy elements for booking, customer and staff portals, service menus, catalogs, galleries, reviews, and booking management.
* Fixed the enabled Already booked banner being suppressed by legacy option types or temporarily unavailable destination URLs.
* Prevented partial General settings actions from silently clearing unrelated checkboxes.
* Fixed delayed checkbox checkmarks across all Settings controls in Chromium and Edge.
* Fixed false no-availability results when a primary Square variation was also submitted as an add-on after staff selection.
* Added Google sign-in and My Appointments to the optional booking-form portal banner, automatic customer-portal page setup, and clearer OAuth readiness guidance.
* Replaced misleading empty availability for local-only staff in Square mode with an actionable sync/platform message.
* Added shared Google OpenID Connect identity for customers and explicitly authorized employees.
* Added customer Google sign-in and verified profile prefill in both Local and Square booking modes.
* Added employee Google, email-code, SMS-code, and six-digit PIN sign-in with one hardened session model.
* Added persistent identity links, one-time OAuth handoffs, collision-safe customer matching, and Square Customer resolution.
* Added an Identity & Sign-in admin screen with per-employee authorization controls and audit-ready bindings.
* Simplified the booking-page sign-in dropdown wording ("Continue with email" / "Continue with text message") and made both labels editable under Settings.
* Fixed the "Already booked with us?" banner heading not upgrading to the shorter default when the saved text used different capitalization.
* Moved the direct-access guard in class-yatoon-core.php to the top of the file (it previously sat after an unguarded top-level function).
* Added revenue trend, revenue-by-service, and revenue-by-staff charts to the Reports page.
* Added an AI reschedule assistant: customers can describe a new time in their own words in "My Appointments"; AI only reads real open slots and never invents availability, and the customer still confirms before anything changes.
* Gave WhatsApp reminders and the Bookly/Amelia/LatePoint migration center their own readme callouts instead of leaving them buried in a shared bullet point.
* Rebuilt the Reports page charts on a locally-vendored Chart.js (no CDN): a combined revenue/bookings trend chart plus real bar charts for revenue by service and by staff, replacing the earlier plain CSS bars.
* Broadened the AI assistant in "My Appointments" beyond reschedule-only: it now also recognizes cancellation requests ("please cancel it") from the same chat box, still only proposing an action after checking real data, and still requiring the customer to confirm before anything changes.
* Removed non-interactive heading focus outlines that appeared as pink frames during keyboard and assistive step navigation, and added breathing room below the professional heading before staff cards.

= 4.5.6 =
* Closed a concurrent Square webhook duplicate-processing window with atomic event claims and safe retry release.
* Stopped the booking service worker from persisting HTML, API responses, WordPress nonces, or personalized pages.
* Added post-migration table verification so failed optional-module migrations retry instead of being marked complete.
* Added direct-access guards to remaining core integration classes and expanded executable release contracts.

Older release notes are preserved in the project release archive; the plugin package intentionally carries only recent upgrade-relevant history.
