diff --git a/README.md b/README.md
index 860cfae..2f0d40c 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,10 @@ Building and integrating DHTMLX React Gantt (`@dhtmlx/trial-react-gantt` and `@d
Building and integrating DHTMLX Angular Gantt (`@dhtmlx/trial-angular-gantt` and `@dhx/angular-gantt`) - wrapper-specific setup, data ownership and persistence patterns (`data.save` / `data.batchSave`), and theming approach, with known failure modes and concrete fixes.
+### `dhtmlx-js-scheduler`
+
+Building and integrating the core DHTMLX JavaScript Scheduler in JavaScript and TypeScript applications. Recognises all delivery channels (`dhtmlx-scheduler` Standard/GPL, `@dhx/trial-scheduler`, `@dhx/scheduler`, `
+
+
+```
+
+Globals exposed in this mode:
+- `window.scheduler` — the singleton, present in every edition.
+- `window.Scheduler` — the factory class, present only in PRO editions that support multiple instances. When `window.Scheduler` is `undefined`, the page is running Standard or a single-instance PRO build and `Scheduler.getSchedulerInstance()` is not available.
+
+The same singleton-vs-factory rules apply: do not call `scheduler.destructor()` on the global singleton in Standard/single-instance builds unless the page will be reloaded (see Cleanup), and use `Scheduler.getSchedulerInstance()` only when the global `Scheduler` is present and the edition supports it.
+
+See [editions.md](editions.md) for how to detect the edition when there is no `package.json` to inspect.
+
+## Vite
+
+Include the installed Scheduler package in `optimizeDeps` when Vite has trouble pre-bundling or the project already follows this pattern. Use the package name that matches the installed edition:
+
+```ts
+// vite.config.ts
+export default {
+ optimizeDeps: {
+ include: ["dhtmlx-scheduler"], // Standard
+ // include: ["@dhx/trial-scheduler"], // Trial
+ // include: ["@dhx/scheduler"], // Commercial
+ },
+};
+```
+## Height Rule
+
+The Scheduler container must have a defined height:
+
+```html
+
+```
+
+If using `height: 100%`, all parent elements must also have a defined height. Otherwise, the container will collapse.
+
+## Initialization
+
+Initialize Scheduler after the container exists:
+
+```ts
+scheduler.init("scheduler_here", new Date(), "week");
+```
+
+or:
+
+```ts
+scheduler.init(container, new Date(), "week");
+```
+
+Load client-side data with:
+
+```ts
+scheduler.parse(events);
+```
+
+Keep all Scheduler-related logic (initialization, configuration, data loading, events, DataProcessor, cleanup) in a single module. Avoid scattering direct Scheduler calls across the app.
+
+## Plugins
+
+Enable plugins before calling APIs that depend on them:
+
+```ts
+scheduler.plugins({
+ recurring: true,
+ tooltip: true,
+ readonly: true,
+});
+```
+
+In v6.0+, extensions are bundled in `dhtmlxscheduler.js` and activated through `scheduler.plugins({...})`; do not import old `ext/dhtmlxscheduler_*.js` files unless the project is on an older version.
+
+## Markup vs Header Config
+
+You can initialize with Scheduler markup:
+
+```html
+
+```
+
+For app layouts, prefer `scheduler.config.header` plus an empty container because it is easier to make responsive:
+
+```ts
+scheduler.config.header = ["day", "week", "month", "date", "prev", "today", "next"];
+```
+
+## Cleanup
+
+Cleanup depends on whether the instance was created via the singleton or the factory. The two paths are not interchangeable.
+
+**Factory instance (`Scheduler.getSchedulerInstance()`):** call `destructor()` when the container is removed. This clears data, removes event handlers, detaches the instance from the DOM, and disposes the attached DataProcessor. Safe because the factory created a dedicated instance.
+
+```ts
+const schedulerA = Scheduler.getSchedulerInstance();
+// ...
+schedulerA.destructor();
+```
+
+**Singleton (`import { scheduler }`):** **do not** call `scheduler.destructor()` for cleanup-and-reuse. The singleton is the only Scheduler instance available to the page, and destroying it leaves the module in a non-functional state until a full page reload. For reuse, clear data and detach the handlers that the init code attached:
+
+```ts
+// during init — capture handler ids
+const handlerIds = [
+ scheduler.attachEvent("onEventChanged", onEventChanged),
+ scheduler.attachEvent("onEventDeleted", onEventDeleted),
+];
+
+// on cleanup
+scheduler.clearAll();
+for (const id of handlerIds) scheduler.detachEvent(id);
+```
+
+The DataProcessor attached to the singleton, however, is safe to destroy and recreate. Keep a reference to the DataProcessor returned by `scheduler.createDataProcessor(...)` and call `dataProcessor.destructor()` on cleanup; create a fresh DataProcessor when Scheduler is activated again:
+
+```ts
+// during init
+const dataProcessor = scheduler.createDataProcessor(routerFn);
+
+// on cleanup
+dataProcessor.destructor();
+
+// on reactivation
+const dataProcessor = scheduler.createDataProcessor(routerFn);
+```
+
+Clearing `container.innerHTML` afterwards is rarely needed and only useful when the host element survives across re-mounts.
+
+## Config And Templates
+
+Common configuration areas:
+
+- `scheduler.config.header` — navigation controls and visible views
+- `scheduler.config.date_format` — event date parsing format
+- `scheduler.config.first_hour`, `last_hour`, `time_step` — time scale and time resolution
+- `scheduler.config.readonly`, `readonly_form` — interaction settings
+- `scheduler.config.lightbox.sections` — event editing UI
+- `scheduler.config.show_loading` — loading indicator behavior
+- `scheduler.xy.*` — sizing values
+- view-specific configuration for Timeline, Units, Grid, Agenda, Year, and other Scheduler views
+
+Templates:
+
+- `scheduler.templates.*` — formatting of event text, CSS classes, scale labels, tooltips, month cells, Timeline cells, Timeline rows, Units output, and view-specific rendering
+
+Example:
+
+```ts
+// Event text
+scheduler.templates.event_text = (start, end, event) => {
+ return event.text;
+};
+
+// Event CSS class
+scheduler.templates.event_class = (start, end, event) => {
+ return event.status ? `status-${event.status}` : "";
+};
+
+// Tooltip text
+scheduler.templates.tooltip_text = (start, end, event) => {
+ return event.text;
+};
+
+// Highlight month cells, e.g. weekends
+scheduler.templates.month_date_class = (date) => {
+ const day = date.getDay();
+ return day === 0 || day === 6 ? "weekend" : "";
+};
+```
+
+Do not guess template signatures. Verify unfamiliar templates with MCP.
+
+**Security — templates return raw HTML.** Whatever a template returns is inserted into the DOM as HTML, not as text. Any user-supplied field (`event.text`, descriptions, resource names, notes, free-form custom fields) that reaches a template unsanitized is an XSS vector — e.g. an event named `
` will execute on render.
+
+Mitigate at both ends:
+
+- Sanitize / escape user-supplied text on save in the backend (defense in depth).
+- Escape — or sanitize via a vetted library like DOMPurify — before the data reaches Scheduler (`parse`, `addEvent`, `updateEvent`, `remoteUpdates`, DataProcessor responses), or escape inside the template before returning:
+
+```ts
+const escapeHtml = (value) => String(value ?? "").replace(/[&<>"']/g, (character) => ({
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ "\"": """,
+ "'": "'",
+})[character]);
+
+scheduler.templates.event_text = (_start, _end, event) => escapeHtml(event.text);
+scheduler.templates.tooltip_text = (_start, _end, event) => `${escapeHtml(event.text)}`;
+```
+
+If the template intentionally returns markup, escape only the user-supplied substrings, not the static markup.
+
+`scheduler.templates.parse_date` and `scheduler.templates.format_date` can be overridden to accept or emit non-default date formats (useful when the backend returns timestamps or compact strings):
+
+```ts
+scheduler.config.date_format = "%Y-%m-%d %H:%i";
+
+const parseDate = scheduler.date.str_to_date(scheduler.config.date_format);
+const formatDate = scheduler.date.date_to_str(scheduler.config.date_format);
+
+scheduler.templates.parse_date = (value) => parseDate(value);
+scheduler.templates.format_date = (date) => formatDate(date);
+```
+
+## Events
+
+Wire app logic through documented events rather than direct mutation. Attach with `scheduler.attachEvent` and detach (or destroy via `scheduler.destructor`) on unmount:
+
+```ts
+const handlerId = scheduler.attachEvent("onEventChanged", (id, event) => {
+ // app-side reactions, persistence triggers, store updates
+});
+
+// later
+scheduler.detachEvent(handlerId);
+```
+
+For one-shot subscriptions (e.g. running first-init startup code through `onSchedulerReady`), pass `{ once: true }` so Scheduler auto-detaches the handler after the first invocation:
+
+```ts
+scheduler.attachEvent("onSchedulerReady", () => {
+ // runs once, even if scheduler.init is called again later
+}, { once: true });
+```
+
+Event names and argument lists are stable but numerous. Verify unfamiliar events with MCP before wiring them.
+
+## Localization
+
+Switch the active locale at runtime with `scheduler.i18n.setLocale("xx")`. Per-label overrides go through `scheduler.locale.labels.*` or a partial locale object passed to `scheduler.i18n.setLocale(...)`:
+
+```ts
+scheduler.i18n.setLocale("ru");
+scheduler.locale.labels.day_tab = "Day";
+scheduler.locale.labels.week_tab = "Week";
+scheduler.locale.labels.section_description = "Description";
+```
+
+Or:
+
+```ts
+scheduler.i18n.setLocale({
+ labels: {
+ day_tab: "Day",
+ week_tab: "Week",
+ section_description: "Description",
+ },
+});
+```
+
+Apply locale changes before `scheduler.init` when possible. If changed after init, call `scheduler.render()`.
+
+## Read-Only Mode
+
+To make the Scheduler non-editable:
+
+```ts
+scheduler.config.readonly = true;
+```
+
+This makes the Scheduler non-editable and prevents users from opening the lightbox.
+
+To allow opening the lightbox while preventing edits inside it:
+
+```ts
+scheduler.config.readonly_form = true;
+```
+
+This requires the `readonly` extension.
+
+Read-only behavior can also be applied to individual events:
+
+```ts
+const event = scheduler.getEvent(id);
+event.readonly = true;
+```
+
+Note that read-only mode is a UI restriction, not a security boundary. Also remove or hide app-level controls that mutate data (e.g. add buttons, undo/redo) and enforce permissions in DataProcessor routes and on the backend.
diff --git a/dhtmlx-js-scheduler/references/styling-and-theming.md b/dhtmlx-js-scheduler/references/styling-and-theming.md
new file mode 100644
index 0000000..c67afd1
--- /dev/null
+++ b/dhtmlx-js-scheduler/references/styling-and-theming.md
@@ -0,0 +1,223 @@
+# Styling And Theming
+
+Use this file when theming Scheduler, matching an app design system, or styling events, scales, lightboxes, blocked time, and advanced views.
+
+## Contents
+
+- Styling Priority
+- Skins
+- Theme Variables First
+- Use Config For Size And Geometry
+- Templates
+- Data-Driven Styling
+- Common Selectors And Escape Hatches
+- Practical Guardrails
+
+## Styling Priority
+
+Use this order by default:
+1. built-in skins via `scheduler.skin` or `scheduler.setSkin`
+2. CSS variables for global theme alignment
+3. config for size and geometry
+4. templates for semantic or data-driven styling
+5. direct CSS selectors only for structural exceptions
+
+## Skins
+
+Built-in skins:
+- `"terrace"` (default)
+- `"dark"`
+- `"material"`
+- `"flat"`
+- `"contrast-black"`
+- `"contrast-white"`
+
+Starting from Scheduler v7.0, all skins are bundled in `dhtmlxscheduler.css`.
+
+Set the skin before calling `scheduler.init()`:
+
+```ts
+scheduler.skin = appTheme === "dark" ? "dark" : "terrace";
+
+scheduler.init("scheduler_here", new Date(), "week");
+```
+
+Or switch the skin at runtime:
+
+```ts
+scheduler.setSkin("dark");
+```
+
+Use the application theme as the single source of truth. Avoid introducing a Scheduler-specific theme switch when a global theme already exists.
+
+## Theme Variables First
+
+CSS variables are the preferred customization path.
+
+Define shared variables at `:root` so inheritance works correctly across the whole component:
+
+```css
+:root {
+ --dhx-scheduler-base-colors-primary: #2563eb;
+ --dhx-scheduler-container-background: #ffffff;
+ --dhx-scheduler-container-color: #0f172a;
+ --dhx-scheduler-event-background: #2563eb;
+ --dhx-scheduler-event-color: #ffffff;
+}
+```
+
+### High-Impact Variables
+
+Typography and surfaces:
+- `--dhx-scheduler-font-family`
+- `--dhx-scheduler-font-size`
+- `--dhx-scheduler-container-background`
+- `--dhx-scheduler-container-color`
+- `--dhx-scheduler-popup-background`
+- `--dhx-scheduler-popup-color`
+
+Primary and semantic colors:
+- `--dhx-scheduler-base-colors-primary`
+- `--dhx-scheduler-base-colors-background`
+- `--dhx-scheduler-base-colors-text-base`
+- `--dhx-scheduler-base-colors-border`
+
+Events:
+- `--dhx-scheduler-event-background`
+- `--dhx-scheduler-event-color`
+- `--dhx-scheduler-event-border`
+
+Use CSS variables for application-wide theming and design system alignment.
+
+Per-event `color` and `textColor` override event CSS variables through inline CSS variables. Use them only when colors are true event data; use classes and templates for semantic styling.
+
+## Templates
+
+Templates should be the primary customization mechanism for data-driven content.
+
+```ts
+scheduler.templates.event_text = (start, end, event) => {
+ return escapeHtml(event.text);
+};
+```
+
+Common template areas:
+- event text and content
+- event CSS classes
+- hour scale labels
+- quick info and tooltip content
+- agenda view rendering
+- units view rendering
+- year view rendering
+
+## Use Config For Size And Geometry
+
+Some visible styling is controlled by Scheduler configuration, not CSS:
+
+```ts
+scheduler.xy.scale_width = 60;
+scheduler.xy.scale_height = 25;
+scheduler.xy.bar_height = 24;
+scheduler.xy.scroll_width = 18;
+
+scheduler.config.hour_size_px = 90;
+```
+
+Common geometry settings:
+- `scheduler.xy.scale_width`
+- `scheduler.xy.scale_height`
+- `scheduler.xy.bar_height`
+- `scheduler.xy.scroll_width`
+- `scheduler.xy.month_scale_height`
+- `scheduler.xy.min_event_height`
+- `scheduler.config.hour_size_px`
+
+Apply geometry-related settings before calling `scheduler.init()`.
+
+## Data-Driven Styling
+
+When styling depends on event data or time cell data, return CSS classes from templates and style those classes with CSS variables.
+
+```ts
+scheduler.templates.event_class = (_start, _end, event) => {
+ return event.priority === "high" ? "event-priority-high" : "";
+};
+```
+
+```css
+.event-priority-high {
+ --dhx-scheduler-event-background: #dc2626;
+ --dhx-scheduler-event-color: #fff;
+}
+```
+
+For background time cells in Day and Week views, use documented templates such as `scheduler.templates.time_slot_class` rather than broad selectors.
+
+### Events
+
+Prefer `event_class` to style groups of events by priority, status, owner, or any other semantic field:
+
+```js
+scheduler.templates.event_class = (_start, _end, event) => {
+ return event.priority ? `priority_${event.priority}` : "";
+};
+```
+
+```css
+.priority_high {
+ --dhx-scheduler-event-background: #dc2626;
+ --dhx-scheduler-event-color: #ffffff;
+}
+```
+
+Supported event color shortcut fields:
+- `color`
+- `textColor`
+
+Important caveat:
+- these fields are applied by Scheduler directly to the event container and text
+- they can override class-based event styling depending on CSS precedence
+
+Use shortcut color fields only when the app truly stores per-event visual values as data. For reusable semantic styling, `event_class` is usually safer.
+
+Advanced pattern:
+- if colors come from backend-driven entities such as owners, calendars, or stages, generate CSS classes from the loaded dataset and return those classes from `event_class`
+
+## Common Selectors And Escape Hatches
+
+Use these when skins, variables, and templates are not enough.
+
+Scheduler structure:
+- `.dhx_cal_container`
+- `.dhx_cal_navline`
+- `.dhx_cal_header`
+- `.dhx_cal_data`
+- `.dhx_cal_tab`
+
+Events:
+- `.dhx_cal_event`
+- `.dhx_cal_event_line`
+- `.dhx_cal_event_clear`
+
+Mini calendar:
+- `.dhx_month_head`
+- `.dhx_calendar_click`
+- `.dhx_month_head.dhx_year_event`
+- `.dhx_now`
+
+Lightbox:
+- `.dhx_cal_light`
+
+Prefer CSS variables and templates over direct selectors whenever possible.
+
+Scope overrides to a wrapper class when multiple Scheduler instances or other DHTMLX widgets exist on the page.
+
+## Practical Guardrails
+
+- Prefer Scheduler CSS variables for theme-wide restyling before touching selectors.
+- Prefer templates when styling depends on event or time cell data.
+- Prefer scoped selectors over global overrides when changing only one Scheduler area.
+- Apply geometry changes through documented `scheduler.xy` and `scheduler.config` settings instead of CSS.
+- Keep skin changes wired to the application theme.
+- Remember that the Material skin requires Roboto to be imported manually.
+- Avoid selector-heavy overrides that depend on internal DOM structure.