/**
 * DOCX Editor Styles — SINGLE SOURCE OF TRUTH.
 *
 * This file is the one canonical chrome stylesheet for the editor UI. Both the
 * React and Vue adapters `@import` it from their own src/styles/editor.css, so
 * the color-token palette and all UI styling can never drift between the two.
 * Both adapter editor.css files are import-only (enforced by
 * scripts/check-adapter-css-thin.mjs) — do NOT fork UI styling into an adapter,
 * add it here.
 *
 * Contains:
 * - CSS custom properties / color tokens (shadcn-compatible + --doc-* chrome
 *   palette) and the .ep-root.dark scaffold
 * - Cursor/caret, selection, content-control, popup/menu chrome, etc.
 *
 * NOTE: `@tailwind utilities` lives here so the directive is shared; each
 * adapter's own Tailwind build (React via the CLI, Vue via vite PostCSS)
 * expands it against that adapter's component sources. We intentionally do NOT
 * include @tailwind base (preflight) to avoid resetting the host application.
 */

@tailwind utilities;

/* ============================================================================
  * CSS CUSTOM PROPERTIES (shadcn theme)
  * ============================================================================ */

/* Scoped to .ep-root to avoid clashing with host application CSS variables */
.ep-root {
  /* ----------------------------------------------------------------------
    * shadcn / Tailwind tokens (HSL triples). These back the Tailwind utility
    * classes (bg-primary, text-foreground, bg-muted, ...). These are the
    * canonical React values (the slate-tinted shadcn palette) — DO NOT change
    * them; both adapters share them so Vue matches React exactly. The `/
    * <alpha-value>` form in the Tailwind preset lets opacity modifiers work.
    * -------------------------------------------------------------------- */
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --card: 0 0% 100%;
  --card-foreground: 222.2 84% 4.9%;
  --popover: 0 0% 100%;
  --popover-foreground: 222.2 84% 4.9%;
  --primary: 221.2 83.2% 53.3%;
  --primary-foreground: 210 40% 98%;
  --secondary: 210 40% 96.1%;
  --secondary-foreground: 222.2 47.4% 11.2%;
  --muted: 210 40% 96.1%;
  --muted-foreground: 215.4 16.3% 46.9%;
  --accent: 210 40% 96.1%;
  --accent-foreground: 222.2 47.4% 11.2%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 210 40% 98%;
  --border: 214.3 31.8% 91.4%;
  --input: 214.3 31.8% 91.4%;
  --ring: 221.2 83.2% 53.3%;
  --radius: 0.5rem;

  /* ======================================================================
    * Document-editor chrome palette — the single source of truth for UI
    * colors. Components reference these via var(--doc-*); component styles
    * carry no raw hex/rgba. Override the whole set under .ep-root.dark to
    * theme the UI. The document canvas is painted from the .docx and is
    * intentionally NOT themed here (it stays Word-faithful, like a page in
    * Word/Google Docs that stays white regardless of app chrome).
    * ==================================================================== */

  /* Surfaces */
  --doc-surface: #ffffff; /* panels, menus, dropdowns, cards */
  --doc-card: #f8fbff; /* collapsed comment / suggestion cards (near-white) */
  --doc-bg: #f8f9fa; /* app background behind the page */
  --doc-bg-subtle: #f5f5f5; /* subtle section backgrounds */
  --doc-bg-hover: #f1f3f4; /* hover states */
  --doc-bg-input: #f8f9fa; /* input backgrounds */

  /* Primary action color (Google blue) */
  --doc-primary: #1a73e8;
  --doc-primary-hover: #1557b0;
  --doc-primary-light: #e8f0fe; /* selected/active backgrounds */

  /* Accent (indigo — agent / assistant UI) */
  --doc-accent: #6366f1;
  --doc-accent-bg: #eef2ff;

  /* Foreground for text/icons sitting on a colored fill (primary/accent/
    * dark buttons, badges, tooltips). Inverts in dark mode so contrast holds. */
  --doc-on-primary: #ffffff;

  /* Active toolbar toggle (bold/italic/comments/...): dark slab in light mode,
    * Word-accent tint in dark mode (where a dark slab would flip light). */
  --doc-toggle-active-bg: hsl(var(--foreground));
  --doc-toggle-active-fg: #ffffff;

  /* Inline comment/annotation marks. Resting highlights stay quiet on the
    * document canvas; focused sidebar items get the stronger active treatment. */
  --doc-comment-bg: rgba(255, 212, 0, 0.12);
  --doc-comment-border: rgba(245, 174, 0, 0.45);
  --doc-comment-active-bg: rgba(255, 212, 0, 0.35);
  --doc-comment-active-border: rgba(245, 174, 0, 0.9);

  /* Text */
  --doc-text: #202124; /* primary text */
  --doc-text-muted: #5f6368; /* secondary text */
  --doc-text-subtle: #9aa0a6; /* tertiary/disabled text */
  --doc-text-placeholder: #999; /* placeholder text */

  /* Borders */
  --doc-border: #e0e0e0; /* standard borders */
  --doc-border-light: #dadce0; /* lighter borders */
  --doc-border-dark: #d0d0d0; /* darker borders (tables) */
  --doc-border-input: #ccc; /* input borders */

  /* Status */
  --doc-error: #c5221f; /* error states */
  --doc-error-bg: #fce8e6; /* error backgrounds */
  --doc-danger: var(--doc-error); /* invalid and refused controls */
  --doc-destructive: var(--doc-error); /* destructive menu/context rows */
  --doc-destructive-hover-bg: var(--doc-error-bg);
  --doc-success: #34a853; /* success states */
  --doc-success-bg: #e8f5e9; /* success backgrounds */
  --doc-warning: #f9a825; /* warning states (icon/accent/border) */
  --doc-warning-bg: #fff8e1; /* warning backgrounds */
  --doc-warning-text: #856404; /* readable warning text on warning-bg */

  /* Link */
  --doc-link: #0563c1; /* hyperlinks */

  /* Revision indicators */
  --doc-revision-insertion: #2e7d32;
  --doc-revision-deletion: #c62828;
  --doc-revision-insertion-tint: rgba(46, 125, 50, 0.09);
  --doc-revision-deletion-tint: rgba(198, 40, 40, 0.09);
  /* The wash a PENDING change wears. The painter puts this on the run itself, so it covers
     tracked text anywhere in the document rather than only where the band layer reaches; the
     band adds the full tint on top for the one the caret is in, and the two multiply into a
     clearly deeper colour. Keep the two pairs in step — this is the faint end of that ramp. */
  --doc-revision-insertion-wash: rgba(46, 125, 50, 0.05);
  --doc-revision-deletion-wash: rgba(198, 40, 40, 0.05);
  /* A tracked FORMAT change: the words are unchanged, so it takes neither the insertion nor
     the deletion colour — grey says "the appearance is the decision". The wash plus a faint
     dotted rule make the range findable (it is the hover balloon's target); both are quiet
     enough that a heavily restyled page reads as text, not as marking. */
  --doc-revision-format: #6b7f8c;
  --doc-revision-format-wash: rgba(107, 127, 140, 0.1);
  /* Word's tracked-change palette. Deletions read as removal, insertions as addition, and the
     margin rules take the same two colours so the margin says WHAT happened, not only that
     something did. */
  /* Per-AUTHOR review colours. OOXML carries no colour on a revision — Word assigns one per
     author in the application — so this ramp is presentation policy, and overriding a slot
     under `.ep-root` restyles both the painted document and the review cards. Chosen to stay
     distinguishable from each other and from the black body text. */
  --doc-review-author-0: #c0392b;
  --doc-review-author-1: #1f6fb2;
  --doc-review-author-2: #7d3c98;
  --doc-review-author-3: #117a65;
  --doc-review-author-4: #b9770e;
  --doc-review-author-5: #a93226;
  --doc-review-author-6: #2e4053;
  --doc-review-author-7: #6c3483;
  /* Retained as an override hook for a host that wants one neutral margin rule instead of the
     kind-coloured pair. Nothing reads it by default. */
  --doc-review-change-bar: #767676;

  /* Selected table cells. A native selection is a run of characters and cannot
    * express a rectangle of cells, so that one highlight is drawn rather than
    * left to the browser. Kept close to the browser's own selection tint so the
    * two read as the same gesture. */
  --doc-cell-selection: rgba(26, 115, 232, 0.22);

  /* Shadows & overlays */
  --doc-shadow: rgba(0, 0, 0, 0.15);
  --doc-shadow-strong: rgba(0, 0, 0, 0.3);
  --doc-shadow-subtle: rgba(0, 0, 0, 0.06);
  --doc-overlay: rgba(0, 0, 0, 0.5); /* modal backdrops */
  /* Open header/footer: body + inactive furniture opacity (screen chrome only; print resets). */
  --doc-hf-dim-opacity: 0.45;

  /* Sidebar card elevation (Google-grey, compound) — shared by React's
    * cardStyles.ts and the Vue comment/tracked-change cards so both match. */
  --doc-card-shadow: 0 1px 3px rgba(60, 64, 67, 0.2), 0 2px 6px rgba(60, 64, 67, 0.08);
  --doc-card-shadow-strong: 0 1px 3px rgba(60, 64, 67, 0.3), 0 4px 8px 3px rgba(60, 64, 67, 0.15);
  /* Elevated dropdown/popover (Tailwind shadow-lg) — mirrors React's Radix
    * Select content so the Vue toolbar dropdowns match. */
  --doc-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);

  /* Focus ring & text selection (derived from primary) */
  --doc-focus-ring: rgba(26, 115, 232, 0.4);
  --doc-selection: rgba(26, 115, 232, 0.3);

  /* The page sheet itself — the paper.
   *
   * Declared here for the DEFAULT theme, which it was not: `--doc-page-bg` existed only
   * inside the dark block (and a dark print override), so
   * `.ep-one-surface__page { background: var(--doc-page-bg) }` resolved to nothing in light
   * mode and the sheet painted TRANSPARENT — a box-shadow around a see-through interior,
   * because neither the viewport nor the surface sets a background either. The same silent
   * `var()` failure as the caret, in the same file, found by the scope-aware token check
   * rather than by a report.
   *
   * A literal, not a themed token: the canvas is deliberately not themed, and dark mode
   * overrides it to the grey Word uses. */
  --doc-page-bg: #ffffff;
  /* The colour a sheet is PAINTED. In the legacy lane the page is lightness-inverted, so
     `--doc-page-bg` is a pre-filter value and this is what it lands on; the paginated lane
     inverts only the content, so it paints this directly. Declared rather than written at
     the use site, or the print override below cannot reach it. */
  --doc-page-bg-rendered: #ffffff;
  /* Declared, not just defaulted in a `var()` fallback — the third silent-var bug in this
     file was one more unnamed token. Stays #000 in both themes so the content inversion
     lands on near-white. */
  --doc-page-text: #000000;

  /* Caret on the document canvas.
   *
   * A LITERAL rather than var(--doc-text): the canvas is deliberately not themed, so the
   * caret tracks the paper it sits on, not the UI chrome. The dark-mode block overrides it
   * for the inverted canvas.
   *
   * This was missing entirely and only ever declared in the dark block, so
   * `.ep-one-surface__caret { background: var(--doc-caret) }` resolved to nothing in the
   * default theme and painted a 1px transparent div — the caret was correctly positioned,
   * visible and non-blinking-off, and simply had no colour. */
  --doc-caret: #202124;

  /* Document scroll container scrollbar */
  --doc-scrollbar-size: 14px;
  --doc-scrollbar-thumb: color-mix(in srgb, var(--doc-text-muted) 45%, transparent);
  --doc-scrollbar-thumb-hover: color-mix(in srgb, var(--doc-text-muted) 65%, transparent);
  --doc-scrollbar-track: transparent;
}

/* ========================================================================
  * Dark theme. Add the `dark` class to the .ep-root element to enable it
  * (Tailwind darkMode: ['class'] is already configured). Theming is driven by
  * these token overrides — every UI token above is re-pointed here, so all
  * chrome re-themes automatically. The document canvas is left untouched on
  * purpose: it must stay Word-faithful.
  *
  * NOTE: because `important: '.ep-root'` emits `dark:` utilities as
  * `.ep-root .dark\:x:is(.dark *)`, those variants only match DESCENDANTS of a
  * `.dark` element — NOT the `.ep-root.dark` element itself. So theme the root
  * via these token overrides (as below), never via a `dark:` utility placed
  * directly on the `.ep-root` node.
  * ====================================================================== */
/* Also targets nested `.ep-root` elements (e.g. the paged-editor root, Radix
  * portals) so the base `.ep-root` light tokens don't shadow these inside a
  * dark tree. */
.ep-root.dark,
.ep-root.dark .ep-root {
  /* Palette sampled from Microsoft Word Online dark mode (chrome + canvas).
    * shadcn / Tailwind tokens (HSL triples) — mirror the --doc-* chrome values
    * below so shadcn-based components (Select, Button) re-theme in lockstep. */
  --background: 0 0% 12%; /* #1f1f1f ribbon/surface */
  --foreground: 0 0% 91%; /* #e8e8e8 */
  --card: 0 0% 18%; /* #2d2d2d */
  --card-foreground: 0 0% 91%;
  --popover: 0 0% 18%; /* #2d2d2d */
  --popover-foreground: 0 0% 91%;
  --primary: 212 100% 65%; /* #4e9dff Word accent */
  --primary-foreground: 0 0% 12%;
  --secondary: 0 0% 20%; /* #333333 */
  --secondary-foreground: 0 0% 91%;
  --muted: 0 0% 20%; /* #333333 */
  --muted-foreground: 0 0% 63%; /* #a0a0a0 */
  --accent: 0 0% 23%; /* #3a3a3a */
  --accent-foreground: 212 100% 65%;
  --destructive: 0 72% 60%; /* #e05656 */
  --destructive-foreground: 0 0% 98%;
  --border: 0 0% 24%; /* #3c3c3c */
  --input: 0 0% 24%;
  --ring: 212 100% 60%;

  /* chrome palette (Word Online dark) */
  --doc-surface: #1f1f1f; /* ribbon / toolbar / title bar */
  --doc-card: #2d2d2d; /* collapsed comment / suggestion cards */
  --doc-bg: #262626; /* workspace behind the page */
  --doc-bg-subtle: #2d2d2d; /* dropdowns, dialogs, panels */
  --doc-bg-hover: #3a3a3a; /* hover states */
  --doc-bg-input: #333333; /* input fields */
  --doc-primary: #4e9dff; /* Word accent blue (Home-tab underline) */
  --doc-primary-hover: #6cb0ff;
  --doc-primary-light: rgba(78, 157, 255, 0.18); /* selected/active bg */
  --doc-accent: #4e9dff;
  --doc-accent-bg: #1f3047;
  --doc-on-primary: #1f1f1f; /* text/icon on a filled primary surface */
  --doc-toggle-active-bg: var(--doc-primary-light);
  --doc-toggle-active-fg: var(--doc-primary);
  --doc-comment-bg: rgba(253, 214, 99, 0.16);
  --doc-comment-border: rgba(253, 214, 99, 0.5);
  --doc-comment-active-bg: rgba(253, 214, 99, 0.32);
  --doc-comment-active-border: rgba(253, 214, 99, 0.95);
  /* Dark mode: the same ramp, lifted so it reads on a dark page. */
  --doc-review-author-0: #ff8a80;
  --doc-review-author-1: #82b1ff;
  --doc-review-author-2: #d7a3ff;
  --doc-review-author-3: #7fe3c5;
  --doc-review-author-4: #ffd180;
  --doc-review-author-5: #ff9e80;
  --doc-review-author-6: #b0bec5;
  --doc-review-author-7: #ce93d8;
  --doc-revision-format: #9fb3bf;
  --doc-review-change-bar: #9e9e9e;
  --doc-text: #e8e8e8; /* primary text */
  --doc-text-muted: #a0a0a0; /* secondary text */
  --doc-text-subtle: #6e6e6e; /* tertiary/disabled text */
  --doc-text-placeholder: #6e6e6e;
  --doc-border: #3c3c3c; /* standard borders */
  --doc-border-light: #353535; /* lighter borders */
  --doc-border-dark: #555555; /* darker borders (tables) */
  --doc-border-input: #4a4a4a; /* input borders */
  --doc-error: #f28b82;
  --doc-error-bg: #3c1f1d;
  --doc-success: #81c995;
  --doc-success-bg: #1f2e22;
  --doc-warning: #fdd663;
  --doc-warning-bg: #332a1a;
  --doc-warning-text: #fdd663;
  --doc-link: #6eb9ff;
  --doc-shadow: rgba(0, 0, 0, 0.4);
  --doc-shadow-strong: rgba(0, 0, 0, 0.6);
  --doc-shadow-subtle: rgba(0, 0, 0, 0.2);
  --doc-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(0, 0, 0, 0.2);
  --doc-card-shadow-strong: 0 1px 3px rgba(0, 0, 0, 0.5), 0 4px 8px 3px rgba(0, 0, 0, 0.3);
  --doc-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.5);
  --doc-overlay: rgba(0, 0, 0, 0.7);
  --doc-hf-dim-opacity: 0.4;
  --doc-focus-ring: rgba(78, 157, 255, 0.45);
  --doc-selection: rgba(78, 157, 255, 0.32);

  /* Document canvas in dark mode (a VIEW transform — the saved DOCX never
    * changes). Word doesn't just swap two colors; it perceptually inverts the
    * LIGHTNESS of every document color while keeping its hue, so black text →
    * white, dark-navy headings → light blue, dark-red → light red, etc. We get
    * that for free by rendering the page in normal (light) colors and applying
    * `invert(1) hue-rotate(180deg)` to the whole page below — hue-rotate undoes
    * the hue flip that invert() introduces, leaving only the lightness flip.
    *
    * So the page is painted light here: pre-filter #ccc inverts to the ~#333
    * canvas Word uses; text stays #000 (→ near-white). Images are inverted back
    * to normal by the counter-filter below. */
  --doc-page-bg: #cccccc;
  --doc-page-bg-rendered: #333333;
  /* --doc-page-text stays #000000 (light fallback) so it inverts to white. */

  /* Caret on the dark canvas. The selection overlay sits OUTSIDE the inverted
    * page (it's a sibling, not filtered), so a black caret would be invisible —
    * point it at a light colour in dark mode. */
  --doc-caret: #e8e8e8;
}

/* Smart lightness inversion of the document canvas — the heart of dark mode.
  * invert(1) hue-rotate(180deg) flips lightness but preserves hue for ALL
  * authored colors, so nothing is unreadable. Media is double-inverted back so
  * photos/logos render normally. */
.ep-root.dark .layout-page,
/* The paginated lane paints its content into `.docx-page-content`; inverting the page
   FRAME as well would flip the paper itself, so the sheet keeps its own token background
   and only the content it holds is lightness-inverted. */
/* Highlights are COUNTER-INVERTED, like images.
   `invert(1) hue-rotate(180deg)` preserves hue for most colours but not on the yellow/blue
   axis: yellow inverts to blue, and the hue-rotate matrix drives the blue channel negative
   where it clamps to zero, landing on a dark olive that reads as a redaction bar. Word keeps
   a highlight its authored colour, so the run is inverted back — the same treatment media
   already gets, for the same reason. */
.ep-root.dark .docx-page-content [data-highlight],
.ep-root.dark .layout-page [data-highlight] {
  filter: invert(1) hue-rotate(180deg);
}

/* The selection is drawn INSIDE the inverted subtree, so the colour written here is what
   the filter receives, not what the user sees. A normal blue came out orange; this is the
   pre-image that inverts back to the accent blue. The comment further up claiming the
   selection overlay sits outside the inverted page is true of the legacy lane only. */
.ep-root.dark .docx-page-content ::selection {
  background-color: rgba(177, 98, 0, 0.32);
}
.ep-root.dark .docx-page-content {
  /* contrast(0.92) softens the pure black/white extremes a plain invert
    * produces, landing on Word's gentler off-white text / dark-grey fills
    * rather than #fff on #000. */
  filter: invert(1) hue-rotate(180deg) contrast(0.92);
  /* Replace the painter's drop shadow (the filter would turn it into a weird
    * light glow) with a 1px ring. Pre-invert dark → post-invert a subtle light
    * border, matching Word's framed dark page. */
}
/* The ring replaces the page frame's drop shadow, so it belongs to the FRAME. Applied to
   the content box as well it outlined the text area — a box Word never draws — while the
   real page edge lost its separation from the workspace. */
.ep-root.dark .layout-page {
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18) !important;
}
.ep-root.dark .layout-page img,
.ep-root.dark .layout-page svg,
.ep-root.dark .layout-page canvas,
.ep-root.dark .layout-page video,
.ep-root.dark .layout-page [data-no-color-invert],
.ep-root.dark .docx-page-content img,
.ep-root.dark .docx-page-content svg,
.ep-root.dark .docx-page-content canvas,
.ep-root.dark .docx-page-content video,
.ep-root.dark .docx-page-content [data-no-color-invert] {
  filter: invert(1) hue-rotate(180deg);
}

/* Printing is always on white paper: drop the inversion and paint the page
  * white with black text (matches Word, saves toner). */
@media print {
  .ep-root.dark {
    --doc-page-bg: #ffffff;
    /* The colour a sheet is PAINTED. In the legacy lane the page is lightness-inverted, so
     `--doc-page-bg` is a pre-filter value and this is what it lands on; the paginated lane
     inverts only the content, so it paints this directly. Declared rather than written at
     the use site, or the print override below cannot reach it. */
    --doc-page-bg-rendered: #ffffff;
    /* Declared, not just defaulted in a `var()` fallback — the third silent-var bug in this
     file was one more unnamed token. Stays #000 in both themes so the content inversion
     lands on near-white. */
    --doc-page-text: #000000;
  }
  .ep-root.dark .layout-page,
  .ep-root.dark .layout-page img,
  .ep-root.dark .layout-page svg,
  .ep-root.dark .layout-page canvas,
  .ep-root.dark .layout-page video {
    filter: none;
  }
}

/* ============================================================================
  * DOCUMENT SCROLLBAR
  * ============================================================================ */

.ep-root .docx-editor__scroll-container,
.ep-root .docx-editor-vue__pages-viewport {
  scrollbar-width: auto;
  scrollbar-color: var(--doc-scrollbar-thumb) var(--doc-scrollbar-track);
}

.ep-root .docx-editor__scroll-container {
  /* `both-edges` reserves a symmetric gutter so the centered page stays centered
      on classic-scrollbar platforms (single-edge nudges it ~7px left). Matches
      the Vue viewport (DocxEditor.css `__pages-viewport`). */
  scrollbar-gutter: stable both-edges;
}

.ep-root .docx-editor__scroll-container::-webkit-scrollbar,
.ep-root .docx-editor-vue__pages-viewport::-webkit-scrollbar {
  width: var(--doc-scrollbar-size);
  height: var(--doc-scrollbar-size);
}

.ep-root .docx-editor__scroll-container::-webkit-scrollbar-track,
.ep-root .docx-editor-vue__pages-viewport::-webkit-scrollbar-track {
  background: var(--doc-scrollbar-track);
}

.ep-root .docx-editor__scroll-container::-webkit-scrollbar-thumb,
.ep-root .docx-editor-vue__pages-viewport::-webkit-scrollbar-thumb {
  background: var(--doc-scrollbar-thumb);
  border: 3px solid transparent;
  border-radius: 9999px;
  background-clip: content-box;
}

.ep-root .docx-editor__scroll-container:hover::-webkit-scrollbar-thumb,
.ep-root .docx-editor-vue__pages-viewport:hover::-webkit-scrollbar-thumb {
  background: var(--doc-scrollbar-thumb-hover);
  border: 3px solid transparent;
  border-radius: 9999px;
  background-clip: content-box;
}

/* ============================================================================
  * CURSOR / CARET STYLING
  * ============================================================================ */

/* Base cursor styles for all editable elements */
[contenteditable='true'] {
  /* Black caret for light backgrounds - highly visible */
  caret-color: #000;

  /* Ensure cursor is always visible */
  outline: none;

  /* Smooth caret animation */
  caret-shape: bar;
}

/* Editable runs - the main text editing elements */
.docx-run-editable[contenteditable='true'] {
  caret-color: #000;

  /* Ensure minimum height for cursor visibility in empty runs */
  min-height: 1em;

  /* Display inline for text flow */
  display: inline;
}

/* Empty paragraph cursor placeholder */
.docx-paragraph-empty [contenteditable='true'] {
  /* Ensure cursor is visible in empty paragraphs */
  min-height: 1em;
  min-width: 1px;
  display: inline-block;
}

/* Editable paragraphs container */
.docx-paragraph-editable {
  /* Allow cursor placement anywhere in paragraph */
  cursor: text;
}

/* ============================================================================
  * FOCUS STATES
  * ============================================================================ */

/* Subtle focus indicator without disrupting layout */
.docx-run-editable[contenteditable='true']:focus {
  outline: none;
  /* Optional: very subtle indicator - uncomment if needed */
  /* box-shadow: 0 0 0 1px rgba(26, 115, 232, 0.2); */
}

/* Focus within paragraph */
.docx-paragraph-editable:focus-within {
  /* No visible border to maintain WYSIWYG fidelity */
  outline: none;
}

/* ============================================================================
  * SELECTION HIGHLIGHTING
  * ============================================================================ */

/*
  * Selection highlighting CSS ensures consistent visual feedback when selecting
  * text across multiple runs (spans) with different formatting.
  *
  * Key considerations:
  * - Use !important to override inline styles from formatting
  * - Ensure selection is visible against various backgrounds
  * - Maintain text color (inherit) for readability
  * - Use rgba for semi-transparent highlight that shows text clearly
  */

/* Base selection styling for all editable elements */
.docx-run-editable::selection,
.docx-run-editable *::selection,
.docx-run::selection,
.docx-run *::selection,
[contenteditable='true']::selection,
[contenteditable='true'] *::selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* Firefox selection */
.docx-run-editable::-moz-selection,
.docx-run-editable *::-moz-selection,
.docx-run::-moz-selection,
.docx-run *::-moz-selection,
[contenteditable='true']::-moz-selection,
[contenteditable='true'] *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* Selection in paragraphs - ensure runs within get consistent styling */
.docx-paragraph::selection,
.docx-paragraph *::selection,
.docx-paragraph-editable::selection,
.docx-paragraph-editable *::selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

.docx-paragraph::-moz-selection,
.docx-paragraph *::-moz-selection,
.docx-paragraph-editable::-moz-selection,
.docx-paragraph-editable *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* Painted hyperlinks.
 *
 * The anchor is FURNITURE: colour and underline come from the resolved `Hyperlink`
 * character style on the runs inside it, exactly as Word paints them, so this must not
 * impose a colour of its own or an authored override would be overruled by chrome.
 * What it adds is the affordance the character style cannot carry — a pointer cursor, a
 * visible focus ring — plus the inert case, where there is nothing to click. */
a.docx-hyperlink {
  cursor: pointer;
  /* The runs inside carry their own colour/decoration; the anchor stays transparent. */
  color: inherit;
  text-decoration: none;
}

a.docx-hyperlink:not([href]) {
  /* A refused scheme, a dangling relationship, or read-only page furniture: it still reads
   * as a link because the document says it is one, and it does nothing. */
  cursor: default;
}

a.docx-hyperlink:focus-visible {
  outline: 2px solid var(--doc-focus-ring);
  outline-offset: 1px;
  border-radius: 2px;
}

/* Selection in hyperlinks */
.docx-hyperlink::selection,
.docx-hyperlink *::selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

.docx-hyperlink::-moz-selection,
.docx-hyperlink *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* Selection on highlighted text - use darker selection for visibility */
.docx-run-highlighted::selection,
.docx-run-highlighted *::selection {
  background-color: rgba(26, 115, 232, 0.5) !important;
  color: inherit !important;
}

.docx-run-highlighted::-moz-selection,
.docx-run-highlighted *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.5) !important;
  color: inherit !important;
}

/* Selection on dark background text - lighter selection */
.docx-run-dark-bg::selection,
.docx-run-dark-bg *::selection {
  background-color: rgba(100, 181, 246, 0.5) !important;
  color: inherit !important;
}

.docx-run-dark-bg::-moz-selection,
.docx-run-dark-bg *::-moz-selection {
  background-color: rgba(100, 181, 246, 0.5) !important;
  color: inherit !important;
}

/* Selection on bold text - ensure same style */
.docx-run-bold::selection,
.docx-run-bold *::selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

.docx-run-bold::-moz-selection,
.docx-run-bold *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* Selection on italic text - ensure same style */
.docx-run-italic::selection,
.docx-run-italic *::selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

.docx-run-italic::-moz-selection,
.docx-run-italic *::-moz-selection {
  background-color: rgba(26, 115, 232, 0.3) !important;
  color: inherit !important;
}

/* ============================================================================
  * FIND & REPLACE HIGHLIGHTING
  * ============================================================================ */

/* Find/replace match highlighting */
.docx-find-highlight {
  background-color: rgba(255, 235, 59, 0.5) !important;
  border-radius: 2px;
}

/* Current find/replace match */
.docx-find-highlight-current {
  background-color: rgba(255, 152, 0, 0.6) !important;
  border-radius: 2px;
  outline: 2px solid rgba(255, 152, 0, 0.8);
}

/* ============================================================================
  * AI ACTION PREVIEW HIGHLIGHTING
  * ============================================================================ */

/* Text selected for AI action */
.docx-ai-selection-preview {
  background-color: rgba(156, 39, 176, 0.2);
  border-bottom: 2px dashed rgba(156, 39, 176, 0.6);
}

/* Transient paragraph flash used by scrollToParaId({ highlight }). */
.layout-paragraph.docx-paragraph-flash {
  animation: docx-paragraph-flash-fade var(--docx-paragraph-flash-duration, 1200ms) ease-out both;
}

@keyframes docx-paragraph-flash-fade {
  0%,
  70% {
    box-shadow: inset 0 0 0 9999px var(--docx-paragraph-flash-color, rgba(255, 235, 59, 0.55));
  }

  100% {
    box-shadow: inset 0 0 0 9999px transparent;
  }
}

/* ============================================================================
  * SELECTION OVERLAY (for programmatic highlighting)
  * ============================================================================ */

/* Container for selection overlay rectangles */
.docx-selection-overlay-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
  overflow: hidden;
}

/* Individual selection overlay rectangle */
.docx-selection-overlay-rect {
  position: absolute;
  background-color: rgba(66, 133, 244, 0.25);
  pointer-events: none;
  user-select: none;
}

/* ============================================================================
  * SPECIAL CONTENT TYPES
  * ============================================================================ */

/* Highlighted text - ensure caret is visible against yellow */
.docx-run-highlighted[contenteditable='true'] {
  caret-color: #333;
}

/* Dark background text - use white caret */
.docx-run-dark-bg[contenteditable='true'] {
  caret-color: #fff;
}

/* ============================================================================
  * EDITOR CONTAINER
  * ============================================================================ */

/* Main editor container */
.docx-editor {
  /* Inherit cursor styling */
  cursor: default;
}

/* Editor page area */
.docx-editor-page {
  cursor: text;
}

.docx-generated-region {
  cursor: pointer;
  user-select: none;
}

/*
 * Empty TOC furniture — the ONE box an empty region gets; paint-only, never model text.
 *
 * The control-boundary rectangle is suppressed for these regions (see the surface's
 * `suppressedIds`), so this is the whole affordance: subtle enough to read as a slot,
 * always on so the region stays identifiable and right-clickable. No minimum height —
 * the box is exactly the line layout reserved, so it cannot double up against the flow.
 */
.docx-toc-empty-placeholder {
  box-sizing: border-box;
  border: 1px solid color-mix(in srgb, var(--doc-primary) 28%, var(--doc-page-bg-rendered));
  border-radius: 3px;
  background: color-mix(in srgb, var(--doc-primary) 6%, var(--doc-page-bg-rendered));
}

/* Non-editable elements within editor */
.docx-list-marker,
.docx-bookmark-start,
.docx-bookmark-end,
.docx-field,
.docx-drawing-placeholder,
.docx-shape-placeholder,
.docx-content-control-chrome,
.docx-content-control-boundary,
.docx-content-control-label,
.docx-content-control-widget {
  cursor: default;
  user-select: none;
}

/* Content-control boundary furniture — overlay only; never contributes layout. */
.docx-content-control-boundary {
  box-sizing: border-box;
  border: 1px solid color-mix(in srgb, var(--doc-primary) 24%, var(--doc-page-bg-rendered));
  border-radius: 3px;
  background: color-mix(in srgb, var(--doc-primary) 3%, var(--doc-page-bg-rendered));
  opacity: 0;
  pointer-events: auto;
}

.docx-content-control-chrome[data-boundary-visible] .docx-content-control-boundary {
  opacity: 1;
}

.docx-content-control-chrome[data-active] .docx-content-control-boundary,
.docx-content-control-chrome[data-open] .docx-content-control-boundary,
.docx-content-control-chrome[data-hover] .docx-content-control-boundary,
.docx-content-control-chrome:hover .docx-content-control-boundary {
  border-color: var(--doc-primary);
  background: color-mix(in srgb, var(--doc-primary) 10%, transparent);
  opacity: 1;
}

/*
 * Populated TOC: nothing at rest — no border, no background — and never sticky from the
 * caret or a click. The surface sets `data-hover` on the painted chrome while the pointer
 * is over the region and takes it off again on the way out.
 */
.docx-content-control-chrome[data-docx-toc]:not([data-hover]):not([data-boundary-visible])
  .docx-content-control-boundary {
  opacity: 0;
}

.docx-content-control-label {
  box-sizing: border-box;
  max-width: 12rem;
  overflow: hidden;
  padding: 1px 6px;
  border-radius: 3px 3px 0 0;
  background: var(--doc-primary);
  color: var(--doc-on-primary);
  font:
    500 10px/14px system-ui,
    sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: none;
  pointer-events: none;
}

.docx-content-control-chrome[data-active] .docx-content-control-label,
.docx-content-control-chrome[data-open] .docx-content-control-label,
.docx-content-control-chrome[data-hover] .docx-content-control-label,
.docx-content-control-chrome:hover .docx-content-control-label {
  display: block;
}

.docx-content-control-widget {
  box-sizing: border-box;
  border-radius: 4px;
  background: color-mix(in srgb, var(--doc-primary) 4%, var(--doc-page-bg-rendered));
  border: 1px solid color-mix(in srgb, var(--doc-primary) 28%, var(--doc-page-bg-rendered)) !important;
  cursor: pointer !important;
}

.docx-content-control-chrome[data-active] .docx-content-control-widget,
.docx-content-control-chrome[data-open] .docx-content-control-widget,
.docx-content-control-chrome:hover .docx-content-control-widget {
  background: color-mix(in srgb, var(--doc-primary) 15%, transparent);
  border-color: color-mix(in srgb, var(--doc-primary) 55%, transparent) !important;
}

.docx-content-control-widget::after {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--doc-primary);
  font:
    600 10px/1 system-ui,
    sans-serif;
}

.docx-content-control-widget[data-docx-cc-widget='dropdown']::after,
.docx-content-control-widget[data-docx-cc-widget='comboBox']::after {
  content: '▾';
}

.docx-content-control-widget[data-docx-cc-widget='date']::after {
  content: '';
  inset: 3px;
  display: block;
  border: 1.5px solid currentcolor;
  border-radius: 2px;
  background: linear-gradient(currentcolor, currentcolor) 0 3px / 100% 1px no-repeat;
}

.docx-content-control-widget[data-docx-cc-widget='date']::before {
  content: '';
  position: absolute;
  z-index: 1;
  top: 2px;
  left: 5px;
  width: 1px;
  height: 3px;
  background: currentcolor;
  box-shadow: 4px 0 currentcolor;
}

.docx-content-control-widget[data-docx-cc-widget='checkbox']::after {
  content: '';
  inset: 2px 5px 4px;
  display: block;
  border-right: 2px solid currentcolor;
  border-bottom: 2px solid currentcolor;
  opacity: 0;
  transform: rotate(45deg);
}

.docx-content-control-widget[data-docx-cc-widget='checkbox'][data-checked='true']::after {
  opacity: 1;
}

.docx-content-control-widget:disabled,
.docx-content-control-widget[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed !important;
}

.docx-content-control-menu {
  min-width: 13rem;
  max-width: 18rem;
  max-height: 16rem;
  overflow: auto;
  background: var(--doc-popover-bg, #fff);
  border: 1px solid var(--doc-border, rgba(0, 0, 0, 0.15));
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);
  padding: 0.3rem;
  user-select: none;
}

.docx-content-control-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;
  font: inherit;
}

.docx-content-control-menu-item:hover {
  background: color-mix(in srgb, var(--doc-primary) 12%, transparent);
}

.docx-content-control-menu-input,
.docx-content-control-date {
  display: block;
  width: 100%;
  margin: 0 0 0.3rem;
  padding: 0.45rem 0.65rem;
  border-radius: 6px;
  box-sizing: border-box;
}

.docx-content-control-calendar {
  width: 17rem;
  max-width: calc(100vw - 1.5rem);
  padding: 0.65rem;
  border-radius: 12px;
}

.docx-content-control-calendar-input {
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 0.6rem;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--doc-border);
  border-radius: 7px;
  background: var(--doc-surface);
  color: var(--doc-text);
  font: inherit;
}

.docx-content-control-calendar-input:focus {
  border-color: var(--doc-primary);
  outline: 2px solid var(--doc-primary-light);
  outline-offset: 1px;
}

.docx-content-control-calendar-input[aria-invalid='true'] {
  border-color: var(--doc-danger);
}

.docx-content-control-calendar-input::-webkit-calendar-picker-indicator {
  display: none;
}

.docx-content-control-calendar-header {
  display: grid;
  grid-template-columns: 2rem 1fr 2rem;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 0.45rem;
}

.docx-content-control-calendar-title {
  text-align: center;
  font-weight: 600;
}

.docx-content-control-calendar-nav,
.docx-content-control-calendar-day {
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
}

.docx-content-control-calendar-nav {
  width: 2rem;
  height: 2rem;
  border-radius: 6px;
  font-size: 1.35rem;
}

.docx-content-control-calendar-weekdays,
.docx-content-control-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.2rem;
}

.docx-content-control-calendar-weekdays {
  margin-bottom: 0.2rem;
  color: var(--doc-text-muted);
  font-size: 0.75rem;
  text-align: center;
}

.docx-content-control-calendar-day {
  width: 2rem;
  height: 2rem;
  border-radius: 7px;
}

.docx-content-control-calendar-nav:hover,
.docx-content-control-calendar-day:hover {
  background: var(--doc-primary-light);
}

.docx-content-control-calendar-day[data-other-month] {
  color: var(--doc-text-muted);
  opacity: 0.6;
}

.docx-content-control-calendar-day[data-selected] {
  background: var(--doc-primary);
  color: var(--doc-on-primary);
}

.docx-content-control-calendar-day[data-today]:not([data-selected]) {
  box-shadow: inset 0 0 0 1px var(--doc-primary);
}

.docx-drawing {
  pointer-events: auto;
}

.docx-drawing-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.docx-drawing-layer-behind {
  z-index: 0;
}

.docx-drawing-layer-front {
  z-index: 2;
}

.docx-drawing-placeholder-card {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 1px dashed var(--doc-border, #c8c8c8);
  background: var(--doc-surface-muted, #f3f4f6);
  color: var(--doc-text-muted, #6b7280);
}

.docx-drawing-placeholder-label {
  font: 11px/1.3 var(--doc-font-ui, system-ui, sans-serif);
  text-align: center;
  padding: 4px;
}

.docx-drawing-image-frame {
  width: 100%;
  height: 100%;
}

.docx-drawing-crop-viewport {
  position: relative;
}

.docx-drawing-image {
  position: absolute;
  max-width: none;
  max-height: none;
}

.ep-root.dark .docx-drawing-placeholder-card,
.dark .docx-drawing-placeholder-card {
  background: var(--doc-surface-muted, #2a2a2a);
  border-color: var(--doc-border, #404040);
  color: var(--doc-text-muted, #a3a3a3);
}

/* ============================================================================
  * TEMPLATE VARIABLES
  * ============================================================================ */

/* Template variable highlighting - non-editable within run */
.docx-run-has-variable [contenteditable='false'] {
  cursor: default;
  user-select: all;
}

/* Table interaction furniture (core-owned, semantic geometry). */
.docx-table-furniture {
  z-index: 3;
  pointer-events: none;
}

.docx-table-divider-handle,
.docx-table-edge-handle-right {
  pointer-events: auto;
}

.docx-table-resize-preview {
  background-color: var(--doc-primary);
  opacity: 0.85;
  pointer-events: none;
}

.docx-table-insert-row,
.docx-table-insert-column {
  pointer-events: auto;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 1px solid var(--doc-border-dark);
  border-radius: 2px;
  background: var(--doc-surface);
  color: var(--doc-text-muted);
  font-size: 12px;
  line-height: 14px;
  cursor: pointer;
}

.paged-editor--readonly .docx-table-furniture {
  display: none !important;
}

/* Table chrome — contextual border/fill controls (Task 9). */
.docx-table-chrome {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
}

.docx-table-chrome__panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  right: 0;
  min-width: 150px;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  box-shadow: 0 4px 16px var(--doc-shadow);
  padding: 6px;
}

.docx-table-chrome__target-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2px;
}

.docx-table-chrome__option,
.docx-table-chrome__target-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    border-color 0.12s ease;
}

.docx-table-chrome__option:hover:not(:disabled),
.docx-table-chrome__target-btn:hover:not(:disabled) {
  background: var(--doc-bg-hover);
}

.docx-table-chrome__option:focus-visible,
.docx-table-chrome__target-btn:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: 1px;
}

.docx-table-chrome__option:disabled,
.docx-table-chrome__target-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

.docx-table-chrome__option[data-active='true'],
.docx-table-chrome__target-btn[data-active='true'] {
  background: var(--doc-toggle-active-bg);
  color: var(--doc-toggle-active-fg);
}

.docx-table-chrome__width-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 6px 12px;
  border: none;
  background: transparent;
  color: var(--doc-text);
  font-size: 12px;
  cursor: pointer;
  text-align: left;
}

.docx-table-chrome__width-row:hover:not(:disabled) {
  background: var(--doc-bg-hover);
}

.docx-table-chrome__width-row:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: -2px;
}

.docx-table-chrome__width-row:disabled {
  opacity: 0.3;
  cursor: default;
}

.docx-table-chrome__swatch {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 1px solid var(--doc-border-dark);
  border-radius: 2px;
  background: var(--doc-surface);
}

.docx-table-line {
  display: block;
  width: 50px;
  height: 1px;
  background: var(--doc-text);
  border-radius: 0;
}

.docx-table-line--single {
  display: block;
  width: 50px;
  height: 1px;
  background: var(--doc-text);
}

.docx-table-line--dashed {
  background: none;
  border-top: 1px dashed var(--doc-text);
  height: 0;
}

.docx-table-line--dotted {
  background: none;
  border-top: 1px dotted var(--doc-text);
  height: 0;
}

.docx-table-line--double {
  height: 3px;
  background: none;
  border-top: 1px solid var(--doc-text);
  border-bottom: 1px solid var(--doc-text);
}

.docx-table-line--triple {
  height: 5px;
  background: none;
  border-top: 1px solid var(--doc-text);
  border-bottom: 1px solid var(--doc-text);
  box-shadow: inset 0 1px 0 var(--doc-text);
}

.docx-table-line--thick {
  height: 3px;
  background: var(--doc-text);
}

.docx-table-chrome__destructive-row {
  color: var(--doc-destructive);
}

.docx-table-chrome__destructive-row:hover:not(:disabled) {
  background: var(--doc-destructive-hover-bg);
}

@media (max-width: 640px) {
  .docx-table-chrome {
    max-width: 100%;
  }

  .docx-table-chrome__target-grid {
    grid-template-columns: repeat(4, minmax(28px, 1fr));
  }
}

@media (prefers-reduced-motion: reduce) {
  .docx-table-chrome__option,
  .docx-table-chrome__target-btn,
  .docx-table-chrome__width-row {
    transition: none;
  }
}

/* ============================================================================
  * LAYOUT TABLE COLUMN RESIZE
  * ============================================================================ */

/* ============================================================================
  * TABLE CELL SELECTION (visible layout table cells)
  * ============================================================================ */

.layout-table-cell-selected {
  position: relative;
  outline: 2px solid var(--doc-selection);
  outline-offset: -2px;
}

.layout-table-cell-selected::after {
  content: '';
  position: absolute;
  inset: 0;
  background-color: rgba(66, 133, 244, 0.15);
  pointer-events: none;
}

.layout-table-resize-handle {
  background-color: transparent;
  transition: background-color 0.15s;
}

.layout-table-resize-handle[data-active='true'] {
  background-color: transparent;
}

.layout-table-resize-handle[data-active='true']::after,
.layout-table-edge-handle-right[data-active='true']::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background-color: var(--doc-primary);
  opacity: 0.75;
  pointer-events: none;
  transform: translateX(-50%);
}

.layout-table-resize-handle:hover,
.layout-table-resize-handle.dragging {
  background-color: transparent;
}

.layout-table-resize-handle:hover::after,
.layout-table-resize-handle.dragging::after {
  opacity: 1;
}

/* Row resize handles */
.layout-table-row-resize-handle,
.layout-table-edge-handle-bottom {
  background-color: transparent;
  transition: background-color 0.15s;
}

.layout-table-row-resize-handle[data-active='true']::after {
  content: '';
  position: absolute;
  top: 50%;
  right: 0;
  left: 0;
  height: 2px;
  background-color: var(--doc-primary);
  opacity: 0.75;
  pointer-events: none;
  transform: translateY(-50%);
}

.layout-table-row-resize-handle:hover,
.layout-table-row-resize-handle.dragging,
.layout-table-edge-handle-bottom:hover,
.layout-table-edge-handle-bottom.dragging {
  background-color: transparent;
}

.layout-table-row-resize-handle:hover::after,
.layout-table-row-resize-handle.dragging::after {
  opacity: 1;
}

/* Right edge handle */
.layout-table-edge-handle-right {
  background-color: transparent;
  transition: background-color 0.15s;
}

.layout-table-edge-handle-right[data-active='true'] {
  background-color: transparent;
}

.layout-table-edge-handle-right:hover,
.layout-table-edge-handle-right.dragging {
  background-color: transparent;
}

.layout-table-edge-handle-right:hover::after,
.layout-table-edge-handle-right.dragging::after {
  opacity: 1;
}

/* ============================================================================
  * READONLY MODE — suppress interactive editing cues
  * ============================================================================ */

/* Hide table resize handles */
.paged-editor--readonly .layout-table-resize-handle,
.paged-editor--readonly .layout-table-row-resize-handle,
.paged-editor--readonly .layout-table-edge-handle-bottom,
.paged-editor--readonly .layout-table-edge-handle-right {
  display: none !important;
}

/* Remove header/footer hover effects and edit hints */
.paged-editor--readonly .layout-page-header,
.paged-editor--readonly .layout-page-footer {
  cursor: default;
  pointer-events: none;
}

/* Remove text cursor from page content */
.paged-editor--readonly .layout-page-content {
  cursor: default;
}

/* Outline heading hover */
.docx-outline-heading-btn:hover {
  background-color: var(--doc-bg-hover);
}

/* React toolbar toggle buttons (bold/italic/comments/...). Owned here, not via
  * Tailwind utilities: `cn` is clsx-only (no tailwind-merge), so competing
  * hover:bg utilities don't dedupe and the active slab could lose its color on
  * hover (white icon on a light bg). The `.ep-root` prefix outranks the
  * single-class Tailwind hover utilities. */
.ep-root .ep-toolbar-toggle:hover {
  background-color: var(--doc-bg-hover);
  color: var(--doc-text);
}
.ep-root .ep-toolbar-toggle[data-active='true'],
.ep-root .ep-toolbar-toggle[data-active='true']:hover {
  background-color: var(--doc-toggle-active-bg);
  color: var(--doc-toggle-active-fg);
}

/* Outline / navigation toggle button (shown when the panel is collapsed).
  * Google-Docs-style filled circular control: a resting disc + ring so it
  * reads as a button against the gray document gutter (--doc-bg), darkening
  * on hover. Adapters supply only position (it tracks horizontal scroll). */
.docx-outline-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--doc-border-light);
  background: var(--doc-bg-hover);
  color: var(--doc-text-muted);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    color 0.12s ease,
    box-shadow 0.12s ease;
}
.docx-outline-toggle:hover {
  background: var(--doc-border);
  color: var(--doc-text);
  box-shadow: 0 1px 3px rgba(60, 64, 67, 0.18);
}
.docx-outline-toggle:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: 2px;
}

/* ============================================================================
  * HEADER / FOOTER EDITING
  *
  * These styles are needed when editing headers/footers inline (Google Docs style).
  * They must be in dist/styles.css since the runtime CSS import in
  * OffscreenEditorHost.tsx is stripped by tsup (injectStyle: false).
  * ============================================================================ */

/* Page content area — show text cursor when hovering over editable content */
.layout-page-content {
  cursor: text;
}

/* Block-level Structured Document Tag (content control) boundary.
    The painter lays body fragments as flat absolutely-positioned siblings, so
    the boundary is a single overlay box per control (see renderSdtBoundaryBoxes)
    spanning its fragments at content width — drawn as one rounded rectangle
    like Word, with a corner label chip revealed on hover/focus. The box is
    non-interactive so it never steals clicks from the editable content under it.
    Nested controls each draw their own (slightly inset) box. */
.layout-block-sdt-box {
  pointer-events: none;
  border: 1px solid transparent;
  border-radius: 4px;
  box-sizing: border-box;
  transition: border-color 0.1s ease;
  z-index: 1;
}
.layout-block-sdt-box.is-active,
.layout-block-sdt-box.is-focused {
  border-color: rgba(25, 103, 210, 0.5);
}
/* Corner label chip — hidden until its control is hovered/active. */
.layout-block-sdt-label {
  position: absolute;
  left: -1px;
  bottom: 100%;
  max-width: 160px;
  height: 16px;
  padding: 0 6px;
  font-size: 10px;
  line-height: 16px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #fff;
  background-color: rgba(25, 103, 210, 0.92);
  border-radius: 4px 4px 0 0;
  display: none;
}
.layout-block-sdt-box.is-active .layout-block-sdt-label,
.layout-block-sdt-box.is-focused .layout-block-sdt-label {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

/* Header/footer CONTENT is non-interactive in normal mode: a single click on a
    header/footer is already a no-op (Word parity), and — crucially — a page- or
    margin-anchored shape (e.g. a full-page letterhead in a header) overflows the
    band and would otherwise sit on top of the body and swallow clicks meant for
    the document text (#856). The band element itself keeps pointer events so it
    stays the double-click-to-edit target; only its content is passed through.
    Kept here (not only in prosemirror/editor.css) so the React adapter's
    styles.css build — which compiles this file — ships the rule. */
.layout-page-header > *,
.layout-page-footer > * {
  pointer-events: none;
}

/* While editing a region, its content must be hittable again so clicks map to
    header/footer caret positions. */
.paged-editor--editing-header .layout-page-header > *,
.paged-editor--editing-footer .layout-page-footer > * {
  pointer-events: auto;
}

/* Header/footer areas — double-click hint */
.layout-page-header,
.layout-page-footer {
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.layout-page-header:hover,
.layout-page-footer:hover {
  background-color: rgba(37, 99, 235, 0.06);
}
/* Show "Double-click to edit" hint on hover when area is empty */
.layout-page-header:empty:hover::after {
  content: 'Double-click to add header';
  display: block;
  text-align: center;
  color: var(--doc-text-subtle);
  font-size: 11px;
  padding: 4px 0;
}
.layout-page-footer:empty:hover::after {
  content: 'Double-click to add footer';
  display: block;
  text-align: center;
  color: var(--doc-text-subtle);
  font-size: 11px;
  padding: 4px 0;
}

/*
  * Phase 5 of HF editing unification (openspec/changes/unify-hf-editing/):
  * the inline overlay no longer mounts a PM EditorView, so the entire
  * `.hf-editor-pm` rule block (font-strut zeroing, table-layout overrides,
  * `top: 0.4em` shim, line-height resets) is gone. Painter + persistent
  * hidden PM are the only HF rendering paths now.
  */

/* Dim body content when editing header/footer */
.paged-editor--hf-editing .layout-page-content {
  opacity: 0.4;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

/* While editing one HF region, the sibling region (and the non-edited area)
    shows a normal arrow, not the double-click "pointer" hint. The active
    region's `cursor: text` below wins via later source order. */
.paged-editor--hf-editing .layout-page-header,
.paged-editor--hf-editing .layout-page-footer {
  cursor: default;
}

/* Dotted border on active header area; text caret since it's being edited */
.paged-editor--editing-header .layout-page-header {
  border-bottom: 1px dotted var(--doc-primary);
  cursor: text;
}

/* Dotted border on active footer area; text caret since it's being edited */
.paged-editor--editing-footer .layout-page-footer {
  border-top: 1px dotted var(--doc-primary);
  cursor: text;
}

/*
  * HF editing unification phase 2 (openspec/changes/unify-hf-editing/):
  * removed; the painter is now the sole visible HF renderer in both modes
  * and the inline overlay's PM container moves off-screen instead.
  */

/* Remove hover effect on header/footer when in editing mode */
.paged-editor--hf-editing .layout-page-header:hover,
.paged-editor--hf-editing .layout-page-footer:hover {
  background-color: transparent;
}

/* Body caret blink for the Vue adapter's painted caret (useSelectionSync sets
    `animation: ep-caret-blink ...` inline). React drives its caret's blink from a
    JS timer instead; both land on the same 530ms half-period, which is the
    platform default. Defined here so the keyframes aren't duplicated per adapter. */
@keyframes ep-caret-blink {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

/* HF caret overlay blink. Used by the painted HF caret in both adapters
    (DocxEditorPagedArea.tsx / DocxEditor.vue set `animation: hf-caret-blink ...`
    inline). Defined once here so the keyframes aren't duplicated per adapter. */
@keyframes hf-caret-blink {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

/* Section break indicator */
.docx-section-break {
  position: relative;
}
.docx-section-break::after {
  content: 'Section Break (' attr(data-section-break) ')';
  display: block;
  text-align: center;
  font-size: 9px;
  color: var(--doc-text-muted);
  border-top: 1px dashed var(--doc-border);
  margin-top: 4px;
  padding-top: 2px;
  pointer-events: none;
}

/* Hyperlink popup icon button hover */
.ep-hyperlink-popup__icon-btn:hover {
  background: var(--doc-bg-hover);
}

/* =============================================================================
  * ProseMirror decoration forwarding overlay
  *
  * Generic surface for decorations published via PM plugins' `props.decorations`
  * (the painter doesn't render them itself — see `DecorationLayer.tsx`).
  * Children are absolutely-positioned inside this container; pointer-events
  * are off by default so editing isn't blocked. Plugins that need hover/click
  * on a decoration (e.g. cursor name labels) opt in via inline styles.
  *
  * z-index: 11 — one above SelectionOverlay (10) so cursor name labels render
  * above the local caret.
  * ============================================================================= */
.paged-editor__decoration-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 11;
}

/* Default styles for y-prosemirror remote cursor decorations. Consumers can
  * override by providing their own `.ProseMirror-yjs-cursor` rules. */
.ProseMirror-yjs-cursor {
  position: relative;
  margin-left: -1px;
  margin-right: -1px;
  border-left: 1px solid;
  border-right: 1px solid;
  word-break: normal;
  pointer-events: none;
}
.ProseMirror-yjs-cursor > div {
  position: absolute;
  top: -1.05em;
  left: -1px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  color: #fff;
  padding: 2px 4px;
  border-radius: 3px 3px 3px 0;
  white-space: nowrap;
  user-select: none;
  pointer-events: none;
}

/* Tracked-revision styles live in core (prosemirror/editor.css), shared
    by React + Vue adapters. Do not duplicate here. */

/* Interactive trigger for typed controls (checkbox/dropdown/date). The box is
    pointer-events:none; the trigger re-enables them so it is clickable. Sits at
    the top-right corner of the control box. */
.layout-sdt-widget {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 18px;
  height: 18px;
  padding: 0 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  line-height: 1;
  color: var(--doc-primary);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(25, 103, 210, 0.5);
  border-radius: 3px;
  cursor: pointer;
  pointer-events: auto;
  opacity: 0.55;
  transition: opacity 0.1s ease;
}
.layout-block-sdt-box.is-active .layout-sdt-widget,
.layout-block-sdt-box.is-focused .layout-sdt-widget,
.layout-sdt-widget:focus {
  opacity: 1;
}
.layout-sdt-widget:hover {
  background: var(--doc-primary-light);
}

.layout-inline-sdt-widget {
  cursor: pointer;
  pointer-events: auto;
  border-radius: 2px;
  outline-offset: 1px;
  user-select: none;
}
.layout-inline-sdt-widget:hover,
.layout-inline-sdt-widget:focus {
  background: var(--doc-primary-light);
  outline: 1px solid rgba(25, 103, 210, 0.55);
}

/* Popup for dropdown/date content-control widgets (rendered by the adapter). */
.layout-sdt-widget-popup {
  min-width: 120px;
  max-height: 240px;
  overflow-y: auto;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border-light);
  border-radius: 6px;
  box-shadow: 0 2px 10px var(--doc-shadow);
  padding: 4px;
  font-size: 13px;
}
.layout-sdt-widget-option {
  display: block;
  width: 100%;
  text-align: left;
  padding: 6px 10px;
  border: 0;
  background: transparent;
  border-radius: 4px;
  cursor: pointer;
  color: var(--doc-text);
}
.layout-sdt-widget-option:hover {
  background: var(--doc-primary-light);
}
.layout-sdt-widget-empty {
  padding: 6px 10px;
  color: var(--doc-text-muted);
}
.layout-sdt-widget-date {
  font: inherit;
  padding: 4px 6px;
  border: 1px solid var(--doc-border-light);
  border-radius: 4px;
}
.layout-sdt-widget-option.is-selected {
  font-weight: 600;
  background: var(--doc-bg-hover);
}

/* Repeating-section item add/remove affordances (bottom-right of the item box). */
.layout-sdt-repeat-controls {
  position: absolute;
  bottom: 1px;
  right: 1px;
  display: flex;
  gap: 2px;
  opacity: 0.55;
  pointer-events: none;
}
.layout-block-sdt-box.is-active .layout-sdt-repeat-controls,
.layout-block-sdt-box.is-focused .layout-sdt-repeat-controls {
  opacity: 1;
}
.layout-sdt-repeat-btn {
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  font-size: 11px;
  line-height: 1;
  color: var(--doc-primary);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(25, 103, 210, 0.5);
  border-radius: 3px;
  cursor: pointer;
  pointer-events: auto;
}
.layout-sdt-repeat-btn:hover {
  background: var(--doc-primary-light);
}

/* ============================================================================
  * Revision indicators shared by both adapters.
  * Visible painter cues live here so React and Vue stay in lockstep.
  * ========================================================================== */

.layout-revision-bars {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.layout-revision-change-bar {
  position: absolute;
  left: -10px;
  width: 2px;
  pointer-events: none;
}

.layout-revision-change-bar.layout-revision-ins {
  background-color: var(--doc-revision-insertion);
}

.layout-revision-change-bar.layout-revision-del {
  background-color: var(--doc-revision-deletion);
}

.docx-table-row--revision::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -8px;
  width: 2px;
  pointer-events: none;
}

.docx-table-row--revision.layout-revision-ins::before {
  background-color: var(--doc-revision-insertion);
}

.docx-table-row--revision.layout-revision-del::before {
  background-color: var(--doc-revision-deletion);
}

.docx-table-row--revision.layout-revision-ins .layout-run-text {
  color: var(--doc-revision-insertion);
}

.docx-table-row--revision.layout-revision-del .layout-run-text {
  color: var(--doc-revision-deletion);
  text-decoration: line-through;
}

/* The row is a BOX, so it gets the box treatment text changes get from their wash: a tracked
   row reads as one pending decision at a glance, and gives the hover balloon a visibly
   bounded target. Directional, not grey — a row is added or removed, and the wash should say
   which the way the struck/underlined text inside it already does. */
.docx-table-row--revision.layout-revision-ins {
  background-color: var(--doc-revision-insertion-wash);
}

.docx-table-row--revision.layout-revision-del {
  background-color: var(--doc-revision-deletion-wash);
}

/* A tracked FORMAT change: grey, because nothing was added or removed — the appearance
   itself is the pending decision. A stylesheet rule rather than painter inline style on
   purpose: an authored underline or strike arrives as inline style and therefore WINS over
   the dotted rule here, and a host that finds even this too loud for its documents can
   silence it with one override. */
.docx-revision-format {
  background-color: var(--doc-revision-format-wash);
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--doc-revision-format);
}

.layout-revision-pmark {
  position: relative;
}

.layout-revision-pmark-glyph {
  display: inline;
  margin-left: 2px;
  font-weight: normal;
  opacity: 0.75;
  pointer-events: none;
}

.layout-revision-pmark-glyph.layout-revision-ins {
  color: var(--doc-revision-insertion);
}

.layout-revision-pmark-glyph.layout-revision-del {
  color: var(--doc-revision-deletion);
  text-decoration: line-through;
}

.ep-revision-cell.ep-revision-ins {
  box-shadow: inset 0 3px 0 var(--doc-revision-insertion);
  background-color: var(--doc-revision-insertion-tint);
}

.ep-revision-cell.ep-revision-del {
  box-shadow: inset 0 3px 0 var(--doc-revision-deletion);
  background-color: var(--doc-revision-deletion-tint);
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--doc-revision-deletion) 60%, transparent);
}

.ep-revision-cell.ep-revision-merge {
  box-shadow: inset 0 3px 0 var(--doc-text-muted);
  background-color: color-mix(in srgb, var(--doc-text-muted) 8%, transparent);
}

.layout-run-image.docx-insertion,
.layout-run-image-wrapper.docx-insertion > .layout-run-image,
.layout-block-image.docx-insertion,
.layout-image.docx-insertion,
.layout-page-floating-image.docx-insertion > img,
.layout-cell-floating-image.docx-insertion > img,
.layout-header-footer-floating-image.docx-insertion > img {
  outline: 2px solid var(--doc-revision-insertion);
  outline-offset: 1px;
}

.layout-run-image.docx-deletion,
.layout-run-image-wrapper.docx-deletion > .layout-run-image,
.layout-block-image.docx-deletion,
.layout-image.docx-deletion,
.layout-page-floating-image.docx-deletion > img,
.layout-cell-floating-image.docx-deletion > img,
.layout-header-footer-floating-image.docx-deletion > img {
  outline: 2px solid var(--doc-revision-deletion);
  outline-offset: 1px;
  opacity: 0.6;
}

/* ========================================================================
 * ONE-SURFACE PAINT LAYER — restored after the legacy stylesheet swap dropped
 * it. NOT legacy chrome: these belong to the greenfield painter, which owns the
 * document canvas (port rule 4). Losing them broke hit testing, because the page
 * stack lost the positioning the engine's geometry assumes.
 * ======================================================================== */
/* ========================================================================
 * One-surface interactive paginated editing (interactive-paginated-editing
 * task 6.1).
 *
 * The single source of truth for the direct-editing surface. Both adapters
 * `@import` this file and add no CSS of their own (enforced by
 * `bun run check:adapter-css-thin`).
 *
 * Layer model, bottom to top, inside one scroll container:
 *
 *   .ep-one-surface                 positioning context
 *   └ .ep-one-surface__pages        stacked page boxes
 *     └ .ep-one-surface__page       one engine-sized page box
 *       ├ .ep-one-surface__content  painted DisplayItem[] (engine geometry)
 *       └ .ep-one-surface__overlay  caret + selection, pointer-transparent
 *
 * Every box that carries document geometry is positioned by the engine in
 * content pixels through inline styles. Nothing here invents or overrides a
 * width, height, x, or y for a page or a display item — the rules below only
 * supply painting, stacking, and pointer policy. Zoom is NOT a CSS transform:
 * the engine holds the scale itself and repaints (re-laying out where the scale
 * changes measurement), so every box above is already sized in zoomed pixels
 * and geometry and paint agree by construction.
 * ======================================================================== */

.ep-one-surface {
  position: relative;
  /* Page separation is a paint concern; the engine reports the same gap in
   * scrollGeometry so hit testing and paint stay in agreement. */
  --doc-page-gap: 24px;
}

/* Scroll container. The host reports scrollTop/scrollLeft to the engine as
 * InteractionHostMetrics.scrollOffset — the engine never reads the DOM. */
.ep-one-surface__viewport {
  position: relative;
  overflow: auto;
  overscroll-behavior: contain;
}

/* The page stack is the engine's content origin: the engine publishes page 0 at
 * content (0, 0), and `measureInteractionHostMetrics` reports this element's
 * client origin as that point.
 *
 * So the stack must HUG its pages. `width: max-content` makes the box exactly as
 * wide as the widest page and `margin-inline: auto` centers the whole stack in a
 * wider viewport — the pretty centered look, with the stack's top-left still
 * sitting on the page's top-left. Centering pages *inside* a full-width stack
 * (`align-items: center` on a stretched box) instead offsets every page from the
 * stack origin, which shifts every hit test by that offset and makes clicks land
 * on "page background". */
.ep-one-surface__pages {
  display: flex;
  flex-direction: column;
  width: max-content;
  margin-inline: auto;
  gap: var(--doc-page-gap);
  /* Zoom repaints rather than transforms, so nothing here is scaled. The origin
   * is pinned anyway so a host that adds a transform of its own (a print
   * preview, a fit-to-width gesture) scales about the stack's top-left, keeping
   * client→content conversion a plain divide. */
  transform-origin: 0 0;
}

.ep-one-surface__page {
  position: relative;
  flex: none;
  background: var(--doc-page-bg);
  box-shadow: 0 1px 3px var(--doc-shadow);
  /* Painted items are placed absolutely in page-local coordinates and must not
   * bleed past the sheet. */
  overflow: hidden;
}

/* Painted display items. Text is selected through the engine's semantic
 * selection, never the browser's, so native selection is suppressed here to
 * stop a second, contradictory selection appearing on the same glyphs. */
.ep-one-surface__content {
  position: absolute;
  inset: 0;
  user-select: none;
  -webkit-user-select: none;
}

.ep-one-surface__content > * {
  position: absolute;
}

/* Overlay layer: caret and selection rectangles, both derived from
 * interaction-frame geometry. Pointer-transparent so a click always reaches
 * the page and resolves through the engine hit test. */
.ep-one-surface__overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.ep-one-surface__selection-rect {
  position: absolute;
  background: var(--doc-selection);
}

.ep-one-surface__caret {
  position: absolute;
  /* 2px, not 1: a hairline caret disappears against body text at 100% zoom on a
   * high-DPI screen, and reads as a rendering artefact rather than a cursor.
   * Every desktop word processor draws a two-pixel insertion point. */
  width: 2px;
  background: var(--doc-caret);
  animation: ep-caret-blink 1.06s steps(1) infinite;
}

/* A caret that is being moved or dragged should not blink. */
.ep-one-surface__caret--steady {
  animation: none;
}

/* Right-to-left runs paint their caret on the trailing edge; the engine
 * supplies the rect, this only marks direction for the host. */
.ep-one-surface__caret--rtl {
  direction: rtl;
}

/* Active IME composition. The composed range stays visible under the engine
 * selection so the user can see what the input method is holding. */
.ep-one-surface__composition {
  position: absolute;
  border-bottom: 1px solid var(--doc-text);
  pointer-events: none;
}

/* Explicit exceptions to overlay pointer-transparency: selection handles and
 * object controls that must receive their own pointer events. Anything using
 * this class opts out deliberately — it is not the default for overlay content.
 */
.ep-one-surface__overlay-control {
  pointer-events: auto;
}

/* The hidden ProseMirror input host. Position, size, clipping, and opacity are
 * owned imperatively by engine-binding's input-host module, which keeps the
 * host attached, non-`display:none`, and tracking the engine caret so browser
 * IME and autofill UI follow it.
 *
 * This class declares NO properties on purpose. It previously set
 * `contain: strict`, which was a bug: strict containment implies layout
 * containment, and a layout-contained element becomes the containing block for
 * `position: fixed` descendants and clips them to its padding box. The engine
 * mounts its clip shell inside this element and positions that shell `fixed` at
 * the caret's CLIENT rect, so containment made those client coordinates resolve
 * against this div rather than the viewport — measured in Chromium as an anchor
 * offset equal to the whole page-stack height (y 80 -> 2080 on a 2000px stack).
 * Every IME candidate window, composition popup, and autofill prompt was
 * anchored that far from the caret, and the engine's scroll-tracking
 * re-placement became a no-op.
 *
 * Do NOT add layout-affecting properties here. `contain`, `transform`,
 * `filter`, `perspective`, `will-change`, and `backdrop-filter` each create a
 * containing block for fixed descendants and would reintroduce this. */

/* The host must never expose a second visible or assistive copy of the
 * document, so its projected content is not painted. */
.ep-one-surface__input-host * {
  color: transparent;
}

/* Private browser-feedback checkpoint: one page-like sheet with the real
 * ProseMirror contenteditable. It is deliberately not a pagination claim. */
.ep-browser-first__page {
  box-sizing: border-box;
  width: 816px;
  min-height: 1056px;
  padding: 96px;
  overflow: visible;
  cursor: text;
}

.ep-browser-first__mount,
.ep-browser-first__mount * {
  color: var(--doc-caret);
}

.ep-browser-first__mount .ProseMirror {
  min-height: 864px;
  outline: none;
  font-size: 11pt;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.ep-browser-first__mount .ProseMirror p {
  margin: 0 0 0.75em;
}

@media (prefers-reduced-motion: reduce) {
  .ep-one-surface__caret {
    animation: none;
  }
}

/* ========================================================================
 * Polished editor shell (interactive-paginated-editing M4.2).
 *
 * Ported from the legacy DocxEditorShell presentation at 9bb06c38: a framed
 * app region, a scrolling document backdrop the page floats on, and slots for
 * toolbar, rulers, and the page indicator.
 *
 * The shell owns CHROME ONLY. It sets no document geometry — the page stack
 * inside `.ep-shell__canvas` is positioned by the engine, and the shell must
 * not introduce any horizontal offset the engine does not know about, or hit
 * testing drifts (the lesson from M3's centering bug).
 * ======================================================================== */

.ep-shell {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  background: var(--doc-bg);
  color: var(--doc-text);
}

.ep-shell__title,
.ep-shell__toolbar {
  flex: none;
  border-bottom: 1px solid var(--doc-border);
  background: var(--doc-surface);
}

/* The scrolling document region — the backdrop the page sits on. */
.ep-shell__document {
  position: relative;
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--doc-bg);
}

/* Sticky horizontal ruler: scrolls horizontally with the document, stays put
 * vertically, and never covers the page content. */
.ep-shell__ruler-h {
  position: sticky;
  top: 0;
  z-index: 2;
  flex: none;
  display: flex;
  justify-content: center;
  padding: 4px 20px;
  background: var(--doc-bg);
}

.ep-shell__canvas {
  position: relative;
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
}

/* Vertical ruler pinned to the canvas's left edge so it scrolls with the page. */
.ep-shell__ruler-v {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  pointer-events: none;
}

/* The one-surface viewport fills the canvas. Page centering stays the page
 * stack's own job (`margin-inline: auto` on `.ep-one-surface__pages`), so the
 * shell adds no offset the engine would have to be told about. */
.ep-shell__canvas > .ep-one-surface {
  flex: 1;
  min-width: 0;
}

/* Floating page indicator, out of the document flow and pointer-transparent so
 * it can never swallow a click meant for the page. */
.ep-shell__page-indicator {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  pointer-events: none;
}

/* Document scroll region padding: breathing room around the sheet, matching the
 * legacy backdrop. Applied to the viewport rather than the page stack so it
 * cannot shift the stack origin away from the engine's page origin. */
.ep-shell .ep-one-surface__viewport,
.docx-editor__content .ep-one-surface__viewport {
  padding: 24px 0;
  scrollbar-gutter: stable both-edges;
}

/* Legacy shell regions, ported at M6V.1. Geometry that the legacy code kept inline
 * stays inline in `DocxEditorShell.tsx`; only what it expressed in CSS is here.
 *
 * A DEVIATION RECORDED HERE EARLIER IS NOW REVERTED: this file used to keep
 * `.ep-one-surface__viewport` as the scroller inside the shell as well. With the shell's
 * container also declaring `overflow: auto`, neither box ended up bounded — the whole
 * chain grew to document height and the window scrolled, so the page indicator never
 * left page 1. Legacy's structure is restored: inside the shell,
 * `.docx-editor__scroll-container` is the sole scroller and the viewport is inert.
 * Bare (no chrome), the viewport still scrolls and nothing about it changes. */

/* Hosted in the shell: the shell's container scrolls, not this box. */
.ep-one-surface__viewport--hosted {
  overflow: visible;
}
/* The title + menu column, INSIDE the header row (legacy layout). It used to render as
 * two full-width bands under the header, which turned a single ~110px product band into
 * three tall stacked strips with the menu floating in whitespace. */
.docx-editor__title-region {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0;
  padding-left: 18px;
}

.docx-editor__scroll-container {
  display: flex;
  flex-direction: column;
}

.docx-editor__content {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* Title chrome and page indicator (interactive-paginated-editing M4.3). */

.ep-shell__title-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px;
}

.ep-shell__title-input {
  flex: 1;
  min-width: 0;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 4px 8px;
  font:
    500 15px/1.3 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
  color: var(--doc-text);
  background: transparent;
}

.ep-shell__title-input:hover:not([readonly]) {
  border-color: var(--doc-border);
}

.ep-shell__title-input:focus {
  outline: none;
  border-color: var(--doc-primary);
  box-shadow: 0 0 0 2px var(--doc-focus-ring);
}

.ep-shell__title-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* The indicator is a dark scrim in BOTH themes, so its text stays light —
 * --doc-on-primary flips dark in dark mode and would vanish here. */
.ep-shell__page-indicator-chip {
  background: var(--doc-overlay);
  color: #fff;
  padding: 6px 12px;
  border-radius: 4px;
  font:
    500 12px/1 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
  white-space: nowrap;
  user-select: none;
  transition: opacity 0.3s ease;
  /* A status readout, never a control. Both PageIndicator components document that
   * this element "never intercepts pointer events", but nothing enforced it: Playwright
   * click logs show the chip among the elements intercepting pointer events over the
   * document. (It is NOT the cause of the `?edit=1` smoke failures — those click a
   * paragraph inside the hidden input-host shell; see task M6E.1. This makes the
   * component's own documented contract true.) */
  pointer-events: none;
}

/* Public React page-number primitive. It is an overlay sibling of the viewport inside the
 * positioned workspace, so scrolling the document never moves the readout itself. */
.docx-editor__page-number {
  position: absolute;
  right: 24px;
  top: 50%;
  z-index: 1000;
  opacity: 0;
  transform: translateY(-50%);
}

.docx-editor__page-number[data-visible='true'] {
  opacity: 1;
}

/* Display-only rulers (interactive-paginated-editing M4.4). No margin or tab
 * markers and no drag handles: this change owns no section-geometry contract,
 * so a draggable handle would be a control that silently does nothing. */

.ep-ruler {
  position: relative;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border-light);
  border-radius: 2px;
  user-select: none;
  pointer-events: none;
}

.ep-ruler--horizontal {
  height: 22px;
}

/* The review pane's gutter reaches the ruler as a right MARGIN and the page as the scroller's
   right PADDING. Both move by the same distance, so both have to move on the same curve —
   without this the sheet glided left and the ruler above it snapped, and for the length of the
   animation the ruler measured a page that was no longer under it. */
.docx-horizontal-ruler {
  transition: margin 0.2s ease;
}

@media (prefers-reduced-motion: reduce) {
  .docx-horizontal-ruler {
    transition: none;
  }
}

.ep-ruler--vertical {
  height: 100%;
}

.ep-ruler__tick {
  position: absolute;
  background: var(--doc-text-subtle);
}

.ep-ruler--horizontal .ep-ruler__tick {
  bottom: 0;
  width: 1px;
}

.ep-ruler--vertical .ep-ruler__tick {
  right: 0;
  height: 1px;
}

.ep-ruler__label {
  position: absolute;
  font:
    400 9px/1 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
  color: var(--doc-text-muted);
}

.ep-ruler--horizontal .ep-ruler__label {
  left: 2px;
  bottom: 11px;
}

.ep-ruler--vertical .ep-ruler__label {
  right: 11px;
  top: -4px;
}

/* Toolbar (interactive-paginated-editing M4.5). Formatting and history controls
 * are enabled by Editor.can(command); a disabled control carries the engine's
 * own reason as its tooltip. */

/* Legacy formatting bar: a PILL, not a flat bar.
 *
 * The legacy root was `flex items-center px-2 py-1 bg-muted rounded-full
 * min-h-[36px] overflow-x-auto mx-2 mb-1`. An earlier M6V.1 attempt made it a
 * full-width flat bar with a bottom border and `flex-wrap: wrap`, which is a
 * different control and the wrong overflow behaviour — legacy SCROLLS horizontally
 * rather than wrapping, so the bar stays one row tall at any viewport. */
/* Geometry and colour now come from the legacy Tailwind classes on the element itself
 * (Toolbar.tsx:679: `flex items-center px-2 py-1 bg-muted rounded-full min-h-[36px]
 * overflow-x-auto mx-2 mb-1`). Only the scroll behaviour stays here: the pill scrolls
 * horizontally and must never become a second VERTICAL scroller. */
.ep-toolbar {
  flex-wrap: nowrap;
  flex-shrink: 0;
  overflow-y: hidden;
  scrollbar-width: thin;
}

/* One group plus the separator that precedes it, so the pair wraps together and a
 * separator never becomes the first thing on a wrapped row. */
.ep-toolbar__group-wrap {
  display: inline-flex;
  align-items: center;
}

.ep-toolbar__group {
  display: flex;
  align-items: center;
  gap: 2px;
}

/* Visually hidden but present for assistive technology: a parity-only picker has no
 * tooltip of its own, so its unavailable reason is exposed here instead. */
.ep-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.ep-toolbar__separator {
  width: 1px;
  align-self: stretch;
  margin: 4px 6px;
  background: var(--doc-border);
}

/* Sidebar frame (interactive-paginated-editing M4.6). */

.ep-sidebar {
  display: flex;
  flex-direction: column;
  width: 300px;
  flex: none;
  border-left: 1px solid var(--doc-border);
  background: var(--doc-surface);
}

.ep-sidebar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--doc-border);
}

.ep-sidebar__title {
  font:
    500 13px/1.2 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
  color: var(--doc-text);
}

.ep-sidebar__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-sidebar__close:hover {
  background: var(--doc-bg-hover);
}

.ep-sidebar__body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 12px;
}

/* Title/menu region and sidebar (M6V.1). Legacy rendered a menu row above the
 * formatting pill and an outline/agent sidebar as the main row's second flex child. */
.docx-editor__menu-bar {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px 10px 0;
  flex-shrink: 0;
}

.docx-editor__menu-item {
  padding: 3px 8px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text-subtle);
  font-size: 13px;
  cursor: default;
}

.docx-editor__sidebar {
  display: flex;
  flex-direction: column;
  width: 260px;
  flex-shrink: 0;
  border-left: 1px solid var(--doc-border);
  background: var(--doc-surface);
}

.docx-editor__sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  border-bottom: 1px solid var(--doc-border);
  font-size: 13px;
  color: var(--doc-text);
}

.docx-editor__sidebar-empty {
  padding: 10px;
  font-size: 12px;
  color: var(--doc-text-subtle);
}

/* Dialog launch surfaces: present and disabled for visual parity. */
.docx-editor__launchers {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px;
}

.docx-editor__launcher {
  text-align: left;
  padding: 5px 8px;
  border: 1px solid var(--doc-border);
  border-radius: 4px;
  background: var(--doc-surface);
  color: var(--doc-text-subtle);
  font-size: 12px;
  cursor: default;
  pointer-events: none;
}

/* Application header (M6V.1). The legacy product's top row: identity left, document
 * actions right. Actions are parity-only and disabled. */
.docx-editor__app-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 14px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--doc-border);
  background: var(--doc-surface);
}

.docx-editor__brand {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--doc-text);
}

.docx-editor__brand-name {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.docx-editor__app-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Header actions use solid 500-weight labels; muted text and normal weight make
 * these controls look disabled beside the document title. */
.docx-editor__app-action {
  padding: 6px 12px;
  border: 1px solid var(--doc-border);
  border-radius: 6px;
  background: var(--doc-surface);
  color: var(--doc-text);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  transition: all 0.15s;
  /* Parity-only: they look right and do nothing, with the reason on the tooltip. */
  cursor: default;
  pointer-events: none;
}

/* `styles.newButton` — the secondary action sits on the subtle background. */
.docx-editor__app-action:not(.docx-editor__app-action--primary):nth-of-type(2) {
  background: var(--doc-bg-subtle);
}

/* `styles.fileInputLabel` — the primary action is a solid dark button. */
.docx-editor__app-action--primary {
  background: var(--doc-text);
  border-color: var(--doc-text);
  color: var(--doc-on-primary);
}

/* The page floats on the workspace backdrop with a drop shadow, as in the reference. */
.docx-editor__content .ep-one-surface__page {
  box-shadow:
    0 1px 3px rgb(60 64 67 / 30%),
    0 4px 8px 3px rgb(60 64 67 / 15%);
}

/* Brand block, framework/theme toggles, and outline button (M6V.1, second pass).
 * All parity-only: this build IS the React adapter (Vue chrome is 10V.1), and the
 * document canvas is deliberately unthemed so it stays Word-faithful. */
.docx-editor__brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}

.docx-editor__brand-by {
  font-size: 10px;
  color: var(--doc-text-subtle);
}

.docx-editor__framework,
.docx-editor__theme {
  display: inline-flex;
  align-items: center;
  margin-left: 10px;
  padding: 2px;
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  background: var(--doc-bg-subtle);
  cursor: default;
  pointer-events: none;
}

/* The framework toggle carries TEXT labels ("React"/"Vue"), so it keeps a padded pill.
 * Folding it into the theme toggle's rule below forced both options to a 26px square and
 * crushed the labels into "ReactVue". */
.docx-editor__framework-option {
  padding: 3px 10px;
  border-radius: 6px;
  font-size: 12px;
  color: var(--doc-text-subtle);
  white-space: nowrap;
}

/* Theme options are 26px round icon buttons rather than padded text pills. */
.docx-editor__theme-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 9999px;
  font-size: 12px;
  color: var(--doc-text-subtle);
  transition:
    background 0.15s,
    color 0.15s;
}

.docx-editor__framework-option--active,
.docx-editor__theme-option--active {
  background: var(--doc-surface);
  color: var(--doc-text);
  /* The legacy shadow token, not a hand-mixed rgba. */
  box-shadow: 0 1px 2px var(--doc-shadow-subtle);
}

.docx-editor__theme {
  margin-left: 0;
  margin-right: 4px;
}
.docx-editor__theme-option {
  padding: 3px 8px;
}

/* Title indented to align with the page, as in the reference, rather than flush left. */
/* Retained so an existing consumer's selector still resolves; the region is indented by
 * default now that it lives inside the header row. */
.docx-editor__title-region--indented {
  padding-left: 18px;
}

/* Outline toggle: a circular button in the left gutter. */
.docx-editor__outline-toggle {
  position: absolute;
  left: 26px;
  top: 44px;
  z-index: 31;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--doc-border);
  border-radius: 50%;
  background: var(--doc-surface);
  color: var(--doc-text-subtle);
  cursor: default;
  pointer-events: none;
  box-shadow: 0 1px 2px rgb(0 0 0 / 8%);
}

/* The pill needs enough fill to read AS a pill against the workspace. */
.ep-toolbar {
  background: var(--doc-bg-subtle);
  border: 1px solid var(--doc-border);
}

/* Ruler margin zones (M6V.6), from the legacy `ui/HorizontalRuler.tsx`:
 * `MARGIN_ZONE_COLOR = var(--doc-shadow-subtle)` with a 1px border on the inner edge. */
.ep-ruler__margin {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--doc-shadow-subtle);
  pointer-events: none;
}

.ep-ruler__margin--start {
  left: 0;
  border-right: 1px solid var(--doc-shadow-subtle);
}

.ep-ruler__margin--end {
  right: 0;
  border-left: 1px solid var(--doc-shadow-subtle);
}

/* The vertical ruler's zones run the other axis; the shared `.ep-ruler__margin` rule
 * pins top/bottom, so these override the horizontal defaults. */
.ep-ruler__margin--top {
  left: 0;
  right: 0;
  bottom: auto;
  border-bottom: 1px solid var(--doc-shadow-subtle);
}

.ep-ruler__margin--bottom {
  left: 0;
  right: 0;
  top: auto;
  border-top: 1px solid var(--doc-shadow-subtle);
}

/* Canonical-tree projection: content the editor preserves but cannot edit yet.
 *
 * Shown as a visible chip rather than an empty span. An invisible placeholder reads as
 * "your picture is gone" when in fact it is in the tree and will be saved; a visible one
 * says what it is and that it is intact. Non-editable, so a caret cannot enter it. */
.docx-unknown-inline {
  display: inline-block;
  vertical-align: text-bottom;
  min-width: 2.4em;
  height: 1.15em;
  margin: 0 0.15em;
  border: 1px dashed var(--doc-border, #b4b8bf);
  border-radius: 3px;
  background: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--doc-border, #b4b8bf) 22%, transparent) 0 4px,
    transparent 4px 8px
  );
  cursor: default;
  user-select: none;
}

/* A tab renders as whitespace that can still be seen while selecting. */
.docx-tab {
  display: inline-block;
  min-width: 2em;
  white-space: pre;
  color: var(--doc-text-muted, #8a8f98);
}

/* The engine-owned paginated surface: painted pages plus a semantic caret and selection.
 * Geometry comes entirely from the layout records; these rules only supply appearance. */
.docx-paginated-surface {
  position: relative;
  outline: none;
}
.ep-root.dark .docx-paginated-surface .docx-page {
  background: var(--doc-page-bg-rendered);
}
/* Paper is always white, whatever the screen theme. Without resetting the CONTENT
   inversion here, printing in dark mode left near-white text on paper the printer drops to
   white — blank pages. `print-color-adjust` stops the sheet colour being dropped too. */
@media print {
  .ep-root.dark .docx-page-content,
  .ep-root.dark .docx-page-content img,
  .ep-root.dark .docx-page-content svg,
  .ep-root.dark .docx-page-content canvas,
  .ep-root.dark .docx-page-content video,
  .ep-root.dark .docx-page-content [data-no-color-invert] {
    filter: none !important;
  }
  .docx-paginated-surface .docx-page {
    background: #ffffff !important;
    color: #000000 !important;
    box-shadow: none !important;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}
.docx-paginated-surface .docx-page {
  /* The TOKEN, not a literal. Dark mode sets `--doc-page-bg` to #ccc precisely so the
     page inversion lands on Word's grey canvas; a hardcoded #fff inverts to pure black
     and takes the text down to unreadable with it. */
  background: var(--doc-page-bg-rendered, #fff);
  /* The page states its OWN text colour rather than inheriting the chrome's: a light chrome
     colour carried into the inverted content turned every run dark grey on grey. The token
     stays #000 in both themes precisely so the inversion lands on near-white. */
  color: var(--doc-page-text, #000000);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  /* Painted text stays selectable so the BROWSER can run drag, double-click-for-a-word and
     triple-click-for-a-paragraph; the surface reads the result back as model positions. */
  user-select: text;
  -webkit-user-select: text;
}
/* The caret and the TEXT highlight are the BROWSER's, so they follow real glyph shapes and
   per-line metrics instead of the uniform band a hand-drawn rectangle produces. */
.docx-paginated-surface .docx-pages {
  outline: none;
}

/* Inactive furniture: Word-like affordance that the band is enterable. Active band and
 * open-scope dimming live under `.docx-pages--hf-editing` so screen chrome never mutates
 * painted ink for print (print media resets opacity). */
.docx-paginated-surface .docx-hf:not([data-docx-hf-active]),
.docx-pages .docx-hf:not([data-docx-hf-active]) {
  cursor: text;
}

/* Blank furniture: a page with no header/footer paints an empty band over that margin.
 * Invisible until hovered; the hover invites the double-click that creates the story.
 * The hint text stays in CSS (like the band itself it is screen-only chrome), and the
 * document canvas stays Word-faithful because nothing shows until the pointer asks. */
.docx-pages .docx-hf--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

.docx-pages .docx-hf--placeholder:hover {
  background: var(--doc-primary-light);
  border-radius: 4px;
}

.docx-pages .docx-hf--placeholder:hover::after {
  content: 'Double-click to add header';
  font-family:
    system-ui,
    -apple-system,
    sans-serif;
  font-size: 12px;
  color: var(--doc-primary);
  user-select: none;
  -webkit-user-select: none;
}

.docx-pages .docx-hf--placeholder[data-docx-hf='footer']:hover::after {
  content: 'Double-click to add footer';
}

/* Hovering an EXISTING inactive band tints it and floats an edit invitation beside it —
 * without this the enterable header answered a hover with nothing at all. The pill is a
 * sibling because the band clips its own overflow. */
.docx-pages .docx-hf:not([data-docx-hf-active]):not(.docx-hf--placeholder):hover {
  background: var(--doc-primary-light);
  border-radius: 4px;
}

.docx-pages .docx-hf-edit-hint {
  display: flex;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.1s ease;
}

.docx-pages .docx-hf:not([data-docx-hf-active]):hover + .docx-hf-edit-hint {
  opacity: 1;
}

.docx-pages .docx-hf-edit-hint::after {
  content: 'Double-click to edit header';
  font-family:
    system-ui,
    -apple-system,
    sans-serif;
  font-size: 11px;
  line-height: 1.6;
  color: var(--doc-primary);
  background: var(--doc-primary-light);
  border-radius: 10px;
  padding: 0 10px;
  margin-top: 4px;
  user-select: none;
  -webkit-user-select: none;
}

.docx-pages .docx-hf-edit-hint[data-docx-hf-hint='footer'] {
  align-items: flex-end;
}

.docx-pages .docx-hf-edit-hint[data-docx-hf-hint='footer']::after {
  content: 'Double-click to edit footer';
  margin-top: 0;
  margin-bottom: 4px;
}

/* No affordance while another furniture scope is open, in view mode, or in print. */
.docx-pages--hf-editing .docx-hf--placeholder:hover,
.docx-paginated-surface--viewing .docx-hf--placeholder:hover,
.docx-pages--hf-editing .docx-hf:not([data-docx-hf-active]):hover,
.docx-paginated-surface--viewing .docx-hf:not([data-docx-hf-active]):hover {
  background: none;
}

.docx-pages--hf-editing .docx-hf--placeholder:hover::after,
.docx-paginated-surface--viewing .docx-hf--placeholder:hover::after {
  content: none;
}

.docx-pages--hf-editing .docx-hf-edit-hint,
.docx-paginated-surface--viewing .docx-hf-edit-hint {
  display: none;
}

@media print {
  .docx-hf--placeholder,
  .docx-hf-edit-hint {
    display: none !important;
  }
}

.docx-pages--hf-editing .docx-page-content {
  opacity: var(--doc-hf-dim-opacity);
  pointer-events: none;
  transition: opacity 0.15s ease;
}

.docx-pages--hf-editing .docx-hf:not([data-docx-hf-active]) {
  opacity: var(--doc-hf-dim-opacity);
  cursor: default;
  transition: opacity 0.15s ease;
}

.docx-pages--hf-editing .docx-hf[data-docx-hf-active] {
  cursor: text;
  opacity: 1;
}

.docx-pages--hf-editing .docx-hf[data-docx-hf-active][data-docx-hf='header'] {
  border-bottom: 1px dotted var(--doc-primary);
}

.docx-pages--hf-editing .docx-hf[data-docx-hf-active][data-docx-hf='footer'] {
  border-top: 1px dotted var(--doc-primary);
}

@media print {
  .docx-pages--hf-editing .docx-page-content,
  .docx-pages--hf-editing .docx-hf {
    opacity: 1 !important;
    pointer-events: auto !important;
    border: none !important;
  }
}

/* The one highlight a native selection cannot express: a rectangle of table cells. Drawn on
   a sibling layer of the pages — never inside them, where the page painter would sweep it
   away and a keystroke could land in it. */
.docx-paginated-surface .docx-selection-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.docx-paginated-surface .docx-cell-selection-rect {
  background-color: var(--doc-cell-selection);
}

/*
 * A selection the engine keeps lit while a panel holds focus.
 *
 * The same colour the browser's own `::selection` uses, because it is standing in for exactly
 * that: the user's highlight did not change, only which element the browser thinks is
 * focused. A different colour here would read as a different KIND of selection.
 */
.docx-paginated-surface .docx-retained-selection-rect {
  background-color: var(--doc-selection);
}

/* ========================================================================
 * COMPOUND TOOLBAR (`docx-toolbar` family) — the composition API's default
 * chrome bar, the chrome spec's visual recipe:
 *
 * - bar: `flex items-center px-2 py-1 bg-muted rounded-full min-h-[36px]`
 *   — the neutral #f1f3f4-family pill.
 * - buttons: 28px ghost squares (h-7 w-7), muted
 *   glyphs, subtle hover, the dark active slab (`.ep-toolbar-toggle`
 *   [data-active] → --doc-toggle-active tokens), disabled at opacity .3.
 * - pickers (style, font family, editing mode): TRANSPARENT triggers with a
 *   chevron (h-8 rounded px-2 bg-transparent hover:bg-muted/80),
 *   not bordered boxes.
 * - font size: `− [boxed value] +` — only the VALUE is boxed
 *   (`h-7 w-10 border bg-doc-bg-input rounded-none`).
 * - dropdown card: `rounded-lg border bg-popover shadow-lg` with `p-1` viewport,
 *   items `rounded px-2 py-1.5 text-sm hover:bg-muted` with a right-edge ✓,
 *   group labels `px-2 py-1.5 text-xs font-medium text-muted-foreground`.
 *   --radius is 0.5rem, so the card radius is 8px.
 *
 * SINGLE SOURCE OF TRUTH: both adapters get these rules from this sheet;
 * adapters add no toolbar CSS of their own (`bun run check:adapter-css-thin`).
 * Colors are exclusively `--doc-*` tokens, so dark mode re-themes the bar
 * through the token overrides above — no rules are repeated per theme.
 * ======================================================================== */

.docx-toolbar {
  display: flex;
  align-items: center;
  /* NOT overflow-scroll like the chrome spec's pill: this toolbar hosts LIVE popups
   * (font menu, swatch grids) positioned absolutely inside their parts, and any
   * overflow clipping on the bar would cut them off. A bar that does not measure
   * itself wraps to a second row instead; one that does collapses groups into the
   * "⋯" menu and stays on one row (`[data-overflow]` below). */
  flex-wrap: wrap;
  flex-shrink: 0;
  gap: 2px;
  min-height: 36px;
  padding: 4px 8px;
  /* The bar fill is the spec's `bg-muted` — hsl(210 40% 96.1%),
   * a faint blue-gray, NOT the neutral #f1f3f4 hover gray. The --muted bridge var
   * is defined in this sheet for light and dark, so this tracks dark mode too. */
  background: hsl(var(--muted));
  border-radius: 9999px;
  color: var(--doc-text);
  font:
    400 13px/1 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
}

.docx-toolbar__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 28px;
  height: 28px;
  flex: none;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: transparent;
  /* Glyphs are muted at rest (`text-muted-foreground`), full on hover. */
  color: var(--doc-text-muted);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    color 0.12s ease;
}

.docx-toolbar__button:hover:not(:disabled) {
  background: var(--doc-border);
  color: var(--doc-text);
}

/* The dark active slab for toggles (B/I/U...): --doc-toggle-active-*. */
.docx-toolbar__button[data-active],
.docx-toolbar__button[data-active]:hover {
  background: var(--doc-toggle-active-bg);
  color: var(--doc-toggle-active-fg);
}

.docx-toolbar__button:disabled {
  opacity: 0.3;
  cursor: default;
}

/* ── Overflow ("⋯") ────────────────────────────────────────────────────────────────
 *
 * The bar that measures itself is ONE ROW: groups that do not fit move into the menu
 * rather than wrapping. The adapter sets `data-overflow` only while it is actually
 * measuring, so a hand-composed bar (or `overflow={false}`) keeps the wrapping above
 * and nothing about it changes. */
.docx-toolbar[data-overflow] {
  flex-wrap: nowrap;
}

/* The collapse unit: one registry group. Rendered even when nothing overflows, so the
 * measured width of a group is the width it will have when it comes back. */
.docx-toolbar__group {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: 2px;
}

/* The trigger sits at the row's end, whatever is in front of it. */
.docx-toolbar__more {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: none;
  margin-inline-start: auto;
}

/* The panel SCROLLS when it is taller than the room under the bar. That does clip a
 * popup opened from a control inside it (a font list, a swatch grid) — the same
 * trade every scrolling menu makes — and the alternative, a panel that runs off the
 * bottom of a short window, loses the rows entirely. */
.docx-toolbar__more-panel {
  position: absolute;
  top: calc(100% + 6px);
  inset-inline-end: 0;
  z-index: 60;
  box-sizing: border-box;
  inline-size: min(340px, calc(100vw - 16px));
  min-inline-size: min(260px, calc(100vw - 16px));
  max-inline-size: min(340px, calc(100vw - 16px));
  max-height: min(72vh, 560px);
  overflow-y: auto;
  padding: 6px;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  box-shadow: var(--doc-shadow-lg);
}

.docx-toolbar__more-section + .docx-toolbar__more-section {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--doc-border-light);
}

.docx-toolbar__more-heading {
  display: block;
  padding: 6px 10px 2px;
  font-size: 11px;
  font-weight: 600;
  color: var(--doc-text-muted);
  user-select: none;
}

/* A control row: the registry's name on the left, the real control on the right. */
.docx-toolbar__more-control {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 32px;
  padding: 2px 6px 2px 10px;
}

.docx-toolbar__more-control-label {
  flex: 1 1 auto;
  overflow: hidden;
  font-size: 13px;
  line-height: 18px;
  color: var(--doc-text);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.docx-toolbar__more-control-body {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: 2px;
}

/* One command row in the overflow dialog: ordinary button, shared chrome vocabulary. */
.docx-toolbar__more-command {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 32px;
  padding: 4px 10px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  cursor: pointer;
  font: inherit;
  text-align: start;
}

.docx-toolbar__more-command:hover:not(:disabled) {
  background: var(--doc-border);
}

.docx-toolbar__more-command[data-active],
.docx-toolbar__more-command[data-active]:hover {
  background: var(--doc-toggle-active-bg);
  color: var(--doc-toggle-active-fg);
}

.docx-toolbar__more-command:disabled {
  opacity: 0.3;
  cursor: default;
}

.docx-toolbar__more-command-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: var(--doc-text-muted);
}

.docx-toolbar__more-command-label {
  flex: 1 1 auto;
  overflow: hidden;
  font-size: 13px;
  line-height: 18px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Separator: `w-px h-6 bg-border mx-1.5`. */
.docx-toolbar__separator {
  width: 1px;
  height: 24px;
  flex: none;
  margin: 0 6px;
  background: var(--doc-border);
}

/* Picker (style picker, editing mode, line spacing): the spec's TRANSPARENT
 * trigger — value (and/or glyph) plus a small chevron, hover-filled, no border.
 * Parity-only pickers are aria-disabled <span>s — there is no action. */
.docx-toolbar__picker {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 32px;
  padding: 0 8px;
  flex: none;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  white-space: nowrap;
  user-select: none;
}

.docx-toolbar__picker[aria-disabled='true'] {
  opacity: 0.5;
}

.docx-toolbar__picker-caret {
  font-size: 10px;
  color: var(--doc-text-muted);
}

/* The font-family compound: the trigger is the transparent picker trigger
 * ("Arial ∨"); the popup is the shared dropdown card. */
.docx-toolbar__font-family,
.docx-toolbar__style {
  flex: none;
}

/* The STYLE trigger is fixed width, not content width: the label changes with every
 * caret move ("Normal" -> "Heading 1" -> "List Paragraph"), and a box that resizes with it
 * shunts the whole toolbar sideways as the user clicks around the document. Word and Docs
 * both hold this box at a constant width and ellipsise. */
.docx-toolbar__style-trigger {
  width: 132px;
  flex: none;
}

/* The truncating label needs a line box TALLER than the glyphs.
 *
 * The toolbar sets `13px/1`, so an `overflow: hidden` box inherits a line box exactly as
 * tall as the font size — and a descender sits below that, so "Heading 1" lost the tail of
 * its g. The trigger is a 32px flex row centring this span, so the extra leading costs no
 * layout; it just stops the clip. Same reason on the font-family trigger, where it went
 * unnoticed only because "Arial" and "Calibri" have no descenders. */
.docx-toolbar__style-trigger > span:first-child,
.docx-toolbar__font-family-trigger > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.4;
}

.docx-toolbar__font-family-trigger,
.docx-toolbar__style-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  height: 32px;
  min-width: 64px;
  max-width: 180px;
  padding: 0 8px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font: inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.docx-toolbar__font-family-trigger::after,
.docx-toolbar__style-trigger::after {
  content: '▾';
  font-size: 10px;
  color: var(--doc-text-muted);
}

.docx-toolbar__font-family-trigger:hover:not(:disabled),
.docx-toolbar__style-trigger:hover:not(:disabled) {
  background: var(--doc-border);
}

.docx-toolbar__font-family-trigger:disabled,
.docx-toolbar__style-trigger:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ── The shared dropdown card: white surface
 * card, 8px radius, soft layered shadow, a 4px inner viewport, small gray
 * semibold group headings, roomy hover rows, and the ✓ on the selected row's
 * right edge — selection is the checkmark, never a heavy background slab. */
.docx-toolbar__menu {
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  box-shadow: var(--doc-shadow-lg);
  padding: 4px;
  color: var(--doc-text);
}

.docx-toolbar__menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-width: 112px;
  text-align: left;
  padding: 7px 10px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font-size: 13px;
  line-height: 18px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.1s ease;
}

.docx-toolbar__menu-item:hover:not(:disabled) {
  background: var(--doc-bg-hover);
}

.docx-toolbar__menu-item:disabled,
/* Menu rows carry `aria-disabled` rather than the native attribute, so they stay focusable
 * and their reason stays announceable. The look must not depend on `:disabled`. */
.docx-toolbar__menu-item[aria-disabled='true'] {
  opacity: 0.5;
  cursor: default;
}

.ep-root .docx-menubar__item[aria-disabled='true']:hover {
  background: transparent;
}

/* Group heading: small gray semibold. */
.docx-toolbar__menu-label {
  padding: 8px 10px 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--doc-text-muted);
  user-select: none;
}

.docx-toolbar__menu-separator {
  height: 1px;
  margin: 4px 0;
  background: var(--doc-border);
}

/* The selected row's ✓, pushed to the right edge. */
.docx-toolbar__menu-check {
  margin-left: auto;
  padding-left: 16px;
  font-size: 12px;
  color: var(--doc-text);
}

.docx-toolbar__font-family-content,
.docx-toolbar__style-content {
  margin-top: 4px;
}

.docx-toolbar__font-family-item,
.docx-toolbar__style-item {
  display: flex;
  align-items: center;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font-size: 13px;
  line-height: 18px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.1s ease;
}

/* The current font gets the right-edge ✓ only — no filled slab; hover stays
 * the ordinary subtle wash. */
.docx-toolbar__font-family-item:hover,
.docx-toolbar__style-item:hover {
  background: var(--doc-bg-hover);
}

/* Steppers (font size, zoom): ghost − / + around the middle; no outer border.
 * Only the font-size value is boxed; zoom's middle is a "%" + caret button. */
.docx-toolbar__stepper {
  display: inline-flex;
  align-items: center;
  height: 28px;
  flex: none;
}

.docx-toolbar__stepper-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text-muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.docx-toolbar__stepper-button:hover:not(:disabled) {
  background: var(--doc-border);
  color: var(--doc-text);
}

.docx-toolbar__stepper-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.docx-toolbar__stepper-value {
  min-width: 34px;
  text-align: center;
  color: var(--doc-text);
  font-variant-numeric: tabular-nums;
  user-select: none;
}

/* The boxed font-size value: `h-7 w-10 border bg-doc-bg-input rounded-none`. */
.docx-toolbar__stepper-value--boxed {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  min-width: 40px;
  height: 28px;
  border: 1px solid var(--doc-border);
  border-radius: 0;
  background: var(--doc-surface);
  font-size: 13px;
}

/* The font-size box is a COMBOBOX: typed as readily as picked, so it is an input
 * wearing the boxed value's chrome rather than a readout. */
.docx-toolbar__font-size {
  position: relative;
  display: inline-flex;
  flex: none;
}

.docx-toolbar__font-size-input {
  padding: 0;
  font: inherit;
  font-size: 13px;
  cursor: text;
}

.docx-toolbar__font-size-input:focus {
  outline: 2px solid var(--doc-accent);
  outline-offset: -2px;
}

.docx-toolbar__font-size-input:disabled {
  opacity: 0.5;
  cursor: default;
}

.docx-toolbar__font-size-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  min-width: 72px;
  max-height: 280px;
  overflow-y: auto;
}

.docx-toolbar__font-size-menu .docx-toolbar__menu-item {
  min-width: 64px;
  justify-content: flex-start;
  font-variant-numeric: tabular-nums;
}

/* Line spacing: an icon button with a caret, opening Word's combined menu (the
 * multiples, then the paragraph space-before/after rows). */
.docx-toolbar__line-spacing {
  position: relative;
  display: inline-flex;
  flex: none;
}

.docx-toolbar__line-spacing-trigger {
  gap: 2px;
  width: auto;
  padding: 0 4px;
}

.docx-toolbar__line-spacing-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  min-width: 232px;
}

/* The zoom middle: transparent "%" trigger with a caret. */
.docx-toolbar__stepper-value--menu {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-width: 52px;
  height: 28px;
  padding: 0 4px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font-size: 12px;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.docx-toolbar__stepper-value--menu:hover:not(:disabled) {
  background: var(--doc-border);
}

.docx-toolbar__zoom {
  position: relative;
  display: inline-flex;
  flex: none;
}

.docx-toolbar__zoom-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  min-width: 96px;
}

/* The merged alignment dropdown: current-alignment icon + caret; the popup is
 * the four-in-a-row panel with the active option highlighted. */
.docx-toolbar__alignment {
  position: relative;
  display: inline-flex;
  flex: none;
}

.docx-toolbar__alignment-trigger {
  width: auto;
  padding: 0 3px 0 5px;
  gap: 1px;
}

.docx-toolbar__alignment-popup {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  display: flex;
  gap: 2px;
  padding: 6px;
}

.docx-toolbar__alignment-option {
  width: 32px;
  height: 32px;
  color: var(--doc-text);
}

/* Panel active state: primary tint, NOT the bar's dark slab. */
.docx-toolbar__alignment-option[data-active],
.docx-toolbar__alignment-option[data-active]:hover {
  background: var(--doc-primary-light);
  color: var(--doc-primary);
}

/* Split colour controls (font colour, highlight): the two-half button —
 * a 28px main half stacking the glyph over a 16×4 colour bar, and an 18px
 * chevron half; a 2px gap sells "two buttons" without a divider line. */
.docx-toolbar__colorsplit {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: none;
}

.docx-toolbar__colorsplit-main {
  flex-direction: column;
  gap: 0;
}

.docx-toolbar__colorsplit-bar {
  width: 16px;
  height: 4px;
  margin-top: -2px;
  border-radius: 1px;
  pointer-events: none;
}

.docx-toolbar__colorsplit-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text-muted);
  font-size: 10px;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.docx-toolbar__colorsplit-caret:hover:not(:disabled) {
  background: var(--doc-border);
}

.docx-toolbar__colorsplit-caret:disabled {
  opacity: 0.3;
  cursor: default;
}

/* Word's picker: the clear row (Automatic / No Color), the theme matrix, the
 * standard row and the custom hex field, stacked in one panel. */
.docx-toolbar__swatch-popup {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  box-shadow: var(--doc-shadow-lg);
}

.docx-toolbar__swatch-section {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.docx-toolbar__swatch-heading {
  font-size: 11px;
  color: var(--doc-text-muted);
  user-select: none;
  white-space: nowrap;
}

.docx-toolbar__swatch-grid {
  display: grid;
  grid-template-columns: repeat(10, 18px);
  gap: 3px;
}

/* Base row breathes before the tint/shade block, the way Word separates them. */
.docx-toolbar__swatch-grid--theme > .docx-toolbar__swatch:nth-child(10) {
  margin-bottom: 3px;
}

/* Word's highlighter is five colours per row. */
.docx-toolbar__swatch-grid--highlight {
  grid-template-columns: repeat(5, 18px);
}

.docx-toolbar__swatch-clear {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}

.docx-toolbar__swatch-clear:hover {
  background: var(--doc-border);
}

.docx-toolbar__swatch-clear-chip {
  width: 14px;
  height: 14px;
  border: 1px solid var(--doc-border-dark);
  border-radius: 2px;
  background: #000000;
}

/* No Color: a white chip with the red slash. */
.docx-toolbar__swatch-clear-chip--none {
  background:
    linear-gradient(
      to top right,
      transparent calc(50% - 1px),
      #d83b01 calc(50% - 1px),
      #d83b01 calc(50% + 1px),
      transparent calc(50% + 1px)
    ),
    #ffffff;
}

.docx-toolbar__swatch {
  width: 18px;
  height: 18px;
  padding: 0;
  border: none;
  border-radius: 2px;
  cursor: pointer;
  transition:
    transform 0.1s,
    box-shadow 0.1s;
}

.docx-toolbar__swatch[data-light] {
  box-shadow: inset 0 0 0 1px var(--doc-border-dark);
}

.docx-toolbar__swatch:hover {
  transform: scale(1.15);
  box-shadow: inset 0 0 0 1px var(--doc-text);
}

.docx-toolbar__swatch[data-selected] {
  outline: 2px solid var(--doc-accent);
  outline-offset: 1px;
}

.docx-toolbar__swatch-custom {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.docx-toolbar__swatch-hash {
  color: var(--doc-text-muted);
  font-size: 12px;
  user-select: none;
}

.docx-toolbar__swatch-hex {
  width: 72px;
  height: 24px;
  padding: 0 6px;
  border: 1px solid var(--doc-border-dark);
  border-radius: 4px;
  background: var(--doc-surface);
  color: var(--doc-text);
  font-size: 12px;
  font-family: inherit;
}

.docx-toolbar__swatch-apply {
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--doc-border-dark);
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font-size: 12px;
  cursor: pointer;
}

.docx-toolbar__swatch-apply:hover:not(:disabled) {
  background: var(--doc-border);
}

.docx-toolbar__swatch-apply:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ── Scoped story chrome ──────────────────────────────────────────────────────────────
 * A quiet label rail follows the active header/footer/note story. React keeps it outside
 * the engine-painted subtree, while useScopedChromeAnchor places it at the story boundary. */
.docx-context-bar {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 24px;
  box-sizing: border-box;
  padding: 0 2px 5px;
  color: var(--doc-primary);
  background: var(--doc-page-bg-rendered);
  border: 0;
  border-bottom: 1px dashed var(--doc-primary);
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
}

.docx-context-bar__label {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
}

.docx-context-bar__title {
  min-width: 0;
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
}

.docx-context-bar__status {
  max-width: 150px;
  overflow: hidden;
  color: var(--doc-text-muted);
  font-size: 11px;
  font-weight: 400;
  text-overflow: ellipsis;
}

.docx-context-bar__options-trigger {
  padding: 2px 0 2px 8px;
  font: inherit;
  font-weight: 500;
  color: var(--doc-primary);
  background: transparent;
  border: 0;
  cursor: pointer;
}

.docx-context-bar__options-trigger::after {
  content: ' ▾';
  font-size: 9px;
}

.docx-context-bar__options-trigger:hover {
  text-decoration: underline;
}

.docx-context-bar__options-trigger:focus-visible {
  outline: 2px solid var(--doc-focus-ring);
  outline-offset: 2px;
}

.docx-hf-chrome__options {
  position: relative;
  pointer-events: auto;
}

.docx-hf-chrome__options-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 260px;
  padding: 6px 0;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 6px;
  box-shadow: 0 4px 16px var(--doc-shadow);
  z-index: var(--doc-z-dropdown, 100);
}

.docx-hf-chrome__menu-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--doc-text);
  cursor: pointer;
}

.docx-hf-chrome__menu-row--distance {
  align-items: center;
}

.docx-hf-chrome__menu-row input[type='checkbox'] {
  margin-top: 2px;
  flex: none;
}

.docx-hf-chrome__menu-row input[type='number'] {
  width: 64px;
  padding: 4px 6px;
  font-size: 13px;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-surface);
  color: var(--doc-text);
}

.docx-hf-chrome__menu-hint {
  display: block;
  font-size: 11px;
  color: var(--doc-text-subtle);
}

.docx-hf-chrome__menu-item {
  display: block;
  width: 100%;
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--doc-text);
  background: transparent;
  border: none;
  cursor: pointer;
}

.docx-hf-chrome__menu-item:hover:not(:disabled) {
  background: var(--doc-bg-hover);
}

.docx-hf-chrome__menu-item:disabled {
  opacity: 0.5;
  cursor: default;
}

.docx-hf-chrome__menu-separator {
  height: 1px;
  margin: 4px 0;
  background: var(--doc-border);
}

.docx-hf-chrome__unit {
  font-size: 11px;
  color: var(--doc-text-muted);
}

.docx-note-properties {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  padding: 20px;
  background: var(--doc-overlay);
}

.docx-note-properties__panel {
  width: min(620px, 100%);
  max-height: calc(100vh - 40px);
  overflow: auto;
  color: var(--doc-text);
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 10px;
  box-shadow: 0 12px 36px var(--doc-shadow-strong);
}

.docx-note-properties__title {
  margin: 0;
  padding: 18px 20px 14px;
  font-size: 16px;
  font-weight: 600;
  border-bottom: 1px solid var(--doc-border);
}

.docx-note-properties__body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 18px 20px;
}

.docx-note-properties__scope {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  font-size: 13px;
  font-weight: 500;
}

.docx-note-properties__section {
  min-width: 0;
  margin: 0;
  padding: 14px 16px 16px;
  background: var(--doc-bg-subtle);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
}

.docx-note-properties__legend {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 5px;
  font-size: 13px;
  font-weight: 600;
}

.docx-note-properties__badge {
  padding: 2px 7px;
  font-size: 10px;
  font-weight: 500;
  color: var(--doc-text-muted);
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 9999px;
}

.docx-note-properties__fields {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.docx-note-properties__field {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  color: var(--doc-text-muted);
}

.docx-note-properties__select {
  width: 100%;
  min-height: 34px;
  box-sizing: border-box;
  padding: 6px 30px 6px 9px;
  font: inherit;
  font-size: 13px;
  color: var(--doc-text);
  background: var(--doc-surface);
  border: 1px solid var(--doc-border-input);
  border-radius: 5px;
}

.docx-note-properties__select:focus-visible {
  border-color: var(--doc-primary);
  outline: 2px solid var(--doc-focus-ring);
  outline-offset: 1px;
}

.docx-note-properties__footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--doc-border);
}

.docx-note-properties__button {
  min-height: 32px;
  padding: 6px 14px;
  font: inherit;
  font-size: 13px;
  color: var(--doc-text);
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 5px;
  cursor: pointer;
}

.docx-note-properties__button:hover {
  background: var(--doc-bg-hover);
}

.docx-note-properties__button--primary {
  color: var(--doc-on-primary);
  background: var(--doc-primary);
  border-color: var(--doc-primary);
}

.docx-note-properties__button--primary:hover {
  background: var(--doc-primary-hover);
  border-color: var(--doc-primary-hover);
}

@media (max-width: 640px) {
  .docx-context-bar__status {
    display: none;
  }

  .docx-context-bar {
    max-width: calc(100vw - 16px) !important;
  }

  .docx-note-properties {
    padding: 12px;
  }

  .docx-note-properties__panel {
    max-height: calc(100vh - 24px);
  }

  .docx-note-properties__scope,
  .docx-note-properties__fields {
    grid-template-columns: 1fr;
  }
}

@media print {
  .docx-context-bar {
    display: none !important;
  }
}

/* ── Vue registry-toolbar (`ep-toolbar` family) additions for the same shapes:
 * the parity stepper lookalike and the merged alignment dropdown. */
.ep-toolbar__stepper {
  display: inline-flex;
  align-items: center;
  height: 28px;
  flex: none;
}

.ep-toolbar__stepper[aria-disabled='true'] {
  opacity: 0.5;
}

.ep-toolbar__stepper-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 28px;
  color: var(--doc-text-muted);
  font-size: 14px;
  user-select: none;
}

.ep-toolbar__stepper-value {
  min-width: 34px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

.ep-toolbar__alignment {
  position: relative;
  display: inline-flex;
}

.ep-toolbar__alignment-popup {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  display: flex;
  gap: 2px;
  padding: 6px;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  box-shadow: var(--doc-shadow-lg);
}

/* ---------------------------------------------------------------------------
   Loading surface (`DocxEditor.Loading`)
   --------------------------------------------------------------------------- */

/* Fills whatever box the host places it in, so the same declaration works as a
   full-page screen and as an in-viewport overlay. */
.docx-editor__loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  width: 100%;
  height: 100%;
  min-height: 0;
  color: var(--doc-text-muted);
  font-size: 14px;
}

/* The default screen when the host supplies no children.
   `display` and `box-sizing` are explicit rather than inherited from Tailwind's
   preflight: the part emits its own `ep-root`, so it can be composed somewhere the
   preflight does not reach, and an inline span would otherwise measure 42px and only
   size at all by accident of being a flex item. */
.docx-editor__loading-spinner {
  display: block;
  box-sizing: border-box;
  width: 36px;
  height: 36px;
  border: 3px solid var(--doc-border);
  border-top-color: var(--doc-primary);
  border-radius: 50%;
  animation: docx-editor-loading-spin 0.8s linear infinite;
}

@keyframes docx-editor-loading-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Respect a reduced-motion preference: keep the indicator, drop the rotation. */
@media (prefers-reduced-motion: reduce) {
  .docx-editor__loading-spinner {
    animation: none;
  }
}

/* ─── Hyperlink popover (DocxEditor.HyperLink) ────────────────────────────────────────
 *
 * The Google-Docs arrangement: a small panel under the clicked link, showing the target
 * and the actions on it. CHROME, not document — so it is themed from the `--doc-*` tokens
 * like the toolbar, unlike the painted page it sits over.
 *
 * z-index lives here rather than as an inline constant in the component, so a host that
 * stacks its own chrome over the editor can re-layer the popover in CSS alone.
 */
.docx-hyperlink-popup {
  position: absolute;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 4px;
  max-width: 420px;
  padding: 6px 8px;
  border: 1px solid var(--doc-border);
  border-radius: 8px;
  background: var(--doc-surface);
  color: var(--doc-text);
  box-shadow: 0 2px 10px var(--doc-shadow);
  font-size: 13px;
  /* Offset from the clicked line so the panel sits UNDER it rather than over the words. */
  margin-top: 4px;
}

.docx-hyperlink-popup[data-mode='editing'] {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  min-width: 280px;
}

/* The target readout. Truncates rather than wrapping: a long URL must not make the panel
 * taller than the line it is describing. */
.docx-hyperlink-popup__url {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 260px;
  overflow: hidden;
  padding: 2px 4px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-link);
  font: inherit;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.docx-hyperlink-popup__url:hover:not([data-inert]) {
  text-decoration: underline;
}

/* An inert target — a refused scheme, a dangling relationship — reads as text, not as a
 * control: there is nothing behind it to press. */
.docx-hyperlink-popup__url[data-inert] {
  color: var(--doc-text-muted);
  cursor: default;
}

.docx-hyperlink-popup__actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
}

.docx-hyperlink-popup__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text-muted);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    color 0.12s ease;
}

.docx-hyperlink-popup__action:hover {
  background: var(--doc-border);
  color: var(--doc-text);
}

.docx-hyperlink-popup__action[data-copied] {
  color: var(--doc-text);
}

.docx-hyperlink-popup__fields {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.docx-hyperlink-popup__input {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-bg-input);
  color: var(--doc-text);
  font: inherit;
}

.docx-hyperlink-popup__input:focus-visible {
  outline: 2px solid var(--doc-focus-ring);
  outline-offset: -1px;
}

.docx-hyperlink-popup__apply,
.docx-hyperlink-popup__cancel {
  padding: 4px 10px;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-bg-input);
  color: var(--doc-text);
  font: inherit;
  cursor: pointer;
}

.docx-hyperlink-popup__apply:disabled {
  opacity: 0.5;
  cursor: default;
}

.docx-hyperlink-popup[data-mode='editing'] .docx-hyperlink-popup__actions {
  justify-content: flex-end;
  gap: 6px;
}

/* Why the last Apply was refused. A panel that stays open saying nothing is worse than
 * either closing or explaining. */
.docx-hyperlink-popup__error {
  color: var(--doc-error);
  font-size: 12px;
  line-height: 1.35;
}

/* Room for the review pane. The page centres inside the scroller's padding box, so
 * reserving the rail's width here shifts the sheet left by half of it and the document and
 * its cards read as one centred pair. Closed, only the marker strip is reserved. */
.docx-editor__scroll-container[data-review-pane='open'] {
  padding-right: 316px;
}

.docx-editor__scroll-container[data-review-pane='closed'] {
  padding-right: 44px;
}

/* The review rail (`DocxEditor.Review` / the Vue equivalent): one card per pending decision,
 * anchored beside the text it is about.
 *
 * Geometry only here. Where a card SITS comes from layout records through the adapter, not
 * from CSS and never from measuring painted DOM — that is a repaint behind the document and
 * fails outright while pagination is in flight. These rules supply appearance and the rail's
 * own position; the inline `top` on each slot is the anchor. */
.docx-review {
  position: absolute;
  top: 0;
  right: 0;
  width: 300px;
  pointer-events: none;
  z-index: 3;
}

/* Closed, the rail is a strip of markers: it keeps every anchor and gives up the width. */
.docx-review:not([data-open]) {
  width: 32px;
}

/* The "comment on this" button. Pulled OUT of the card column, onto the page's own edge:
   the column is where comments live, and a button standing in it lands on whichever card
   already annotates the text being re-selected. On the edge there is nothing to collide
   with, and the affordance still reads as belonging to the selection it sits beside. */
.docx-review__add {
  /* Straddling the sheet's right edge — one rail gutter back, plus HALF the button's width.
     Centred on the edge it belongs to both sides: attached to the text it will comment on,
     and clear of the column where the cards live. */
  margin-left: calc(-16px - 17px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--doc-border, #e3e5e8);
  border-radius: 8px;
  background: var(--doc-surface, #fff);
  box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
  color: var(--doc-primary, #1a73e8);
  cursor: pointer;
  pointer-events: auto;
}

/* The hover fill must be OPAQUE. `--doc-surface-hover` is a translucent wash, which is right
   for a control sitting on a flat surface and wrong for this one: it straddles the sheet's
   edge, so a see-through fill showed white paper through its left half and grey canvas
   through its right, split down the middle. Mixed into the surface colour it stays one
   solid shape wherever it sits. */
.docx-review__add:hover {
  background: color-mix(in srgb, var(--doc-primary, #1a73e8) 8%, var(--doc-surface, #fff));
  border-color: color-mix(in srgb, var(--doc-primary, #1a73e8) 35%, var(--doc-border, #e3e5e8));
  box-shadow: 0 2px 6px rgb(0 0 0 / 14%);
}

/* A card being composed reads as unfinished until it is committed. */
.docx-review__card[data-draft] {
  border-color: var(--doc-primary, #1a73e8);
}

/* The Word-style decision balloon: clicking a format or structural change in the page
   raises its card beside the text. The wrapper is a zero-size positioning origin only —
   the balloon positions in rail coordinates, so it scrolls with the text it annotates. */
.docx-review__balloon-root {
  position: absolute;
  top: 0;
  left: 0;
}

.docx-review__balloon {
  position: absolute;
  width: 280px;
  pointer-events: auto;
  z-index: 6;
}

/* Raised harder than a rail card: it floats OVER the sheet, not beside it. */
.docx-review__balloon .docx-review__card {
  margin: 0;
  box-shadow: 0 6px 20px rgb(0 0 0 / 18%);
}

/* Same rule as the list, for the same reason: markers carry anchors too. */
.docx-review__markers {
  position: absolute;
  inset: 0;
}

.docx-review__marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--doc-text-muted, #8a8f98);
  cursor: pointer;
  pointer-events: auto;
}

/* ============================================================================
 * DOCUMENT NAVIGATION PANE  (`DocxEditor.Navigation`)
 *
 * A pane that FLOATS over the document's left gutter rather than docking beside
 * it. On any reasonably wide window the gutter is already empty — a Letter page
 * in a 1600px viewport leaves ~500px on each side — so opening the pane must
 * move nothing. The adapter measures the gutter and publishes the only case that
 * needs a shift (a window too narrow to hold both) as `--docx-nav-shift` on the
 * scroll container; the rule below is the one place that consumes it.
 *
 * Everything here is chrome, so it is token-driven and dark-mode-aware. The
 * document canvas underneath stays Word-faithful and untouched.
 * ========================================================================= */

/* The page column moves ONLY by what the adapter computed, and only while a pane
 * is open. Absent (no pane mounted, pane closed, gutter wide enough) the custom
 * property falls back to 0 and this rule is inert. */
.ep-root .docx-editor__scroll-container {
  padding-inline-start: var(--docx-nav-shift, 0px);
  transition: padding-inline-start 0.2s ease;
}

/* Positioning frame: the gutter strip to the left of the page. `pointer-events`
 * is off on the frame and back on for its controls, so the strip never eats a
 * click meant for the document behind it. */
.ep-root .docx-nav {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--docx-nav-reservation, 328px);
  z-index: 40;
  pointer-events: none;
  font-size: 13px;
  color: var(--doc-text);
}

.ep-root .docx-nav > * {
  pointer-events: auto;
}

/* Collapsed: the panel stays MOUNTED (a typed query and a scrolled list survive a
 * close/reopen) and is taken out of layout with `display: none` — React state
 * lives on either way. `inert` on the element keeps it out of the tab order.
 *
 * DELIBERATELY NOT ANIMATED. Growing the width from zero clips the panel's
 * contents, so every heading appears to unwrap from the left edge while the
 * text reflows inside the shrinking box. The pane is a tool you open to look
 * something up; it should be there when you ask for it. */
.ep-root .docx-nav__panel-shell {
  display: none;
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--docx-nav-inset, 32px);
  width: var(--docx-nav-width, 280px);
  flex-direction: column;
  background: var(--doc-bg);
}

.ep-root .docx-nav--open .docx-nav__panel-shell {
  display: flex;
}

/* The collapsed disc. Aligned with the page's top edge, not the viewport's, so it
 * sits where the panel's back arrow will appear, and inset past the vertical
 * ruler's 20px tick column so it never covers the ticks. */
.ep-root .docx-nav__toggle {
  position: absolute;
  inset-block-start: 24px;
  inset-inline-start: var(--docx-nav-inset, 32px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--doc-border-light);
  background: var(--doc-bg-hover);
  color: var(--doc-text-muted);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    color 0.12s ease,
    box-shadow 0.12s ease;
}

.ep-root .docx-nav__toggle:hover {
  background: var(--doc-border);
  color: var(--doc-text);
  box-shadow: 0 1px 3px var(--doc-shadow);
}

.ep-root .docx-nav__toggle:focus-visible,
.ep-root .docx-nav__close:focus-visible,
.ep-root .docx-nav__tab:focus-visible,
.ep-root .docx-nav__stepper:focus-visible,
.ep-root .docx-nav__heading:focus-visible,
.ep-root .docx-nav__result:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: 2px;
}

/* ── Header ───────────────────────────────────────────────────────────────── */

.ep-root .docx-nav__header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 20px 12px 8px 0;
  flex: none;
}

.ep-root .docx-nav__close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-root .docx-nav__close:hover {
  background: var(--doc-bg-hover);
  color: var(--doc-text);
}

.ep-root .docx-nav__title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--doc-text);
}

/* ── Tabs ─────────────────────────────────────────────────────────────────── */

.ep-root .docx-nav__tabs {
  display: flex;
  align-items: stretch;
  gap: 4px;
  padding-inline: 4px;
  margin-block-end: 10px;
  border-block-end: 1px solid var(--doc-border-light);
  flex: none;
}

.ep-root .docx-nav__tab {
  appearance: none;
  border: none;
  background: none;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--doc-text-muted);
  cursor: pointer;
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
}

.ep-root .docx-nav__tab:hover {
  color: var(--doc-text);
}

.ep-root .docx-nav__tab--selected {
  color: var(--doc-primary);
  border-block-end-color: var(--doc-primary);
  font-weight: 600;
}

/* ── Panels ───────────────────────────────────────────────────────────────── */

.ep-root .docx-nav__panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
  padding-inline: 4px;
  gap: 8px;
}

.ep-root .docx-nav__panel[hidden] {
  display: none;
}

.ep-root .docx-nav__empty {
  margin: 0;
  padding: 8px;
  color: var(--doc-text-subtle);
  font-size: 13px;
  line-height: 1.45;
}

.ep-root .docx-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  min-height: 0;
  flex: 1;
}

/* ── Search box ───────────────────────────────────────────────────────────── */

.ep-root .docx-nav__searchbox {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  padding: 5px 8px;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-bg-input);
}

.ep-root .docx-nav__searchbox:focus-within {
  border-color: var(--doc-primary);
  box-shadow: 0 0 0 1px var(--doc-primary);
}

.ep-root .docx-nav__search-icon {
  color: var(--doc-text-muted);
  flex: none;
}

.ep-root .docx-nav__search-input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: none;
  font: inherit;
  font-size: 13px;
  color: var(--doc-text);
}

.ep-root .docx-nav__search-input::placeholder {
  color: var(--doc-text-placeholder);
}

/* The UA's own clear affordance would sit next to ours. */
.ep-root .docx-nav__search-input::-webkit-search-cancel-button {
  appearance: none;
}

.ep-root .docx-nav__search-clear {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-root .docx-nav__search-clear:hover {
  background: var(--doc-bg-hover);
  color: var(--doc-text);
}

/* ── Find: options, counter, results ──────────────────────────────────────── */

.ep-root .docx-nav__options {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  flex: none;
  padding-inline: 2px;
}

.ep-root .docx-nav__option {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-root .docx-nav__resultbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex: none;
  min-height: 28px;
  padding-inline: 2px;
}

.ep-root .docx-nav__count {
  font-size: 13px;
  font-weight: 600;
  color: var(--doc-text);
}

.ep-root .docx-nav__steppers {
  display: flex;
  gap: 4px;
}

.ep-root .docx-nav__stepper {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-bg-input);
  color: var(--doc-text-muted);
  cursor: pointer;
}

.docx-review__marker:hover {
  background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
  color: var(--doc-text, #1f2328);
}

/* Host furniture: flow content at the top of the rail. It needs its pointer events back (the
 * rail is transparent to the pointer), and it must not become the cards' positioning origin —
 * furniture that pushed the list down moved every card by its own height. */
.docx-review__furniture {
  position: relative;
  z-index: 1;
  pointer-events: auto;
}

/* Absolute, not relative-plus-full-height: a slot's inline `top` is its anchor in the rail's
   own coordinates, so the box it resolves against has to be the rail. */
.docx-review__list {
  position: absolute;
  inset: 0;
}

.docx-review__slot {
  width: 100%;
  pointer-events: auto;
  transition: top 120ms ease-out;
}

/* While the reader scrolls, restacks snap instead of animating. The transition exists for
   accept/reject collapses; during a scroll it animated the height-correction shifts of
   every card below a newly measured one, and the moving cards over the moving page read
   as a second scroll. The rail sets the attribute at scroll frequency without React. */
.docx-review[data-scrolling] .docx-review__slot {
  transition: none;
}

/* An INACTIVE card keeps its summary to a few lines: the rail is a queue, not the reading
   surface, and one long insertion was a full viewport of card pushing everything after it
   pages below its text. The active card renders in full. */
.docx-review__card:not([data-active]) .docx-review__summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

/* A card the stacking pass pushed too far from its own text collapses to its header —
   a full summary there reads as annotating whatever text happens to be beside it.
   Clicking still works, and the active card never collapses. */
.docx-review__slot[data-collapsed] .docx-review__summary,
.docx-review__slot[data-collapsed] .docx-review__replies,
.docx-review__slot[data-collapsed] .docx-review__reply-box {
  display: none;
}

.docx-review__card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* No bottom margin. The slot is absolutely positioned and its height IS the spacing input,
     so a margin here was a second gutter the stacking hook could not see — every card sat a
     card-margin plus a gap apart. Spacing belongs to `gap`, in one place. */
  margin: 0 12px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--doc-border, #e3e5e8);
  /* The card is CHROME, so it is themed; the document canvas beside it never is. */
  border-radius: 12px;
  background: var(--doc-surface, #fff);
  box-shadow: 0 1px 3px rgb(0 0 0 / 6%);
  color: var(--doc-text, #1f2328);
  font-size: 13px;
  line-height: 1.5;
  cursor: pointer;
  transition:
    box-shadow 120ms ease-out,
    border-color 120ms ease-out;
}

.docx-review__card:focus-visible {
  outline: 2px solid var(--doc-focus-ring, #3b82f6);
  outline-offset: 1px;
}

/* The OPEN card lifts. It is not tinted and gains no coloured edge: the band under the text
   already says which conversation is open, and repeating it here in the author's colour made
   the rail read as eight competing highlights. */
.docx-review__card[data-active] {
  box-shadow: 0 4px 14px rgb(0 0 0 / 12%);
  border-color: var(--doc-border-strong, #c8ccd2);
}

.docx-review__card[data-resolved] {
  opacity: 0.55;
}

.docx-review__head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.docx-review__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  border-radius: 50%;
  /* Softened against white: the ramp is chosen to stay legible as TEXT on the page, and the
     same values as a 30px filled disc read as eight warning lights down the margin. */
  background: color-mix(in srgb, var(--doc-review-author, #c0392b) 82%, white);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.docx-review__meta {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
}

.docx-review__author {
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.docx-review__time {
  color: var(--doc-text-muted, #8a8f98);
  font-size: 12px;
}

.docx-review__actions {
  display: flex;
  flex: 0 0 auto;
  gap: 2px;
}

.docx-review__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--doc-text-muted, #8a8f98);
  cursor: pointer;
}

.docx-review__action:hover:not(:disabled) {
  background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
  color: var(--doc-text, #1f2328);
}

.docx-review__action:disabled {
  cursor: default;
  opacity: 0.4;
}

/* The destructive one reads as destructive on hover. It sits beside accept and reject in the
   same row, and three identical grey glyphs give no warning that one of them is the only
   button in the rail that throws a reviewer's words away. */
.docx-review__action[data-testid='review-delete']:hover:not(:disabled) {
  background: var(--doc-destructive-hover-bg);
  color: var(--doc-destructive);
}

/* Delete appears on the ONE node it deletes, when the pointer is on that node.
   `visibility`, not `opacity` or `display`: hidden has to mean unclickable — an invisible
   button that still takes a click is worse than a visible one — while the space stays
   reserved, so the head row does not reflow as the pointer crosses it. */
.docx-review__action[data-testid='review-delete'] {
  visibility: hidden;
}

/* A reply reveals its OWN control. Scoped through the reply's head so a reply cannot reveal
   the control belonging to the comment it answers. */
.docx-review__reply:hover > .docx-review__head [data-testid='review-delete'],
.docx-review__reply:focus-within > .docx-review__head [data-testid='review-delete'] {
  visibility: visible;
}

/* And the card reveals its own — `>` for the card's own head, and the `:has()` guard so
   hovering a nested reply does not light up its parent's control as well. Two identical
   trash icons offered at once is how a reader deletes the wrong one. */
.docx-review__card:hover:not(:has(.docx-review__reply:hover))
  > .docx-review__head
  [data-testid='review-delete'],
.docx-review__card:focus-within:not(:has(.docx-review__reply:focus-within))
  > .docx-review__head
  [data-testid='review-delete'] {
  visibility: visible;
}

/* Keyboard reach. A control revealed only by a pointer is a control a keyboard user cannot
   operate, and this one carries an `aria-label` precisely because it is meant to be reachable. */
.docx-review__action[data-testid='review-delete']:focus-visible {
  visibility: visible;
}

.docx-review__summary {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* A deletion can be a page of text. The card summarises; the document shows it in full. */
  max-height: 7em;
  overflow: hidden;
}

.docx-review__label {
  color: var(--doc-text-muted, #8a8f98);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* In the change's own colour, the one the text already wears on the page. */
.docx-review__label[data-kind='insert'],
.docx-review__label[data-kind='moveTo'] {
  color: var(--doc-revision-insertion);
}

.docx-review__label[data-kind='delete'],
.docx-review__label[data-kind='moveFrom'] {
  color: var(--doc-revision-deletion);
}

.docx-review__text {
  overflow-wrap: anywhere;
}

/* A REVISION's quote is clamped, not scrolled: it quotes text that is already on the page the
   card points at, so pasting a paragraph should not push every card below it off the rail.
   A comment is exempt — there the text is the content and nowhere else, and truncating it
   would hide what someone wrote. */
.docx-review__card:not([data-kind='comment']) .docx-review__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}

/* Replies live INSIDE the card they answer, divided by a hairline — one conversation, one
   card. Given cards of their own they would double the rail and lose the thread. */
.docx-review__replies {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 2px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--doc-border, #e3e5e8);
  list-style: none;
}

.docx-review__reply-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}

.docx-review__input {
  min-width: 0;
  flex: 1 1 auto;
  padding: 7px 14px;
  border: 1px solid var(--doc-border, #e3e5e8);
  border-radius: 999px;
  background: var(--doc-surface, #fff);
  color: inherit;
  font: inherit;
}

.docx-review__input:focus-visible {
  outline: 2px solid var(--doc-focus-ring, #3b82f6);
  outline-offset: -1px;
}

/* A reply needs a visible way to send it. Enter posts too, but a field with no button is a
   field people fill in and then look for the button that is not there. */
.docx-review__reply-actions {
  display: flex;
  flex: 1 0 100%;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
}

.docx-review__text-button {
  padding: 6px 10px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--doc-primary, #1a73e8);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
}

.docx-review__text-button:hover {
  background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
}

.docx-review__submit {
  padding: 6px 14px;
  border: 0;
  border-radius: 999px;
  background: var(--doc-primary, #1a73e8);
  color: #fff;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
}

.docx-review__submit:disabled {
  background: var(--doc-surface-hover, rgb(0 0 0 / 8%));
  color: var(--doc-text-muted, #8a8f98);
  cursor: default;
}

.docx-review__refused {
  flex: 1 0 100%;
  color: var(--doc-danger, #b3261e);
  font-size: 11px;
}

.docx-review__empty {
  padding: 12px;
  color: var(--doc-text-muted, #8a8f98);
  font-size: 12px;
}

/* Commented text, highlighted the way Word highlights it.
 *
 * The layer sits OVER the pages and MULTIPLIES: under them the band would be hidden by the
 * opaque sheet, and a plain translucent wash on top greys the very text it is drawing
 * attention to. Multiply is what a highlighter does — the paper darkens, the glyphs do not.
 * The bands come from layout records through `keyedRangeRects`, so a comment spanning three
 * lines gets three of them and one on an unmaterialized page gets none. */
.docx-comment-overlay {
  mix-blend-mode: multiply;
}

/* Pending, not open. Held back from the open one but still plainly a highlight — this is the
   only layer a comment gets, unlike a revision, whose run the painter washes as well. The
   rule under it thins rather than disappearing; the OPEN one deepens both. */
.docx-comment-band {
  background: color-mix(in srgb, var(--doc-comment-bg) 80%, transparent);
  box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--doc-comment-border) 55%, transparent);
}

/* The one the caret is in. Word deepens the same yellow rather than switching colour, so the
   reader sees "this one" without having to learn a second meaning. */
.docx-comment-band--active {
  background: var(--doc-comment-active-bg);
  box-shadow: inset 0 -1px 0 var(--doc-comment-active-border);
}

/* Tracked changes carry a band always, in the change's OWN colour, so it never contradicts
 * the decoration it sits behind — green where text is arriving, red where it is leaving. A
 * replacement gets both, red over the struck half and green over what replaced it.
 *
 * Pending changes stay faint and the open one deepens, which is the same relationship the
 * comment bands have. Tinting only the active one made every other change look resolved. */
/* Nothing for a PENDING change: the painter already washed the run itself, everywhere in the
   document rather than only where this layer reaches. Repeating it here doubled the colour on
   whichever pages the band happened to cover, which read as some changes being darker than
   others for no reason a reader could name. */
.docx-revision-band--insert,
.docx-revision-band--delete {
  background: transparent;
}

.docx-revision-band--insert.docx-revision-band--active {
  background: var(--doc-revision-insertion-tint);
  box-shadow: inset 0 -1px 0 var(--doc-revision-insertion);
}

.docx-revision-band--delete.docx-revision-band--active {
  background: var(--doc-revision-deletion-tint);
  box-shadow: inset 0 -1px 0 var(--doc-revision-deletion);
}

/* A formatting or structural change decorates no characters of its own, so it gets the
   neutral band rather than a colour that would claim text was added or removed. Only when
   open: a faint grey wash over unchanged-looking text says nothing a reader can act on. */
.docx-revision-band--other {
  background: transparent;
}

.docx-revision-band--other.docx-revision-band--active {
  background: color-mix(in srgb, var(--doc-text-muted, #8a8f98) 14%, transparent);
}

/* Dark paper inverts the arithmetic: multiplying a tint into a dark sheet drives it to
   black, so the band disappears exactly where it is needed. Screen lightens instead, which
   is the same relationship the light theme has — the paper shifts, the glyphs do not. */
.ep-root.dark .docx-comment-overlay {
  mix-blend-mode: screen;
}

/* The editing-mode control: a pill that shows the current mode and a menu that changes it.
 * The one toolbar control whose state is a VALUE, so it renders what it shows rather than a
 * pressed flag. */
.docx-toolbar__mode {
  position: relative;
  display: inline-flex;
}

/* Right-aligned to the pill. The mode control belongs at the end of a toolbar, so a 260px
   menu hung off its left edge runs past the window and clips its own options. */
.docx-toolbar__mode-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 40;
  display: flex;
  min-width: 260px;
  flex-direction: column;
  padding: 6px;
  border: 1px solid var(--doc-border, #e3e5e8);
  border-radius: 10px;
  background: var(--doc-surface, #fff);
  box-shadow: 0 8px 24px rgb(0 0 0 / 16%);
}

.docx-toolbar__mode-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--doc-text, #1f2328);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.docx-toolbar__mode-item:hover {
  background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
}

.docx-toolbar__mode-text {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
}

.docx-toolbar__mode-label {
  font-weight: 500;
}

.docx-toolbar__mode-hint {
  color: var(--doc-text-muted, #8a8f98);
  font-size: 12px;
}

.docx-toolbar__mode-check {
  display: inline-flex;
  width: 18px;
  flex: 0 0 auto;
  color: var(--doc-accent, #1a73e8);
}

/* A replacement's two halves, in the colours the document draws them in: what goes, and
   what takes its place. */
.docx-review__removed {
  color: var(--doc-revision-deletion);
  font-weight: 500;
}

.docx-review__added {
  color: var(--doc-revision-insertion);
  font-weight: 500;
  border: 1px solid var(--doc-border-input);
  border-radius: 4px;
  background: var(--doc-bg-input);
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-root .docx-nav__stepper:hover:not(:disabled) {
  background: var(--doc-bg-hover);
  color: var(--doc-text);
}

.ep-root .docx-nav__stepper:disabled {
  opacity: 0.4;
  cursor: default;
}

.ep-root .docx-nav__result {
  display: block;
  width: 100%;
  text-align: start;
  border: 1px solid transparent;
  border-radius: 4px;
  background: none;
  padding: 7px 8px;
  font: inherit;
  font-size: 13px;
  line-height: 1.45;
  color: var(--doc-text-muted);
  cursor: pointer;
}

.ep-root .docx-nav__result:hover {
  background: var(--doc-bg-hover);
}

/* The active result reads as the one the caret is on: bordered, like Word's. */
.ep-root .docx-nav__result--active {
  border-color: var(--doc-primary);
  color: var(--doc-text);
}

.ep-root .docx-nav__result-text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ep-root .docx-nav__result-hit {
  background: none;
  color: var(--doc-text);
  font-weight: 700;
}

/* ── Headings list ────────────────────────────────────────────────────────── */

.ep-root .docx-nav__heading {
  display: block;
  width: 100%;
  text-align: start;
  border: none;
  border-radius: 4px;
  background: none;
  padding-block: 5px;
  padding-inline-end: 8px;
  font: inherit;
  font-size: 13px;
  line-height: 1.4;
  color: var(--doc-text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ep-root .docx-nav__heading:hover {
  background: var(--doc-bg-hover);
}

.ep-root .docx-nav__heading--current {
  background: var(--doc-primary-light);
  font-weight: 600;
}

/* Reduced motion: the page still moves when it has to, it just does not glide. */
@media (prefers-reduced-motion: reduce) {
  .ep-root .docx-editor__scroll-container {
    transition-duration: 0s;
  }
}

/* ── The menu bar: File · Format · Insert · Help ───────────────────────────────────────
 *
 * Sits under the document title, above the toolbar pill. Triggers are plain text — no
 * chrome at rest, a soft gray plate on hover and while open — and the panels reuse the
 * shared `.docx-toolbar__menu` card so a menu row and a toolbar dropdown row are the same
 * object. What the menu adds is the ROW GRID: a fixed icon column so labels line up down
 * the panel, and a right-hand shortcut column. */
.ep-root .docx-menubar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px;
  color: var(--doc-text);
  font:
    400 13px/1 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
}

.ep-root .docx-menubar__menu-root {
  position: relative;
}

.ep-root .docx-menubar__trigger {
  padding: 4px 8px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  font: inherit;
  line-height: 18px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

/* An OPT-IN trigger icon. The bar has none by default — Word and Docs do not — so this
 * only ever applies where a host passed one, and it inherits the trigger's colour so the
 * glyph tracks hover and open state with the label. */
.ep-root .docx-menubar__trigger-icon {
  display: inline-flex;
  align-items: center;
  margin-right: 5px;
  vertical-align: -2px;
  color: inherit;
}

.ep-root .docx-menubar__trigger:hover,
.ep-root .docx-menubar__trigger[data-open] {
  background: var(--doc-bg-hover);
}

/* The panel: the shared card, dropped below its trigger. */
.ep-root .docx-menubar__menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  margin-top: 4px;
  min-width: 220px;
}

/* The row grid: icon | label | shortcut. The icon column is reserved even on a row with
 * no glyph, so nothing shifts between rows. */
.ep-root .docx-menubar__item {
  gap: 12px;
}

.ep-root .docx-menubar__item-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--doc-text-muted);
}

.ep-root .docx-menubar__item-label {
  flex: 1;
  text-align: left;
}

.ep-root .docx-menubar__item-shortcut,
.ep-root .docx-menubar__item-caret {
  flex: none;
  margin-left: 24px;
  color: var(--doc-text-muted);
  font-size: 12px;
}

.ep-root .docx-menubar__item-caret {
  margin-left: 16px;
  font-size: 14px;
}

/* An applied toggle row (Bold on bold text) reads as the checked one. */
.ep-root .docx-menubar__item[data-active] {
  background: var(--doc-primary-light);
}

/* ── Submenus ──────────────────────────────────────────────────────────────────────── */
.ep-root .docx-menubar__submenu {
  position: relative;
}

.ep-root .docx-menubar__submenu > .docx-menubar__item[data-open] {
  background: var(--doc-bg-hover);
}

/* Opens to the RIGHT of its parent row, top-aligned with it — Word's and Docs' geometry.
 * The small negative offset pulls the panel's padding back onto the row. */
.ep-root .docx-menubar__submenu-panel {
  top: -4px;
  left: 100%;
  margin-top: 0;
  /* FLUSH against the parent panel, not offset by a gap. The panel is absolutely
   * positioned and out of flow, so the wrapper's hit box is the parent ROW only — a
   * pointer sample landing in a gap strip would hit the parent panel instead, fire the
   * wrapper's mouseleave, and close the submenu the user was moving toward. Visual
   * separation comes from the card's own border and shadow. */
  margin-left: 0;
  min-width: 240px;
}

/* A named section of rows. The heading is decoration (the group carries the accessible name),
   so it is sized to read as a label rather than as a row. */
.ep-root .docx-menubar__group-label {
  padding: 8px 12px 4px;
  color: var(--doc-text-subtle, #8a8f98);
  font-size: 10px;
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* No leading gap on the first group: the panel's own padding is already there. */
.ep-root .docx-menubar__group:first-child > .docx-menubar__group-label {
  padding-top: 2px;
}

/* ── The insert-table size grid ────────────────────────────────────────────────────── */
.ep-root .docx-menubar__grid {
  padding: 8px;
}

/* Rows are real elements now (`role="row"`), so the cells lay out per row rather than as
 * one grid container. */
.ep-root .docx-menubar__grid-cells {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ep-root .docx-menubar__grid-row {
  display: flex;
  gap: 3px;
}

.ep-root .docx-menubar__grid-cell {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--doc-border);
  border-radius: 2px;
  background: var(--doc-surface);
  cursor: pointer;
  transition:
    background-color 0.06s ease,
    border-color 0.06s ease;
}

.ep-root .docx-menubar__grid-cell[data-filled] {
  background: var(--doc-primary);
  border-color: var(--doc-primary);
}

.ep-root .docx-menubar__grid-caption {
  min-height: 18px;
  padding-top: 6px;
  text-align: center;
  font-size: 12px;
  line-height: 18px;
  color: var(--doc-text-muted);
}

/* The painted page stack's default placement: centred, with breathing room above.
 *
 * `:where()` on purpose — it matches with ZERO specificity, so any host class on
 * `DocxEditor.Content` wins without `!important` and without counting selectors. This used
 * to be an inline style on the element, which a class cannot override at all. */
:where(.docx-paginated-surface) {
  margin: 24px auto;
}

/* ── The context menu ──────────────────────────────────────────────────────────────────
 *
 * The right-click panel over the painted document. It IS the shared `.docx-toolbar__menu`
 * card holding `.docx-menubar__item` rows — the same object the menu bar drops under a
 * trigger — so a row means the same thing in both places and the disabled treatment has
 * one definition. What this block adds is only what differs: the panel is placed in client
 * space by the component rather than relative to a trigger, and it sits above the dialogs
 * and dropdowns (z-index 40) because it is opened ON them as often as on the page. */
.ep-root .docx-contextmenu,
.docx-contextmenu {
  z-index: 45;
  min-width: 240px;
  /* A menu longer than the window scrolls rather than overflowing it. The flip in
   * `DocxEditorContextMenu` clamps the panel to the top inset when it cannot fit; without
   * a max height and a scroller, the rows below the fold would be unreachable. */
  max-height: calc(100vh - 16px);
  overflow-y: auto;
}

/* The panel is `position: fixed`, so it renders OUTSIDE the `.ep-root` cascade's usual
 * geometry but still inside its subtree — the token values resolve, and this block is
 * duplicated unscoped above so a host that mounts the viewport without the wrapper class
 * still gets the card. Focus ring on the panel itself is suppressed: it takes focus only
 * to give the arrow keys a starting point, and a ring around the whole menu reads as a
 * selected row. */
.docx-contextmenu:focus {
  outline: none;
}

/* Rows inside the context menu carry the menu bar's grid without the menu bar's class
 * being present on an ancestor, so the icon and shortcut columns are restated here. */
.docx-contextmenu .docx-menubar__item {
  gap: 12px;
  width: 100%;
}

.docx-contextmenu__table-align {
  padding: 6px 12px 8px;
}

.docx-contextmenu__table-align-label {
  display: block;
  margin-bottom: 6px;
  color: var(--doc-text-muted);
  font-size: 12px;
  line-height: 16px;
}

.docx-contextmenu__table-align-buttons {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.docx-contextmenu__table-align-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--doc-border);
  border-radius: 4px;
  background: transparent;
  color: var(--doc-text);
  cursor: pointer;
}

.docx-contextmenu__table-align-button:hover:not([aria-disabled='true']) {
  background: var(--doc-bg-hover);
}

.docx-contextmenu__table-align-button[aria-disabled='true'] {
  opacity: 0.3;
  cursor: default;
}

.docx-contextmenu__table-align-button:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: 1px;
}

/* Custom-node section (pro CustomNodeContextMenu): the pointed-at node's card data,
   rendered above the packaged rows. Strings inside are file-derived — text only. */
/* Bounded and wrapping: `title` and `detail` come from a `reviewCard` hook and are commonly a
   sentence, which with no width to push back set the width of the whole menu. */
.docx-contextmenu__custom-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 280px;
  padding: 6px 12px 8px;
}

.docx-contextmenu__custom-title {
  color: var(--doc-text);
  font-size: 13px;
  font-weight: 600;
  line-height: 18px;
  overflow-wrap: anywhere;
}

.docx-contextmenu__custom-detail {
  color: var(--doc-text-muted);
  font-size: 12px;
  line-height: 16px;
  overflow-wrap: anywhere;
}

/* ── Image chrome (Task 15) ─────────────────────────────────────────────────────────── */

.docx-image-insert__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.ep-root .docx-toolbar__image-wrap,
.docx-toolbar__image-wrap {
  position: relative;
  display: inline-flex;
}

.ep-root .docx-toolbar__image-wrap-menu,
.docx-toolbar__image-wrap-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 40;
  min-width: 220px;
  padding: 4px 0;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 6px;
  box-shadow: 0 4px 16px var(--doc-shadow);
}

.ep-root .docx-toolbar__image-wrap-item,
.docx-toolbar__image-wrap-item {
  display: block;
  width: 100%;
  padding: 8px 12px;
  border: 0;
  background: transparent;
  color: var(--doc-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.ep-root .docx-toolbar__image-wrap-item[data-active],
.docx-toolbar__image-wrap-item[data-active] {
  background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
}

.ep-root .docx-toolbar__alt-text,
.docx-toolbar__alt-text {
  position: relative;
  display: inline-flex;
}

.ep-root .docx-toolbar__alt-text-panel,
.docx-toolbar__alt-text-panel {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 40;
  width: 280px;
  padding: 12px;
  background: var(--doc-surface);
  border: 1px solid var(--doc-border);
  border-radius: 6px;
  box-shadow: 0 4px 16px var(--doc-shadow);
}

/* Font compatibility notice (DocxEditor.FontNotice): Word's "substituted fonts" bar,
   shown between the toolbar and the workspace when declared faces render in fallbacks. */
.docx-font-notice {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 16px;
  background: var(--doc-warning-bg);
  color: var(--doc-warning-text);
  border-bottom: 1px solid var(--doc-border);
  font-size: 13px;
  line-height: 1.4;
}

.docx-font-notice__text {
  flex: 1;
  min-width: 0;
}

.docx-font-notice__dismiss {
  flex: none;
  height: 24px;
  padding: 0 10px;
  border: 1px solid var(--doc-warning);
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.docx-font-notice__dismiss:hover {
  background: var(--doc-bg-hover);
}

.docx-font-notice__dismiss:focus-visible {
  outline: 2px solid var(--doc-primary);
  outline-offset: 1px;
}
