/* Image gallery. Layout matches the login and customize pages: a
   dark header bar at the top with the page title, a scrollable main
   area for the image tiles, an optional status row just above the
   bottom toolbar, and a bottom toolbar with the same look/feel as the
   login page (dev action on the left, primary actions on the right). */

h1,
h2,
h3,
h4,
h5,
h6,
p,
input {
  font-family: var(--editor-font-family, Arial, Helvetica, sans-serif);
}

/* Outer page: a flex column that fills the viewport so the header
   stays pinned at the top and the gallery tiles scroll inside the
   main area. */
#image-gallery-div.image-gallery-div {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  background-color: var(--gallery-content-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  text-align: left;
  overflow: hidden;
}

/* Top header bar — same dimensions/style as .customize-header. */
.image-gallery-heading-div {
  display: flex;
  align-items: center;
  flex: none;
  padding: 0.75rem 1.5rem;
  background-color: var(--top-toolbar-background-color);
  color: var(--toolbar-text-color);
  border-bottom: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

.image-gallery-heading {
  margin: 0;
  padding: 0;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: normal;
  color: var(--header-1-color);
  background-color: transparent;
}

/* Main scrollable area: image grid lives here. */
.gallery-images-container {
  flex: 1 1 auto;
  overflow: auto;
  padding: 2.25rem 2rem 1.5rem;
}

.gallery-images-div {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.75rem;
}

/* Image tile: a rounded clickable card, same look/feel as the home
   project tile. */
.gallery-image-group-div {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 14px 12px 12px;
  border-radius: var(--corner-radius);
  border: 1px solid var(--editor-control-border-color);
  background-color: var(--gallery-tile-bg, var(--editor-input-bg, #ffffff));
  max-width: 150px;
  cursor: default;
}

.gallery-image-group-div:focus {
  outline: 2px solid var(--editor-selected-blue);
  outline-offset: -2px;
}

.gallery-image-div {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 110px;
  height: 110px;
}

.gallery-image-div img {
  display: block;
  max-width: 110px;
  max-height: 110px;
  /* Double-clicking to pick an image must register as a dblclick, not start a
     native image-drag or select the picture (which would swallow the second
     click and leave the gallery open). */
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  cursor: pointer;
}

#editing-input {
  width: 110px;
  margin: 5px 0 0;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: 0.85rem;
}

.image-name-p {
  display: block;
  width: 110px;
  margin: 6px 0 0;
  overflow: hidden;
  font-size: 0.85rem;
  text-align: center;
  text-overflow: ellipsis;
  user-select: none;
  white-space: nowrap;
  color: var(--editor-text-color);
}

/* Status row — its own section, sitting just above the bottom toolbar
   so the toolbar reads as a clean action row. */
#status {
  flex: none;
  margin: 0;
  padding: 0.5rem 1.5rem;
  background-color: transparent;
  color: var(--editor-text-color);
  font-size: 0.95rem;
  font-weight: 500;
  text-align: center;
}

/* Bottom action toolbar — same look/feel as the login page's
   `.login-button-div`: dev action on the left, spacer, primary
   actions on the right. */
.image-gallery-footer-div {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  gap: 0.75rem;
  padding: 0.75rem 1.5rem;
  background-color: transparent;
  border-top: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

.image-gallery-dev-buttons {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.image-gallery-footer-spacer {
  flex: 1 1 auto;
}

.buttons {
  min-width: auto;
  margin: 0;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background-color: var(--button-bg);
  color: var(--button-text);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}

.buttons:hover:not(:disabled) {
  background-color: var(--button-bg-hover);
}

.ok-button:disabled,
.image-gallery-footer-div .buttons:disabled {
  border-color: var(--editor-control-border-color);
  background-color: var(--editor-panel-separator-color);
  color: var(--editor-muted-text-color);
  cursor: not-allowed;
  opacity: 0.45;
}

/* Delete action in manage mode — red tint to set it apart from the
   non-destructive upload/download/rename buttons. */
.gallery-delete-button:not(:disabled) {
  border-color: rgba(220, 38, 38, 0.55);
  background-color: rgba(220, 38, 38, 0.12);
  color: #b91c1c;
}

.gallery-delete-button:not(:disabled):hover {
  background-color: rgba(220, 38, 38, 0.2);
}

/* Light-mode: main gallery area matches the editor's canvas surface;
   image tiles use the white "clickable surface" so they pop against
   the gray page. */
html[data-theme="light"] {
  --gallery-content-bg: var(--canvas-background-color);
  --gallery-tile-bg: #ffffff;
}

/* Dark-mode: gallery area uses the panel surface (same as customize
   and home); tiles use the top-toolbar surface so they read as
   elevated controls. */
html[data-theme="dark"] {
  --gallery-content-bg: var(--editor-panel-background-color);
  --gallery-tile-bg: var(--top-toolbar-background-color);
}

/* Status bar. Used on the Home, Customize, Login, Signup, Images, and
   editor pages. Sits flush with the bottom of the page; in the editor
   it pins below the canvas/panels and spans the full viewport. */

.status-bar {
  display: flex;
  align-items: center;
  flex: none;
  gap: 0.75rem;
  height: 26px;
  padding: 0 0.9rem;
  background-color: var(--status-bar-bg, var(--top-toolbar-background-color));
  color: var(--status-bar-text, var(--toolbar-text-color));
  border-top: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  user-select: none;
  box-sizing: border-box;
}

.status-bar-spacer {
  flex: 1 1 auto;
}

.status-bar-left,
.status-bar-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.status-bar-right {
  justify-content: flex-end;
  color: var(--status-bar-muted, var(--editor-muted-text-color));
}

.status-bar-error {
  color: #c0392b;
}

/* Clickable version read-out in the editor's right status bar — opens the
   What's New dialog. Dimmed at rest, brightens to full on hover. */
.status-bar-version {
  cursor: pointer;
  color: var(--status-bar-text, var(--toolbar-text-color));
  opacity: 0.5;
}
.status-bar-version:hover {
  opacity: 1;
}

/* Editor variant pins to the bottom of the viewport. The editor
   renders two of these — one spanning the left toolbar + layers tree,
   one spanning the details panel — and positions each via an inline
   `left`/`right`/`width` style so the canvas region in between is left
   uncovered. The left toolbar, tree, and details panels stop at
   --status-bar-height (see App.css) so they don't overlap. */
.status-bar-editor {
  position: fixed;
  bottom: 0;
  z-index: 15;
}

/* Light-mode: a softer surface than the dark top-toolbar so the bar
   doesn't read as a black slab against the canvas-gray pages. */
html[data-theme="light"] {
  --status-bar-bg: #e1e1e6;
  --status-bar-text: #46454e;
  --status-bar-muted: #6a6973;
}

/* Dark-mode: matches the top-toolbar surface. */
html[data-theme="dark"] {
  --status-bar-bg: var(--top-toolbar-background-color);
  --status-bar-text: var(--editor-text-color);
  --status-bar-muted: var(--editor-muted-text-color);
}

/* Generic loading spinner for async screens (image gallery, project list).
   Bundled globally like the app's other CSS; class names are prefixed so
   they don't collide. */
.app-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    width: 100%;
    padding: 48px 0;
    color: var(--editor-text-color, #5a5964);
}

.app-spinner {
    width: 36px;
    height: 36px;
    border: 3px solid var(--panel-border-color, rgba(0, 0, 0, 0.15));
    border-top-color: var(--editor-selected-blue, #3b82f6);
    border-radius: 50%;
    animation: app-spin 0.8s linear infinite;
}

.app-loading-label {
    font-size: 14px;
    opacity: 0.75;
}

@keyframes app-spin {
    to { transform: rotate(360deg); }
}

/* Small inline spinner for buttons mid-request (e.g. login). Sized in em
   so it tracks the button's font size.

   Drawn in the button's OWN text colour. It was a fixed white ring — right for the solid
   accent buttons it was written for, and invisible on every other kind: the Build Guide's
   "Generate (deterministic)" is a ghost button, so its spinner was white-on-near-white and
   the button simply looked frozen while it worked. currentColor covers both, and the
   transparent quadrant is what reads as motion.

   The animation is a pure transform, so the compositor keeps it turning even while a
   synchronous build (generateAppDesign lays out dozens of screens) holds the main thread. */
.btn-spinner {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: 0.5em;
    vertical-align: -0.15em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    opacity: 0.8;
    border-radius: 50%;
    animation: app-spin 0.7s linear infinite;
}

/* Full-screen dim overlay shown the instant a slow navigation starts
   (e.g. opening a project into the editor) so the click registers
   immediately even while the fresh record is still being fetched. */
.app-loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 18, 24, 0.55);
}
.app-loading-overlay .app-loading-label {
    color: rgba(255, 255, 255, 0.85);
    opacity: 1;
}

/* Authentication pages (login + signup). Layout mirrors the customize
   page: a dark header bar at the top with the page title, then a
   scrollable main area below that centers the form on the canvas
   surface. All colors come from editor variables so the pages match
   the active theme. */

/* All element rules below are scoped to the login + signup page
 * containers. Unscoped versions previously leaked into the rest of the
 * app (centering all <p>, restyling all <h2>) once UserAccountForm was
 * loaded once, since CSS imports in this project are global. */

.login-page h1,
.login-page h2,
.login-page h3,
.login-page h4,
.login-page h5,
.login-page h6,
.login-page p,
.login-page input,
.login-page select,
.signup-page h1,
.signup-page h2,
.signup-page h3,
.signup-page h4,
.signup-page h5,
.signup-page h6,
.signup-page p,
.signup-page input,
.signup-page select {
  font-family: var(--editor-font-family, Arial, Helvetica, sans-serif);
}

/* The .App element acts as our page shell. */
div.App {
  background-color: var(--editor-panel-background-color);
  color: var(--editor-text-color);
}

.login-page p,
.signup-page p {
  font-size: 1.25rem;
  text-align: center;
}

/* Outer page: a flex column that fills the viewport so the header
   stays pinned at the top and the form scrolls inside the main area. */
.login-page,
.signup-page {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  margin: 0;
  background-color: var(--login-content-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  overflow: hidden;
}

/* Forms fill the page and lay out as: heading bar, then the centered
   field block, then the action row at the bottom. */
.login-page > form,
.signup-page > form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

/* Top header bar — same dimensions/style as .customize-header. */
.signup-heading-div {
  display: flex;
  align-items: center;
  flex: none;
  padding: 0.75rem 1.5rem;
  background-color: var(--top-toolbar-background-color);
  color: var(--toolbar-text-color);
  border-bottom: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

h2.signup-heading {
  margin: 0;
  padding: 0;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--header-1-color);
  background-color: transparent;
}

/* h2 fallback for any other usage on these pages. Scoped to login +
   signup so it doesn't bleed into other routes' headings. */
.login-page h2,
.signup-page h2 {
  margin: 0;
  padding: 8px;
  color: var(--toolbar-text-color);
  background-color: var(--top-toolbar-background-color);
}

/* Centered form-card area between the header and the action row.
   Takes the remaining vertical space inside the form and centers the
   user-fields card both horizontally and vertically. Provides its
   own scrolling for tall forms (signup). */
.login-div,
.signup-div {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  margin: 0;
  background: transparent;
  text-align: center;
  overflow: auto;
}

/* The signup/account form can be tall. Its card uses `margin: auto`
   (see .account-card) to center within this area while still scrolling
   fully when it overflows — so no align-items override is needed. */

.user-fields-div {
  display: inline-block;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
}

.user-data-div {
  padding: 5px 10px;
  text-align: left;
}

.user-data-label {
  display: inline-block;
  width: 160px;
  margin: 5px;
  font-size: 14px;
  text-align: left;
  color: var(--editor-text-color);
}

.user-data-input {
  box-sizing: border-box;
  width: 260px;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: 14px;
}

/* "Stay logged in" row, between the password field and the action row. */
.login-remember {
  display: flex;
  align-items: center;
}

.login-remember-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 5px;
  font-size: 0.85rem;
  color: var(--editor-text-color);
  cursor: pointer;
}

.login-remember-label input[type="checkbox"] {
  cursor: pointer;
}

/* Action row tucked inside the form card, below the password input.
   Links (Forgot password / Sign Up) sit to the left of a soft spacer,
   the primary Log In button anchors the right. The previous full-width
   toolbar at the bottom of the page is gone — keeping everything in the
   centered card means messages and actions live in the same visual
   region the user is already focused on. */
.login-card-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 1rem 10px 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--editor-panel-separator-color, var(--editor-control-border-color));
}

.login-card-actions .login-button,
.login-card-actions .signup-button {
  margin-left: auto;
  /* Hold a stable footprint across the idle/submitting label swap. The busy
     state ("Logging in…" + spinner) is wider than the idle label, so without a
     reserved width the button — and the inline-block card around it — visibly
     resize the instant you click. Center the contents within that width. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 8.5rem;
}

/* Terms / Privacy consent line under the Sign Up action. */
.signup-legal-note {
  margin: 0.75rem 10px 0;
  font-size: 0.8rem;
  text-align: center;
  color: var(--editor-text-color);
  opacity: 0.75;
  line-height: 1.45;
}

.signup-legal-note a {
  color: var(--editor-selected-blue);
  text-decoration: none;
  font-weight: 600;
}

.signup-legal-note a:hover {
  text-decoration: underline;
}

/* Dev-only quick-fill row, currently only the Loren button on the Boss
   login. Dashed border + reduced opacity mark it as a non-production
   helper. Stripped from production builds via the NODE_ENV check in
   the Login component. */
.login-card-dev {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.9rem 10px 0;
  padding-top: 0.9rem;
  border-top: 1px dashed var(--editor-panel-separator-color, var(--editor-control-border-color));
}

.login-card-dev .buttons {
  opacity: 0.75;
}

.login-card-dev .buttons:hover {
  opacity: 1;
}

.login-link,
.signup {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--editor-selected-blue);
  text-decoration: none;
}

.login-link:hover,
.signup:hover {
  text-decoration: underline;
}

/* "Back to <app>" link rendered as a button — reset the native button surface
   and push it to the left so the rest of the actions stay grouped on the right. */
.login-landing-link {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  margin-right: auto;
  font-family: inherit;
}

/* Primary action button — same dimensions and surface as the customize
   page header buttons (.customize-back-button). */
.buttons {
  margin: 0;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background-color: var(--button-bg);
  color: var(--button-text);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}

.buttons:hover:not(:disabled) {
  background-color: var(--button-bg-hover);
}

/* Pressed-state feedback for the standard action buttons: a quick nudge
   down + dim while held so a click is visibly acknowledged. Mirrors the
   FS Tracker; the editor toolbar buttons already have their own :active
   states, so this is scoped to the shared .buttons class. */
.buttons {
  transition: transform 0.04s ease, filter 0.1s ease, background-color 0.1s ease;
}
.buttons:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.92);
}

#status {
  display: block;
  margin: 0 1.5rem 1rem;
  color: var(--editor-text-color);
  font-size: 0.95rem;
}

/* Password field with a show/hide eye toggle (PasswordInput widget).
   The wrapper positions the eye button over the right edge of the
   input; the input gets extra right padding so its text never slides
   under the button. */
.password-input-wrap {
  position: relative;
  display: inline-block;
}

/* In the stacked account/signup fields the wrap fills the column so the
   100%-wide .account-control keeps its full width. */
.account-field .password-input-wrap {
  display: block;
}

.password-input-wrap input {
  padding-right: 2.1rem;
}

.password-toggle {
  position: absolute;
  top: 50%;
  right: 0.4rem;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px;
  border: none;
  background: transparent;
  color: var(--editor-text-color);
  opacity: 0.6;
  cursor: pointer;
}

.password-toggle:hover,
.password-toggle:focus-visible {
  opacity: 1;
}

.password-toggle svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* Light-mode: main form area paints the canvas color, matching the
   home and customize pages. */
html[data-theme="light"] {
  --login-content-bg: var(--canvas-background-color);
}

/* ============================================================
   Account / signup form — grouped fields on a centered card
   ============================================================ */

/* The form card. `margin: auto` centers it within the scrollable
   main area when it fits, and — unlike align/justify-center — still
   lets the user scroll up to the top when the form overflows.
   Fluid width up to 960px: on a wide window it grows so the two
   columns get enough room for the controls to breathe (rather than
   pinning at a narrow 720px), and it falls back to the available
   width on smaller screens. */
.account-card {
  margin: auto;
  width: 100%;
  max-width: 960px;
  box-sizing: border-box;
  padding: 1.5rem 1.75rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  text-align: left;
}

/* The labelled field sections flow into two balanced columns. CSS
   multi-column (rather than a row-major grid) evens out the two columns'
   heights on its own — the old grid left the tall Address section alone
   in the left column while the right column ended short. `300px` caps it
   at two columns on the 720px card and collapses to one on narrow screens
   with no media query. */
.account-sections {
  columns: 300px 2;
  column-gap: 1.4rem;
}

/* Keep each section whole within a column, and restore the vertical
   gap between stacked sections (multi-column has no row `gap`, so the
   per-section bottom margin from .account-section does that job again). */
.account-sections .account-section {
  break-inside: avoid;
}

/* Soft "Alpha" banner anchored at the top of the signup / account
   card. The accent-tinted background reads as informative rather than
   alarming — bordered + filled with the same selected-blue used
   elsewhere, at low opacity so it reads in both light and dark
   themes. */
.alpha-banner {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0 0 1.4rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid color-mix(in srgb, var(--editor-selected-blue) 35%, transparent);
  border-radius: var(--corner-radius);
  background-color: color-mix(in srgb, var(--editor-selected-blue) 10%, transparent);
  color: var(--editor-text-color);
  font-size: 0.9rem;
  line-height: 1.4;
  text-align: left;
}

.alpha-banner-badge {
  flex: none;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background-color: var(--editor-selected-blue);
  color: #ffffff;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.alpha-banner-text {
  flex: 1 1 auto;
}

/* A labelled group of related fields. */
.account-section {
  margin-bottom: 1.4rem;
}

.account-section:last-child {
  margin-bottom: 0;
}

.account-section-heading {
  margin: 0 0 0.7rem;
  padding-bottom: 0.3rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--header-2-color);
  border-bottom: 1px solid var(--editor-panel-separator-color, var(--editor-control-border-color));
}

.account-section-note {
  margin: 0.55rem 0 0;
  font-size: 0.8rem;
  font-style: italic;
  text-align: left;
  color: var(--editor-text-color);
  opacity: 0.75;
}

/* Danger zone — the account-mode "Delete Account" section. The heading
   and buttons take a red accent so the irreversible action reads clearly
   apart from the ordinary save/cancel controls. */
.account-section-danger .account-section-heading {
  color: #b91c1c;
  border-bottom-color: rgba(220, 38, 38, 0.45);
}

.account-delete-actions {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.85rem;
}

.account-delete-button,
.account-delete-confirm {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  border-color: rgba(220, 38, 38, 0.55);
  background-color: rgba(220, 38, 38, 0.10);
  color: #b91c1c;
}

.account-delete-button:hover:not(:disabled),
.account-delete-confirm:hover:not(:disabled) {
  background-color: rgba(220, 38, 38, 0.18);
}

/* Field grid within a section: paired fields (First/Last, City/State,
   Password/Confirm) sit two-up when the section is wide enough and stack
   to one column when it isn't — so on phones they don't get squeezed
   (e.g. the State select shrinking to nothing or the Zip placeholder
   truncating). `min(100%, 10rem)` lets a column fall below 10rem on very
   narrow cards rather than overflow. Wide fields keep spanning the full
   row via .account-field-wide (grid-column: 1 / -1). */
.account-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: 0.7rem 1rem;
}

/* One stacked label + control. */
.account-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

/* A field that spans the full width of the grid. */
.account-field-wide {
  grid-column: 1 / -1;
}

.account-field label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--editor-text-color);
}

/* Shared style for text inputs and the country/state <select>s. */
.account-control {
  box-sizing: border-box;
  width: 100%;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: 14px;
}

.account-control:focus {
  outline: 1px solid var(--editor-selected-blue);
  outline-offset: -1px;
}

/* One consent/preference checkbox row inside an account section. */
.account-checkbox {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.25rem 0;
  font-size: 0.9rem;
  color: var(--editor-text-color);
  cursor: pointer;
}

.account-checkbox input[type="checkbox"] {
  cursor: pointer;
}

/* Dev/test quick-fill buttons on the form's action row. The dashed
   border marks them as non-production helpers. */
.dev-fill-button {
  padding: 0.28rem 0.7rem;
  border: 1px dashed var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: transparent;
  color: var(--editor-text-color);
  font-size: 0.78rem;
  cursor: pointer;
  opacity: 0.65;
}

.dev-fill-button:hover {
  opacity: 1;
}

/* Informational (non-error) status message. */
.status-bar-ok {
  color: var(--editor-selected-blue);
}

/* Prominent inline error / status block, shown inside the form card
   above the inputs. Replaces stuffing errors into the StatusBar at the
   bottom corner of the screen — that strip is small and easy to miss,
   especially on tall monitors where the form is centered way above it. */
.login-page .login-form-status,
.signup-page .login-form-status {
  display: block;
  margin: 0 auto 1rem;
  padding: 0.65rem 1rem;
  border-radius: var(--corner-radius);
  font-size: 1rem;
  font-weight: 600;
  text-align: center;
  line-height: 1.4;
}

.login-page .login-form-status.is-error,
.signup-page .login-form-status.is-error {
  background-color: rgba(220, 38, 38, 0.10);
  border: 1px solid rgba(220, 38, 38, 0.45);
  color: #b91c1c;
}

.login-page .login-form-status.is-ok,
.signup-page .login-form-status.is-ok {
  background-color: rgba(34, 197, 94, 0.10);
  border: 1px solid rgba(34, 197, 94, 0.45);
  color: #15803d;
}

/* ALL-BUTTONS PRESS FEEDBACK
   Give every remaining button the same click response as the shared
   .buttons class and the marketing site: a quick nudge down + brightness
   dip while held. Additive to each button's own hover / background states.
   The color-picker drag handle and menu-row divs are intentionally left
   out (they have functional or list-row behaviors, not button presses). */
.home-buttons,
.home-icon-button,
.customize-reset-button,
.dev-fill-button,
.verify-banner-button,
.share-button,
.tt-btn,
.boss-icon-button,
.boss-delete-x,
.boss-primary,
.docs-back-button,
.docs-audience-button,
.docs-account-button,
.export-button,
.image-offset-reset,
.angle-reset,
.color-picker-close,
.color-picker-eyedropper-btn {
  transition: transform 0.04s ease, filter 0.1s ease, background-color 0.08s ease;
}
.home-buttons:active:not(:disabled),
.home-icon-button:active:not(:disabled),
.customize-reset-button:active:not(:disabled),
.dev-fill-button:active:not(:disabled),
.verify-banner-button:active:not(:disabled),
.share-button:active:not(:disabled),
.tt-btn:active:not(:disabled),
.boss-icon-button:active:not(:disabled),
.boss-delete-x:active:not(:disabled),
.boss-primary:active:not(:disabled),
.docs-back-button:active:not(:disabled),
.docs-audience-button:active:not(:disabled),
.docs-account-button:active:not(:disabled),
.export-button:active:not(:disabled),
.image-offset-reset:active:not(:disabled),
.angle-reset:active:not(:disabled),
.color-picker-close:active:not(:disabled),
.color-picker-eyedropper-btn:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.92);
}

/* ── Agentic-authorization consent page (/approve) ───────────────────────── */
/* Reuses the login chrome (.login-page, .login-div, .user-fields-div, fields,
   .login-card-actions, .login-button). These add the consent-specific copy. */
.approve-lead {
  color: var(--editor-text-color);
  font-size: 0.95rem;
  line-height: 1.45;
  margin: 0 0 0.75rem 0;
}

.approve-note {
  color: var(--editor-text-color);
  opacity: 0.8;
  font-size: 0.85rem;
  line-height: 1.4;
  margin: 0.5rem 0 0.25rem 0;
}

.approve-consent {
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.35));
  border-radius: 8px;
  padding: 0.85rem 1rem;
  margin: 0.25rem 0 0.5rem 0;
  background-color: var(--editor-input-bg, rgba(127, 127, 127, 0.08));
}

.approve-scope-list {
  margin: 0.15rem 0 0.5rem 1.1rem;
  padding: 0;
  color: var(--editor-text-color);
  opacity: 0.9;
  font-size: 0.85rem;
  line-height: 1.5;
}

/* A quieter, secondary action sitting next to the primary Approve button. */
.approve-deny-button {
  background-color: transparent;
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.5));
  color: var(--editor-text-color);
}

/* ── Account Settings (tabbed dialog) ────────────────────────────────────── */
/* The Account Settings screen (Account.tsx) is a Customize-style page: a
   header with the back button, a tab strip, and a scrolling .customize-panel.
   The profile form and the Automation access section render embedded inside
   that panel — without their own full-screen .signup-page chrome — so the
   panel is the single scroll area and .account-card centres within it. */
.account-settings-page .account-embedded-form {
  display: block;
}

/* ── Automation access (Account page tokens section) ─────────────────────── */
.token-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0.5rem 0;
}

.token-row {
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.35));
  border-radius: 8px;
  padding: 0.6rem 0.8rem;
  background-color: var(--editor-input-bg, rgba(127, 127, 127, 0.06));
}

.token-row-main {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.token-row-name {
  font-weight: 600;
  color: var(--editor-text-color);
}

.token-row-prefix {
  font-family: monospace;
  opacity: 0.8;
  color: var(--editor-text-color);
}

.token-row-state {
  font-size: 0.75rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid currentColor;
}

.token-row-state.is-active { color: #1f9d55; }
.token-row-state.is-revoked { color: #b04a4a; opacity: 0.85; }

.token-row-meta {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 0.35rem;
  font-size: 0.8rem;
  opacity: 0.75;
  color: var(--editor-text-color);
}

.token-row-actions {
  margin-top: 0.5rem;
}

.token-revoke-button {
  background-color: transparent;
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.5));
  color: var(--editor-text-color);
}

.token-create {
  margin-top: 0.75rem;
}

.token-create-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* One-time reveal box for a freshly minted token. */
.token-reveal {
  border: 1px solid #1f9d55;
  border-radius: 8px;
  padding: 0.75rem 0.9rem;
  margin: 0.5rem 0 0.75rem 0;
  background-color: rgba(31, 157, 85, 0.08);
}

.token-reveal-label {
  font-size: 0.85rem;
  color: var(--editor-text-color);
  margin-bottom: 0.5rem;
}

.token-reveal-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.token-reveal-value {
  font-family: monospace;
  font-size: 0.85rem;
  word-break: break-all;
  flex: 1 1 auto;
  padding: 0.35rem 0.5rem;
  border-radius: 6px;
  background-color: var(--editor-input-bg, rgba(127, 127, 127, 0.12));
  color: var(--editor-text-color);
}

.token-reveal-dismiss {
  display: inline-block;
  margin-top: 0.5rem;
}

/* App-switcher on the login form: pick which product to open after sign-in. */
.login-app-switch {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.login-app-options {
  display: flex;
  gap: 0.5rem;
}
.login-app-option {
  flex: 1;
  cursor: pointer;
}
.login-app-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.login-app-option span {
  display: block;
  text-align: center;
  padding: 0.5rem 0;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  font-weight: 600;
  color: var(--editor-text-color);
}
.login-app-option.is-selected span {
  border-color: var(--editor-selected-blue);
  background-color: color-mix(in srgb, var(--editor-selected-blue) 14%, transparent);
  color: var(--header-1-color);
}

/* The Boss dashboard styling. Anchored to the .App frame like the rest
 * of the editor pages so the table scrolls inside its own area rather
 * than pushing the page past the viewport.
 *
 * Colors reuse the editor theme variables so light/dark theming follows
 * the rest of the app. Modal sits above on a translucent backdrop.
 */

.boss-page {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--editor-panel-background-color);
    color: var(--editor-text-color);
    font-family: var(--editor-font-family, Arial, Helvetica, sans-serif);
}

.boss-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    /* Padding + button sizing match .home-header-div so the Boss / Admin
       pages share the same toolbar height as the home page. */
    padding: 0.75rem 1.5rem;
    background-color: var(--top-toolbar-background-color);
    color: var(--toolbar-text-color);
    border-bottom: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

.boss-header h1 {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--header-1-color);
}

.boss-header-spacer { flex: 1 1 auto; }

/* Icon buttons in the Boss header (Add user, home, Log out boss,
   Log out all). Transparent so they read against the dark header
   surface, white-tint hover/active to match the home page header
   icon-button pattern. */
.boss-icon-button {
    background: transparent;
    border: none;
    margin: 0;
    padding: 4px;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    border-radius: var(--corner-radius);
    cursor: pointer;
    transition: background-color 80ms ease-out, opacity 80ms ease-out;
    /* Foreground-highlight rule: muted glyph at rest, full on hover, no bg box. */
    opacity: 0.8;
}

.boss-icon-button:hover {
    opacity: 1;
}

.boss-icon-button:active {
    opacity: 1;
}

/* Wider variant for the composite Log-out-boss button so the logout
   glyph plus the smaller crown badge fit comfortably without crowding. */
.boss-icon-button-wide {
    width: 54px;
}

.boss-icon-button-img {
    height: 22px;
    width: auto;
    user-select: none;
    pointer-events: none;
}

/* Smaller adornment used for the crown that sits next to the logout
   glyph on the Log-out-boss button. */
.boss-icon-button-img-sm {
    height: 14px;
    width: auto;
    user-select: none;
    pointer-events: none;
}

/* The email cell doubles as the row's edit affordance. Reset native
   button styling so it reads as a link, then add hover/focus underline
   so the cell visibly responds. */
.boss-email-link {
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    color: var(--editor-selected-blue);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.boss-email-link:hover,
.boss-email-link:focus-visible {
    text-decoration: underline;
}

/* Red × delete button matching the .color-picker-close pattern used
   elsewhere (e.g. ColorPicker, GradientEditor) — transparent
   background, red glyph at muted opacity, brighter + lightly tinted
   on hover/active. */
.boss-delete-x {
    background-color: transparent;
    border: none;
    border-radius: var(--corner-radius-sm);
    padding: 2px 8px;
    font-family: var(--editor-font-family);
    font-size: 1rem;
    font-weight: 700;
    color: #e53935;
    cursor: pointer;
    user-select: none;
    line-height: 1;
    opacity: var(--editor-icon-muted-opacity, 0.6);
    transition: background-color 80ms ease-out, opacity 80ms ease-out;
}

.boss-delete-x:hover {
    background-color: transparent;
    opacity: 1;
}

.boss-delete-x:active {
    background-color: rgba(128, 128, 128, 0.32);
    opacity: 1;
}

.boss-status-error {
    margin: 0;
    padding: 0.5rem 1.5rem;
    background-color: rgba(220, 38, 38, 0.10);
    color: #b91c1c;
    font-size: 0.9rem;
}

.boss-table-wrap {
    flex: 1 1 auto;
    overflow: auto;
    padding: 1rem 1.5rem 2rem;
}

.boss-table {
    border-collapse: collapse;
    width: 100%;
    font-size: 0.9rem;
}

.boss-table th, .boss-table td {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--editor-panel-separator-color);
    vertical-align: middle;
}

.boss-table th {
    font-weight: 600;
    color: var(--header-2-color);
    background-color: rgba(0, 0, 0, 0.02);
    position: sticky;
    top: 0;
    z-index: 1;
}

.boss-row-actions {
    display: flex;
    gap: 0.4rem;
}

.boss-toggle input[type="checkbox"] { cursor: pointer; }

/* Inline role select in the Boss table. Sized to match surrounding
   text so the row stays on one line. */
.boss-role-select {
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--editor-control-border-color);
    border-radius: var(--corner-radius-sm, 4px);
    background-color: var(--editor-input-bg, var(--editor-panel-background-color));
    color: var(--editor-text-color);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

/* ----- Modal ----- */
.boss-modal-backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}

.boss-modal {
    background-color: var(--editor-panel-background-color);
    color: var(--editor-text-color);
    border-radius: var(--corner-radius, 6px);
    padding: 1.5rem 1.6rem;
    max-width: 560px;
    width: calc(100% - 2rem);
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

.boss-modal-title {
    margin: 0 0 1rem;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--header-1-color);
}

.boss-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.7rem 1rem;
}

.boss-form-grid label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    color: var(--editor-text-color);
}

.boss-form-grid input[type="text"],
.boss-form-grid input[type="email"],
.boss-form-grid input[type="password"],
.boss-form-grid input:not([type]) {
    padding: 0.4rem 0.55rem;
    border: 1px solid var(--editor-control-border-color);
    border-radius: var(--corner-radius-sm, 4px);
    background-color: var(--editor-input-bg, var(--editor-panel-background-color));
    color: var(--editor-text-color);
    font-size: 0.9rem;
}

.boss-form-wide { grid-column: 1 / -1; }

.boss-form-check {
    flex-direction: row !important;
    align-items: center;
    gap: 0.5rem;
}

.boss-form-status {
    margin: 0.8rem 0 0;
    color: #b91c1c;
    font-size: 0.85rem;
}

.boss-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.2rem;
}

.boss-primary {
    background-color: var(--editor-selected-blue);
    color: #ffffff;
}

/* Delete-admin choice dialog. */
.boss-confirm {
    max-width: 460px;
}

.boss-confirm-text {
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--editor-text-color);
}

.boss-danger {
    border-color: rgba(220, 38, 38, 0.55);
    background-color: rgba(220, 38, 38, 0.12);
    color: #b91c1c;
}

.boss-danger:hover:not(:disabled) {
    background-color: rgba(220, 38, 38, 0.2);
}

/* Back control for full-screen pages: a single major back button.
   See BackControls.tsx. */
.back-controls {
  display: inline-flex;
  align-items: center;
}

/* Customize (preferences) page. Tabbed notebook with Theme, Layout,
   Keybindings, and Colors panels. Everything reads from the same CSS
   variables the editor uses, so the page itself respects the user's
   selected theme. */

.customize-page {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  background-color: var(--customize-page-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-family: var(--editor-font-family);
  overflow: hidden;
  /* One indentation step. Descriptions sit one step under their section
     header; the details below them sit one step further again. */
  --cz-indent: 1.5rem;
}

.customize-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.5rem;
  border-bottom: 1px solid var(--panel-border-color);
  background-color: var(--top-toolbar-background-color);
  color: var(--toolbar-text-color);
}

.customize-header h1 {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--header-1-color);
}

.customize-header-spacer {
  flex: 1;
}

.customize-reset-button {
  padding: 0.4rem 0.9rem;
  font-size: 0.9rem;
  font-weight: 600;
  border-radius: var(--corner-radius);
  border: 1px solid var(--editor-control-border-color);
  background-color: var(--button-bg);
  color: var(--button-text);
  cursor: pointer;
}

.customize-reset-button:hover {
  background-color: var(--button-bg-hover);
}

.customize-tabs {
  display: flex;
  gap: 2px;
  padding: 0 1.5rem;
  background-color: var(--customize-tab-strip-bg, var(--editor-panel-separator-color));
  border-bottom: 1px solid var(--panel-border-color);
}

.customize-tab {
  padding: 0.6rem 1.25rem;
  margin: 0;
  border: none;
  background: var(--customize-tab-bg-inactive, transparent);
  color: var(--customize-tab-color, var(--editor-muted-text-color));
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}

.customize-tab:hover {
  color: var(--customize-tab-color-active, var(--editor-text-color));
}

.customize-tab.active {
  color: var(--customize-tab-color-active, var(--editor-text-color));
  border-bottom-color: var(--editor-selected-blue);
  background-color: var(--customize-tab-bg-active, var(--editor-input-bg, var(--editor-panel-background-color)));
}

/* The tab NAME sits muted and brightens (foreground-highlight rule) on hover for
   an unselected, non-disabled tab — and is full when active. Opacity is used so
   it also lifts the accent-coloured Code tab, and so the per-tab background
   hierarchy (strip / inactive / active) is left untouched. */
.customize-tab-label {
  display: inline-block;
  opacity: 0.58;
  transition: opacity 0.1s ease;
}
.customize-tab:not(.active):not(:disabled):hover .customize-tab-label,
.customize-tab.active .customize-tab-label {
  opacity: 1;
}

.customize-panel {
  flex: 1;
  overflow: auto;
  padding: 1.5rem 2rem;
  /* Defensive: keep panel content left-aligned even if a sibling page's
     CSS were to set a wider text-align: center. */
  text-align: left;
}

.customize-section-title {
  margin: 0 0 0.5rem;
  font-size: 1rem;
  font-weight: 600;
  text-align: left;
  color: var(--header-2-color);
}

.customize-section-hint {
  /* Equal left/right margins so the description block is inset evenly. */
  margin: 0 var(--cz-indent) 1rem;
  color: var(--customize-hint-color, var(--editor-muted-text-color));
  font-size: 0.85rem;
  text-align: left;
}

/* ── Plugins inspector (Plugins tab) ── */
.plugins-list {
  list-style: none;
  margin: 0 var(--cz-indent);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: left;
}
.plugin-card {
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.35));
  border-radius: 6px;
  padding: 10px 12px;
  background: var(--editor-input-bg, transparent);
}
.plugin-card-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.plugin-card-off {
  opacity: 0.55;
}
/* Enable control pinned to the right of the card head. */
.plugin-enable {
  margin-left: auto;
  align-self: center;
}
.plugin-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  font-size: 0.8rem;
  color: var(--editor-text-color);
}
.plugin-toggle input {
  margin: 0;
  cursor: pointer;
}
.plugin-core-badge {
  font-size: 0.72rem;
  color: var(--editor-muted-text-color);
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.35));
  border-radius: 3px;
  padding: 0 5px;
  line-height: 1.6;
}
.plugin-name {
  font-weight: 600;
  color: var(--header-3-color, var(--editor-text-color));
}
.plugin-id {
  font-family: monospace;
  font-size: 0.78rem;
  color: var(--editor-muted-text-color);
}
.plugin-version {
  font-size: 0.78rem;
  color: var(--editor-muted-text-color);
}
.plugin-api-mismatch {
  font-size: 0.72rem;
  color: #b26a00;
  border: 1px solid currentColor;
  border-radius: 3px;
  padding: 0 4px;
}
.plugin-desc {
  margin: 6px 0 8px;
  font-size: 0.82rem;
  color: var(--editor-text-color);
}
.plugin-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.plugin-contribs {
  font-size: 0.8rem;
  color: var(--editor-muted-text-color);
}
.plugin-perms {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
}
.plugin-perm-chip {
  font-size: 0.72rem;
  color: var(--selection-color, #1097e2);
  border: 1px solid var(--selection-color, #1097e2);
  border-radius: 3px;
  padding: 0 5px;
  line-height: 1.5;
}

/* Two-column tab layout. Collapses to a single column when the window
   is too narrow to comfortably hold two. */
.customize-2col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem 2.5rem;
  align-items: start;
}

@media (min-width: 900px) {
  .customize-2col {
    grid-template-columns: 1fr 1fr;
  }
}

/* Engine Defaults groups flow into balanced columns that collapse to a
   single column when the window is too narrow. Multi-column (not grid) so
   groups pack tightly instead of row-aligning and leaving big vertical gaps. */
.customize-engine-cols {
  columns: 2 19rem;
  column-gap: 2.5rem;
}

.customize-engine-cols > .customize-group {
  break-inside: avoid;
  margin-bottom: 1.75rem;
}

/* The Keybindings / Colors group grid is indented one step so the
   group names sit under their tab's section header. */
.customize-2col-sub {
  margin-left: var(--cz-indent);
}

/* A section: the title stays centered (rule above); the description
   sits one indent step in (rule on .customize-section-hint), and the
   detail(s) below it sit one step further again. */
.customize-section {
  display: block;
}

/* Breathing room above each section header (not the first). */
.customize-section + .customize-section {
  margin-top: 1.5rem;
}

/* When one section holds several sub-headings (e.g. the reference settings:
   X/Y measurement + default reference point), the base title only carries a
   bottom margin, so the 2nd+ look cramped. Give them room above. */
.customize-section > .customize-section-title:not(:first-child) {
  margin-top: 1.5rem;
}

.customize-section > .customize-section-hint {
  margin-bottom: 0.75rem;
}

.customize-section > :not(.customize-section-title):not(.customize-section-hint) {
  margin-left: calc(2 * var(--cz-indent));
}

/* A Keybindings / Colors group within a column. The group name stays
   flush left; the group's details are indented by the standard amount,
   matching the Layout-tab sections. */
.customize-group {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.customize-group > :not(.customize-subhead) {
  margin-left: var(--cz-indent);
}

.customize-subhead {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: left;
  color: var(--header-2-color);
}

/* When a section stacks several labelled control groups (e.g. the
   color-picker magnifier settings), separate each subhead from the
   control above it. Margins collapse, so the first subhead keeps an
   even gap from the section hint too. */
.customize-section > .customize-subhead {
  margin-top: 1rem;
}

/* Theme tab */

.theme-options {
  display: grid;
  /* auto-fit so a 3- or 4-option list (theme picker, action announce,
     tooltip mode) lays out on a single row when there's horizontal
     room, and wraps gracefully on narrower viewports. */
  grid-template-columns: repeat(auto-fit, minmax(150px, 200px));
  gap: 1rem;
}

.theme-option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 1rem;
  border: 2px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background: var(--theme-option-bg, var(--editor-panel-background-color));
  cursor: pointer;
  text-align: left;
  color: var(--theme-option-text, var(--editor-text-color));
  font-size: 0.95rem;
}

.theme-option.active {
  border-color: var(--editor-selected-blue);
}

.theme-option-swatch {
  width: 100%;
  height: 60px;
  border-radius: var(--corner-radius-sm);
  border: 1px solid var(--editor-control-border-color);
  display: grid;
  grid-template-columns: 1fr 3fr;
}

.theme-option-swatch > span:first-child {
  border-right: 1px solid var(--editor-control-border-color);
}

/* Action-announcements swatches. Each one draws a tiny abstraction of the
 * fs-designer editor (top toolbar strip, left tools strip, canvas area)
 * and overlays the announcement element belonging to that mode:
 *   • toast — a rounded pill near the top of the canvas (matches the
 *             real canvas-notification position: top: 1.2rem, centred)
 *   • bar   — a thin status strip across the bottom of the editor
 *   • both  — the pill at top AND the bar at bottom
 *   • none  — ∅ glyph centred over a plain editor scene
 * Pseudo-elements layer on top of the base editor sketch so the swatch
 * conveys both the geometry of fs-designer and the announcement layout. */
.announce-swatch {
  display: block;
  position: relative;
  background-color: var(--editor-panel-separator-color);
  overflow: hidden;
}

/* Top-toolbar strip + left-tools strip drawn on every announce swatch so
 * the user recognises the rest of the editor regardless of mode. The
 * remaining area reads as the canvas. */
.announce-swatch::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 9px;
  background: var(--top-toolbar-background-color);
  border-bottom: 1px solid var(--editor-control-border-color);
}

/* Toast pill — small rounded rectangle just under the top-toolbar strip,
 * horizontally centred to mirror the real `.canvas-notification` at
 * top: 1.2rem. Reused for the "both" mode swatch (its bottom bar is
 * drawn via a background gradient since ::before/::after are taken). */
.announce-swatch-toast::after,
.announce-swatch-both::after {
  content: '';
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: 46%;
  height: 9px;
  background: rgba(24, 24, 28, 0.82);
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* Status bar strip pinned to the bottom of the editor sketch. */
.announce-swatch-bar::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 10px;
  background: var(--editor-panel-background-color);
  border-top: 1px solid var(--editor-control-border-color);
}

/* Both mode: the top-toolbar strip lives on `.announce-swatch::before`
 * and the toast pill on `::after` (above), which leaves no pseudo-element
 * for the bottom bar — so we paint it with a background gradient on the
 * swatch itself: a solid panel-bg band at the bottom 10px, transparent
 * above (so the base separator-color shows through as the canvas area). */
.announce-swatch-both {
  background:
    linear-gradient(to top,
      var(--editor-panel-background-color) 0,
      var(--editor-panel-background-color) 10px,
      transparent 10px,
      transparent 100%),
    var(--editor-panel-separator-color);
}

/* None: a centred ∅ over the plain editor scene. */
.announce-swatch-none::after {
  content: '∅';
  position: absolute;
  inset: 9px 0 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--editor-muted-text-color);
  font-size: 1.4rem;
  font-weight: 600;
}

/* Tooltip-mode swatches. Each sketches the editor layout — a top
 * toolbar strip across the top, narrow left strip (Left Toolbar +
 * Layers Panel) on the left, narrow right strip (Design Panel) on the
 * right, and the canvas in the middle. Each mode tints the regions
 * that surface tooltips in blue, the others in muted grey. */
.tooltip-swatch {
  display: block;
  position: relative;
  background-color: var(--editor-panel-separator-color);
  overflow: hidden;
}

/* Top toolbar strip (top 9px), drawn on every tooltip swatch via
 * ::before and tinted by mode below. */
.tooltip-swatch::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 9px;
  background: var(--editor-control-border-color);
  border-bottom: 1px solid var(--editor-control-border-color);
}

/* The left + right side strips drawn together via ::after using a
 * two-band radial-friendly trick: two vertical bands on each edge.
 * We use a layered background on the swatch itself so the inner area
 * (canvas) stays the swatch's default background. */
.tooltip-swatch::after {
  content: '';
  position: absolute;
  top: 9px;
  bottom: 0;
  left: 0;
  right: 0;
  background:
    linear-gradient(to right,
      var(--editor-control-border-color) 0,
      var(--editor-control-border-color) 14px,
      transparent 14px,
      transparent calc(100% - 14px),
      var(--editor-control-border-color) calc(100% - 14px),
      var(--editor-control-border-color) 100%);
}

/* Mode-specific highlights — paint the region that's enabled with the
 * selection blue so the user sees at a glance where tooltips appear. */
.tooltip-swatch-top::before {
  background: var(--editor-selected-blue);
}

.tooltip-swatch-panels::after {
  background:
    linear-gradient(to right,
      var(--editor-selected-blue) 0,
      var(--editor-selected-blue) 14px,
      transparent 14px,
      transparent calc(100% - 14px),
      var(--editor-selected-blue) calc(100% - 14px),
      var(--editor-selected-blue) 100%);
}

.tooltip-swatch-both::before {
  background: var(--editor-selected-blue);
}

.tooltip-swatch-both::after {
  background:
    linear-gradient(to right,
      var(--editor-selected-blue) 0,
      var(--editor-selected-blue) 14px,
      transparent 14px,
      transparent calc(100% - 14px),
      var(--editor-selected-blue) calc(100% - 14px),
      var(--editor-selected-blue) 100%);
}

/* None: dim editor + ∅. The ::before and ::after stay grey; the ∅
 * sits on the swatch background via an extra inset wrapper. */
.tooltip-swatch-none {
  position: relative;
}

.tooltip-swatch-none > * { display: none }

/* Use a CSS-only ∅ via the swatch's content-area: we layer the glyph
 * as a background using SVG data URI to avoid clobbering ::before /
 * ::after that already draw the toolbar + side strips. */
.tooltip-swatch-none {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 100 100%27><text x=%2750%27 y=%2765%27 text-anchor=%27middle%27 font-size=%2752%27 font-weight=%27700%27 fill=%27%238e8c9e%27 font-family=%27Arial, sans-serif%27>%E2%88%85</text></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 36px;
}

/* Layout tab */

.layout-grid {
  display: grid;
  grid-template-columns: 140px 1fr 56px;
  gap: 0.7rem 0.7rem;
  align-items: center;
  max-width: 420px;
}

.layout-grid label {
  font-size: 0.95rem;
}

.layout-grid input[type="range"] {
  width: 100%;
}

.layout-grid input[type="number"] {
  width: 70px;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
}

.layout-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.95rem;
  user-select: none;
  cursor: pointer;
}

.layout-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  margin: 0;
}

.customize-radios {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.customize-radio {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.95rem;
  user-select: none;
  cursor: pointer;
}

.customize-radio input[type="radio"] {
  margin: 0;
}

.customize-slider-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

.customize-slider {
  width: 240px;
  max-width: 60%;
}

.customize-slider-value {
  font-size: 0.9rem;
  color: var(--customize-hint-color, var(--editor-muted-text-color));
  min-width: 3rem;
}

/* Keybindings tab */

.keybindings-table {
  /* Fills the group minus its indent (the table carries a margin-left
     of --cz-indent from the .customize-group rule). */
  width: calc(100% - var(--cz-indent));
  max-width: 720px;
  border-collapse: collapse;
  /* Fixed layout so the command column is a consistent width in every
     group's table and the shortcut boxes all line up. */
  table-layout: fixed;
}

.keybindings-table th,
.keybindings-table td {
  text-align: left;
  padding: 0.35rem 0.6rem;
  font-size: 0.95rem;
}

/* First cell (the command label) starts flush with the group name and
   has a fixed width, so the shortcut boxes in every group line up at
   the same x. Last cell (the shortcut box) has no trailing padding. */
.keybindings-table td:first-child {
  width: 150px;
  padding-left: 0;
}

.keybindings-table td:last-child {
  padding-right: 0;
}

.keybindings-table th {
  color: var(--editor-muted-text-color);
  font-weight: 600;
  letter-spacing: 0.03em;
  font-size: 0.8rem;
  text-transform: uppercase;
}

.keybindings-table tr:hover td {
  background-color: var(--editor-panel-separator-color);
}

.keybinding-input {
  width: 100%;
  max-width: 200px;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.85rem;
}

.keybinding-input.capturing {
  border-color: var(--editor-selected-blue);
  outline: 1px solid var(--editor-selected-blue);
}

/* Colors tab */

/* Each color row: a clear gap between the description and its swatch
   (matching the keybindings layout), a generous row gap for space
   around each pair. */
.color-list {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  gap: 1rem 1.5rem;
  align-items: center;
  padding: 0.25rem 0;
}

.color-row-label {
  font-size: 0.95rem;
  text-align: left;
}

.color-row-input {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

/* Radio-button group for enumerated engine defaults (e.g. Has on creation). */
.customize-radio-group {
  gap: 0.9rem;
}

.customize-radio {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.9rem;
  cursor: pointer;
}

.color-row-input input[type="color"] {
  width: 44px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background: transparent;
  cursor: pointer;
}

.color-row-input input[type="text"] {
  width: 120px;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.85rem;
}

/* Numeric defaults on the Engine tab share the colour-row grid. */
.color-row-input input[type="number"] {
  width: 78px;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: 0.85rem;
}

/* Range slider used in the Engine Defaults grid (e.g. highlighter opacity). */
.engine-slider {
  width: 120px;
}

.engine-slider-value {
  min-width: 2.6rem;
  font-size: 0.9rem;
  color: var(--customize-hint-color, var(--editor-muted-text-color));
}

/* Engine tab: the "reset just these defaults" action sits below the
   groups, indented to line up with them. */
.customize-engine-reset {
  margin: 1.75rem 0 0 var(--cz-indent);
}

/* Each theme (light / dark) is its own section in the Colors tab. Its
   color rows are split into titled groups of related colors: the
   section title spans the column, each group's title sits one indent
   step in, and the swatches sit one step further (matching the
   Layout tab's section / detail hierarchy). */
.color-theme-section {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.color-theme-section > .customize-section-title {
  margin-bottom: 0.85rem;
  text-align: left;
}

.color-theme-section > .color-group {
  margin-left: var(--cz-indent);
}

.color-group {
  margin-bottom: 1.1rem;
}

.color-group:last-child {
  margin-bottom: 0;
}

/* Light-mode customizations:
   - Tab strip and tab titles a touch darker than the muted defaults
     so the navigation reads with a bit more weight.
   - Section hint text darker so descriptions don't look so faint.
   - Theme-option tiles keep their original near-white surface so they
     stand out against the now-grayish page background, but their
     label text is darkened slightly. */
html[data-theme="light"] {
  --customize-page-bg: var(--canvas-background-color);
  /* Three distinct levels in the tab strip:
     - selected tab is the brightest (true white)
     - unselected tabs sit a step darker
     - the strip area outside the tabs is darker still */
  --customize-tab-strip-bg: #b1afb8;
  --customize-tab-bg-inactive: #cfcdd5;
  --customize-tab-bg-active: #ffffff;
  --customize-tab-color: #46454e;
  --customize-tab-color-active: #2c2b33;
  --customize-hint-color: #6a6973;
  --theme-option-bg: #ffffff;
  --theme-option-text: #2c2b33;
}

/* Dark mode: same three-level hierarchy — the selected tab merges
   into the panel below, unselected tabs are a step darker, and the
   strip "frame" is darker still. Tile surfaces use the top-toolbar
   color so the clickable tiles read as elevated controls on the
   slightly brighter panel background. */
html[data-theme="dark"] {
  --customize-tab-strip-bg: #0c0e12;
  --customize-tab-bg-inactive: #14161b;
  --customize-tab-bg-active: var(--editor-panel-background-color);
  --theme-option-bg: var(--top-toolbar-background-color);
}

/* Home page. Layout mirrors the customize page: a dark header bar
   pinned at the top with action buttons, then a scrollable main area
   below that holds the project grid. */

#home-div.home-div {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  margin: 0;
  padding: 0;
  background-color: var(--home-content-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  text-align: center;
  box-sizing: border-box;
}

/* Top action bar — same dimensions and surface as .customize-header. */
.home-header-div {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  background-color: var(--top-toolbar-background-color);
  color: var(--toolbar-text-color);
  border-bottom: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

.home-header-spacer {
  flex: 1 1 auto;
}

/* Buttons styled to match .customize-back-button / .customize-reset-button. */
.home-buttons {
  margin: 0;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  background-color: var(--button-bg);
  color: var(--button-text);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  min-width: auto;
}

.home-buttons:hover:not(:disabled) {
  background-color: var(--button-bg-hover);
}

/* Icon-only header buttons (Add Project, Delete Project, Log Off).
   Transparent on the dark header surface, with a subtle hover/active
   tint so the click target is discoverable. The icon image is sized
   to read at toolbar scale. */
.home-icon-button {
  margin: 0;
  padding: 0;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--corner-radius);
  background-color: transparent;
  cursor: pointer;
  /* The standard toolbar glyph is 48px tall and centred; let it overflow the
     36px hit box the way the editor's .tt-btn does. */
  overflow: visible;
  transition: background-color 80ms ease-out, opacity 80ms ease-out;
  /* Icon-buttons highlight their FOREGROUND, never a background box: muted at
     rest, full-brightness glyph on hover (matches the editor rule app-wide). */
  opacity: 0.8;
}

.home-icon-button:disabled {
  cursor: default;
  opacity: 0.4;
}

.home-icon-button:hover:not(:disabled) {
  opacity: 1;
}

.home-icon-button:active:not(:disabled) {
  opacity: 1;
}

.home-icon-button-img {
  height: 28px;
  width: auto;
  user-select: none;
  pointer-events: none;
}

/* Larger variant: shared by the four primary home-page icon buttons
   (Add, Delete, Account, Log Off). Button hit area is 40x40 with 4px
   padding (32x32 inner). The account initial badge fills that inner
   exactly; plus/minus/logout sit at 22px inside the same inner with
   breathing room. */
.home-icon-button-lg {
  width: 40px;
  height: 40px;
  padding: 4px;
}

.home-icon-button-img-lg {
  height: 22px;
}

.account-initial-badge-lg {
  width: 32px;
  height: 32px;
  font-size: 16px;
}

/* Account icon-button (circular initial badge) + its dropdown menu.
   Pattern mirrors the editor TopToolbar's account button. The wrap
   provides a positioning context so the dropdown can be right-aligned
   to the button regardless of surrounding header layout. */
.home-account-wrap {
  position: relative;
  display: inline-flex;
}

.home-account-button {
  outline: 2px solid transparent;
  outline-offset: -2px;
  transition: background-color 80ms ease-out,
    outline-color 80ms ease-out;
}

.home-account-button-active,
.home-account-button-active:hover {
  outline-color: var(--editor-selected-blue);
  opacity: 1;
}

/* Reposition the shared `.account-menu-div` (defaulted for the editor
   TopToolbar at top:44 / right:194) so it drops directly under the
   home-page account button. Use a descendant selector to outrank the
   base single-class rule regardless of stylesheet load order. */
.home-account-wrap .account-menu-div,
.account-menu-div.home-account-menu {
  top: 100%;
  right: 0;
  left: auto;
  margin-top: 4px;
}

/* Main scrollable area: project grid lives here. Padding is symmetric
   on all four sides so the outer whitespace is balanced; tile-to-tile
   gap stays unchanged. */
.home-projects-div {
  flex: 1 1 auto;
  overflow: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  align-content: flex-start;
  gap: 0.75rem;
  padding: 1.25rem;
}

/* Legacy modifier — used to add header clearance when the header was
   fixed. The new layout pins the header with flex, so no extra padding
   is needed. Keeping the class as a no-op (matching the symmetric
   base padding) avoids touching the JSX. */
.home-projects-top {
  padding-top: 1.25rem;
}

.home-project-div {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Project tile: a clickable card. Light mode uses a true-white surface
   so the tile reads against the canvas-gray page; dark mode uses the
   top-toolbar surface so the tile reads as "elevated control" on the
   slightly brighter panel background. */
.home-project-group-div {
  display: block;
  /* +4px on the sides and bottom, +6px on the top, on top of the
     existing 8px base — gives the tile content a bit more room and
     a slightly larger headroom above the thumbnail. */
  padding: 14px 12px 12px;
  border-radius: var(--corner-radius);
  border: 1px solid var(--editor-control-border-color);
  background-color: var(--home-tile-bg, var(--editor-input-bg, #ffffff));
  cursor: default;
}

.home-project-group-div:focus {
  outline: 1px solid var(--editor-selected-blue);
  outline-offset: -1px;
}

.project-img {
  max-width: 220px;
  height: 150px;
  object-fit: contain;
  background-color: var(--home-project-img-bg, #f4f4f4);
}

.project-img-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 220px;
  height: 150px;
  color: var(--home-placeholder-text, #aaa);
  font-size: 0.95rem;
  font-style: italic;
  border: 2px dashed var(--home-placeholder-border, #ccc);
  border-radius: var(--corner-radius-sm);
  box-sizing: border-box;
}

.project-timestamp-p,
.project-descr-p {
  max-width: 220px;
  margin: 4px 4px 0;
  font-size: 0.85rem;
  text-align: left;
  user-select: none;
  word-wrap: break-word;
  color: var(--editor-text-color);
}

.home-status {
  margin: 0;
  padding: 0.75rem 1.5rem;
  color: #c0392b;
  flex: none;
  border-top: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
}

/* Light-mode: main project area matches the editor's canvas surface;
   project tiles use the white "clickable surface" so they pop against
   the gray page. */
html[data-theme="light"] {
  --home-content-bg: var(--canvas-background-color);
  --home-tile-bg: #ffffff;
}

/* Dark-mode: main project area uses the same panel surface as the
   customize page; project tiles take the top-toolbar surface so they
   match the elevated controls on the customize page. */
html[data-theme="dark"] {
  --home-content-bg: var(--editor-panel-background-color);
  --home-tile-bg: var(--top-toolbar-background-color);
  --home-project-img-bg: #14161b;
  --home-placeholder-text: #6f7383;
  --home-placeholder-border: #3a3d46;
}

/* Bug-report / feedback dialog. Matches the app's modal house style
   (centered card on a dimmed backdrop) and is bundled globally via its
   component import. Class names are prefixed so they don't collide. */

.feedback-backdrop {
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 18, 24, 0.55);
    padding: 24px;
}

.feedback-modal {
    width: 100%;
    max-width: 520px;
    background: var(--editor-panel-background-color, #fff);
    color: var(--editor-text-color, #1a1a1f);
    border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.15));
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
    padding: 22px 24px;
    box-sizing: border-box;
}

.feedback-title {
    margin: 0 0 4px;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.feedback-subtitle {
    margin: 0 0 16px;
    font-size: 0.85rem;
    opacity: 0.7;
    line-height: 1.45;
}

/* Bug / Feedback segmented toggle. */
.feedback-kind {
    display: flex;
    gap: 8px;
    margin-bottom: 14px;
}
.feedback-kind-btn {
    flex: 1;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.18));
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.04s ease, filter 0.1s ease, background-color 0.1s ease;
}
.feedback-kind-btn:hover:not(.feedback-kind-active) {
    background-color: rgba(128, 128, 128, 0.12);
}
.feedback-kind-btn:active {
    transform: translateY(1px);
    filter: brightness(0.92);
}
.feedback-kind-active {
    background-color: var(--editor-selected-blue, #3b82f6);
    border-color: var(--editor-selected-blue, #3b82f6);
    color: #fff;
}

.feedback-label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 6px;
}

.feedback-textarea {
    width: 100%;
    min-height: 130px;
    resize: vertical;
    box-sizing: border-box;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.2));
    border-radius: 8px;
    background: var(--editor-input-bg, #fff);
    color: inherit;
    font-family: inherit;
    font-size: 0.92rem;
    line-height: 1.5;
}
.feedback-textarea:focus {
    outline: 2px solid var(--editor-selected-blue, #3b82f6);
    outline-offset: -1px;
}

/* Note that a diagnostic log will be attached (bug reports in the editor). */
.feedback-attach-note {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 12px 0 0;
    font-size: 0.8rem;
    opacity: 0.75;
    line-height: 1.4;
}

.feedback-status {
    margin: 12px 0 0;
    font-size: 0.85rem;
    line-height: 1.4;
}
.feedback-status.is-error { color: #dc2626; }
.feedback-status.is-ok { color: #16a34a; }

.feedback-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 20px;
}

/* Non-blocking thank-you toast shown after a successful send. Pinned to
   the bottom-center, above everything, and dismisses itself after a few
   seconds — no backdrop, no button. */
.feedback-toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%);
    z-index: 10001;
    max-width: min(90vw, 460px);
    padding: 0.7rem 1.1rem;
    border-radius: 10px;
    border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.15));
    background: var(--editor-panel-background-color, #fff);
    color: var(--editor-text-color, #1a1a1f);
    box-shadow: 0 10px 32px rgba(0, 0, 0, 0.32);
    font-size: 0.9rem;
    font-weight: 600;
    text-align: center;
    cursor: default;
    animation: feedback-toast-in 0.18s ease-out;
}

@keyframes feedback-toast-in {
    from { opacity: 0; transform: translate(-50%, 8px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .feedback-toast { animation: none; }
}

/**
 * FS Designer public launch page. Replicates the FS Tracker landing styles
 * EXACTLY (lp-* rules from fs-tracker public/css/style.css) so the two product
 * landings match — same palette, buttons, spacing, cards. Everything is scoped
 * under .fs-landing (the SPA wrapper, which takes over the viewport) so none of
 * it leaks into the editor's own theming.
 */

.fs-landing {
    --bg: #0a1020;
    --surface: #131b2e;
    --text: #f1f5f9;
    --text-secondary: #cbd5e1;
    --text-muted: #94a3b8;
    --line: #1e293b;
    --line-strong: #334155;
    --accent: #3dcf5a;
    --accent-strong: #7fe095;
    --accent-soft: rgba(61, 207, 90, 0.13);
    --btn-primary: linear-gradient(180deg, #57e16d 0%, #2db546 100%);
    --btn-primary-hover: linear-gradient(180deg, #6be57e 0%, #36bf52 100%);
    --btn-primary-text: #1a472a;

    position: fixed;
    inset: 0;
    overflow-y: auto;
    z-index: 0;
    color: var(--text);
    background: linear-gradient(140deg, #1c2740 0%, #0a1020 100%) fixed;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
    -webkit-font-smoothing: antialiased;
}
.fs-landing h1, .fs-landing h2, .fs-landing h3 { font-weight: 700; }
.fs-landing p { margin: 0; }

.fs-landing .lp-wrap { max-width: 1100px; margin: 0 auto; padding: 0 1.5rem; }
.fs-landing .lp-nav { border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 50;
    background: rgba(10, 16, 32, 0.78); backdrop-filter: saturate(180%) blur(10px); }
.fs-landing .lp-nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 2rem; height: 68px; }
.fs-landing .lp-brand { font-weight: 700; font-size: 1.15rem; letter-spacing: 0.01em; color: var(--text); text-decoration: none; }
.fs-landing .lp-nav-links { display: flex; align-items: center; gap: 1.6rem; }
.fs-landing .lp-nav-links a { color: var(--text-secondary); text-decoration: none; font-size: 0.95rem; }
.fs-landing .lp-nav-links a:hover { color: var(--text); }

.fs-landing .lp-btn { display: inline-flex; align-items: center; gap: 0.4rem; border-radius: 10px;
    padding: 0.6rem 1.1rem; font-weight: 600; text-decoration: none; border: 1px solid transparent;
    cursor: pointer; transition: background 140ms ease, border-color 140ms ease, transform 120ms ease, box-shadow 140ms ease; }
.fs-landing .lp-btn-primary { background: var(--btn-primary); color: var(--btn-primary-text);
    box-shadow: 0 8px 24px rgba(45, 181, 70, 0.28); }
.fs-landing .lp-btn-primary:hover { background: var(--btn-primary-hover); color: var(--btn-primary-text); transform: translateY(-1px); }
.fs-landing .lp-btn-ghost { background: transparent; color: var(--text); border-color: var(--text-secondary); }
.fs-landing .lp-btn-ghost:hover { background: var(--text); color: var(--bg); }
.fs-landing .lp-nav-links a.lp-btn-ghost { color: var(--text); }
.fs-landing .lp-nav-links a.lp-btn-ghost:hover { color: var(--bg); }
.fs-landing .lp-nav-links a.lp-btn-primary,
.fs-landing .lp-nav-links a.lp-btn-primary:hover { color: var(--btn-primary-text); }
.fs-landing .lp-btn-lg { padding: 0.85rem 1.5rem; font-size: 1.05rem; }

.fs-landing .lp-eyebrow { display: inline-block; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.12em;
    text-transform: uppercase; color: var(--accent-strong); margin-bottom: 0.9rem; }

.fs-landing .lp-badge { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.85rem;
    border-radius: 999px; background: var(--accent-soft); color: var(--accent-strong);
    font-size: 0.85rem; font-weight: 600; margin-bottom: 1.4rem; }
.fs-landing .lp-badge .pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
    box-shadow: 0 0 0 0 rgba(61, 207, 90, 0.6); animation: lp-pulse 2s infinite; }
@keyframes lp-pulse {
    0% { box-shadow: 0 0 0 0 rgba(61, 207, 90, 0.5); }
    70% { box-shadow: 0 0 0 8px rgba(61, 207, 90, 0); }
    100% { box-shadow: 0 0 0 0 rgba(61, 207, 90, 0); }
}

.fs-landing .lp-hero { position: relative; padding: 6rem 0 4.5rem; text-align: center; overflow: hidden; }
.fs-landing .lp-hero::before { content: ''; position: absolute; top: -25%; left: 50%; transform: translateX(-50%);
    width: 900px; height: 560px; pointer-events: none;
    background: radial-gradient(closest-side, rgba(61, 207, 90, 0.16), rgba(61, 207, 90, 0) 70%); }
.fs-landing .lp-hero > .lp-wrap { position: relative; }
.fs-landing .lp-hero h1 { font-size: 3.1rem; line-height: 1.1; margin: 0 0 1.2rem; letter-spacing: -0.02em; font-weight: 700; }
.fs-landing .lp-hero h1 .lp-accent { color: var(--accent-strong); }
.fs-landing .lp-sub { font-size: 1.2rem; color: var(--text-secondary); max-width: 720px; margin: 0 auto 2rem; line-height: 1.55; }
.fs-landing .lp-cta { display: flex; gap: 0.9rem; justify-content: center; flex-wrap: wrap; }
.fs-landing .lp-cta-note { color: var(--text-muted); font-size: 0.9rem; margin-top: 1rem; }

.fs-landing .lp-features { padding: 4.5rem 0 5rem; border-top: 1px solid var(--line); }
.fs-landing .lp-features-head { text-align: center; margin-bottom: 2.6rem; }
.fs-landing .lp-features-head h2 { font-size: 2rem; margin: 0; letter-spacing: -0.01em; }
.fs-landing .lp-final h2 { font-size: 2rem; margin: 0 0 0.9rem; letter-spacing: -0.01em; }

.fs-landing .lp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.4rem; }
.fs-landing .lp-card { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 1.25rem;
    transition: border-color 160ms ease, transform 160ms ease; }
.fs-landing .lp-card:hover { border-color: var(--accent); transform: translateY(-3px); }
.fs-landing .lp-card h3 { margin: 0.2rem 0 0.5rem; font-size: 1.15rem; color: var(--text); }
.fs-landing .lp-card p { color: var(--text-secondary); margin: 0; line-height: 1.55; font-size: 0.97rem; }
.fs-landing .lp-shot { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; margin-bottom: 1.05rem;
    background: #0c1322; aspect-ratio: 1400 / 720; }
.fs-landing .lp-shot img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.fs-landing .lp-card--text { display: flex; flex-direction: column; justify-content: center;
    background: linear-gradient(180deg, rgba(61, 207, 90, 0.06), transparent); }

/* Large editor showcases — we have only a few, so show them big (near full
   width) for a good look, instead of cramming them into the small cards. */
.fs-landing .lp-showcase { padding: 4.5rem 0; border-top: 1px solid var(--line); }
.fs-landing .lp-show { margin: 0 auto 3.2rem; }
.fs-landing .lp-show:last-child { margin-bottom: 0; }
.fs-landing .lp-show-frame { border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
    background: #0c1322; box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5); }
.fs-landing .lp-show-frame img { display: block; width: 100%; height: auto; }
.fs-landing .lp-show figcaption { text-align: center; margin-top: 1.15rem; }
.fs-landing .lp-show figcaption h3 { font-size: 1.3rem; margin: 0 0 0.4rem; }
.fs-landing .lp-show figcaption p { color: var(--text-secondary); max-width: 640px; margin: 0 auto; line-height: 1.55; }

.fs-landing .lp-final { background: var(--surface); border-top: 1px solid var(--line); padding: 4.5rem 0; text-align: center; }
.fs-landing .lp-final p { color: var(--text-secondary); margin: 0 0 1.8rem; font-size: 1.12rem; }

.fs-landing .lp-foot { border-top: 1px solid var(--line); padding: 1.75rem 0; color: var(--text-muted); font-size: 0.9rem; }
.fs-landing .lp-foot .lp-wrap { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
.fs-landing .lp-foot a { color: var(--text-secondary); text-decoration: none; }
.fs-landing .lp-foot a:hover { color: var(--text); }

@media (max-width: 720px) {
    .fs-landing .lp-hero { padding: 4rem 0 3rem; }
    .fs-landing .lp-hero h1 { font-size: 2.1rem; }
    .fs-landing .lp-sub { font-size: 1.08rem; }
}

/* Styles for the in-app documentation site at /docs/*.
 * Reuses the tokens defined in App.css so light/dark themes apply
 * automatically through the existing data-theme attribute. */

.docs-page {
    /* Fill the .App frame instead of claiming 100vh. .App is
       position:absolute; overflow:hidden, so a 100vh child would push
       content past the clip and the system chrome could overlap the
       bottom. Anchored fills give the inner .docs-content a bounded
       height to scroll within. */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--editor-panel-background-color, #fff);
    color: var(--editor-text-color, #333);
    font-family: var(--editor-font-family, "Arial", sans-serif);
}

/* ----- Header ----- */
.docs-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.9rem 1.4rem;
    border-bottom: 1px solid var(--editor-panel-separator-color, #ececec);
}

.docs-back-controls {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.docs-back-button {
    background: transparent;
    border: none;
    color: var(--editor-text-color);
    cursor: pointer;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    /* Driven by Customize > Corner roundness. --corner-radius spans 0px
       (square) to 16px (a full circle for this 32x32 button), so the
       button visibly follows the user's preference: subtly rounded at
       the default 0.5, fully circular at the max. */
    border-radius: var(--corner-radius, 8px);
    transition: opacity 80ms ease-out, color 80ms ease-out;
    /* Icon-button foreground-highlight rule: muted at rest, full on hover, no bg. */
    opacity: 0.8;
}

.docs-back-button:hover,
.docs-back-button:active {
    opacity: 1;
}

/* Granular back: smaller, lighter sibling of the major back button. Steps
   back through doc topics; disabled once we're at the entry topic. */
.docs-back-button-granular {
    width: 28px;
    height: 28px;
}

.docs-back-button-granular:disabled {
    opacity: 0.35;
    cursor: default;
}

.docs-back-button-granular:disabled:hover {
    background-color: transparent;
}

.docs-back-icon {
    display: block;
    pointer-events: none;
}

.docs-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--header-1-color, #2a2935);
}

/* Push the audience switcher to the right end of the header. */
.docs-header > .docs-audience-switch {
    margin-left: auto;
}

/* Three-segment audience switcher. */
.docs-audience-switch {
    display: inline-flex;
    border: 1px solid var(--editor-control-border-color, #d0d0d0);
    border-radius: var(--corner-radius, 6px);
    overflow: hidden;
}

.docs-audience-button {
    background: transparent;
    border: none;
    padding: 0.45rem 0.95rem;
    color: var(--editor-text-color);
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    border-right: 1px solid var(--editor-control-border-color, #d0d0d0);
    transition: background-color 80ms ease-out, color 80ms ease-out;
}

.docs-audience-button:last-child {
    border-right: none;
}

.docs-audience-button:hover {
    background-color: rgba(16, 151, 226, 0.12);
    color: var(--editor-selected-blue, rgb(16, 151, 226));
}

.docs-audience-button:active {
    background-color: rgba(16, 151, 226, 0.22);
}

.docs-audience-button-active,
.docs-audience-button-active:hover {
    background-color: var(--editor-selected-blue, rgb(16, 151, 226));
    color: #fff;
}

.docs-audience-button-active:active {
    background-color: rgb(13, 121, 181);
}

/* ----- Account button + dropdown ----- */
.docs-account-button {
    background: transparent;
    border: none;
    padding: 4px;
    margin-left: 0.6rem;
    border-radius: var(--corner-radius, 6px);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: opacity 80ms ease-out, outline-color 80ms ease-out;
    outline: 2px solid transparent;
    outline-offset: -2px;
    /* Icon-button foreground-highlight rule: muted at rest, full on hover, no bg. */
    opacity: 0.8;
}

.docs-account-button:hover,
.docs-account-button:active {
    opacity: 1;
}

.docs-account-button-active,
.docs-account-button-active:hover {
    outline-color: var(--editor-selected-blue, rgb(16, 151, 226));
    opacity: 1;
}

/* Reposition the shared `.account-menu-div` for the docs header. Defaults
 * in App.css target the editor's TopToolbar; we want the menu to drop
 * under the account button at the right edge of the docs header. The
 * compound selector outranks the base single-class rule regardless of
 * stylesheet load order. */
.account-menu-div.docs-account-menu {
    top: 56px;
    right: 1.4rem;
    left: auto;
}

/* ----- Body grid ----- */
.docs-body {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 0;
    flex: 1;
    min-height: 0;
}

/* ----- Sidebar ----- */
.docs-sidebar {
    padding: 1.2rem 1rem 2rem;
    border-right: 1px solid var(--editor-panel-separator-color, #ececec);
    overflow-y: auto;
}

.docs-sidebar-home {
    display: block;
    padding: 0.4rem 0.6rem;
    margin-bottom: 1rem;
    color: var(--editor-text-color);
    text-decoration: none;
    font-weight: 600;
    border-radius: var(--corner-radius-sm, 4px);
    transition: background-color 80ms ease-out, color 80ms ease-out;
}

.docs-sidebar-home:hover {
    background-color: rgba(16, 151, 226, 0.10);
    color: var(--editor-selected-blue, rgb(16, 151, 226));
}

.docs-sidebar-home:active {
    background-color: rgba(16, 151, 226, 0.20);
}

.docs-sidebar-home.active {
    background-color: rgba(16, 151, 226, 0.14);
    color: var(--editor-selected-blue, rgb(16, 151, 226));
}

.docs-sidebar-section {
    margin-bottom: 1.2rem;
}

.docs-sidebar-section-heading {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--header-3-color, #6f6e7c);
    padding: 0 0.6rem;
    margin-bottom: 0.35rem;
}

.docs-sidebar-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.docs-sidebar-link {
    display: block;
    padding: 0.35rem 0.6rem;
    color: var(--editor-text-color);
    text-decoration: none;
    font-size: 0.9rem;
    border-radius: var(--corner-radius-sm, 4px);
    transition: background-color 80ms ease-out, color 80ms ease-out;
}

.docs-sidebar-link:hover {
    background-color: rgba(16, 151, 226, 0.10);
    color: var(--editor-selected-blue, rgb(16, 151, 226));
}

.docs-sidebar-link:active {
    background-color: rgba(16, 151, 226, 0.22);
}

.docs-sidebar-link-active,
.docs-sidebar-link-active:hover {
    background-color: rgba(16, 151, 226, 0.14);
    color: var(--editor-selected-blue, rgb(16, 151, 226));
    font-weight: 600;
}

.docs-sidebar-link-active:active {
    background-color: rgba(16, 151, 226, 0.26);
}

/* ----- Content ----- */
.docs-content {
    padding: 2rem 2.4rem 4rem;
    overflow-y: auto;
}

.docs-article {
    max-width: 760px;
    line-height: 1.55;
}

.docs-article h1 {
    margin: 0 0 1.1rem;
    font-size: 1.9rem;
    font-weight: 700;
    color: var(--header-1-color, #2a2935);
}

.docs-article h2 {
    margin: 2rem 0 0.6rem;
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--header-2-color, #3b3a45);
}

.docs-article h3 {
    margin: 1.4rem 0 0.45rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--header-2-color, #3b3a45);
}

.docs-article p {
    margin: 0.55rem 0 1rem;
}

.docs-article ul,
.docs-article ol {
    margin: 0.55rem 0 1rem;
    padding-left: 1.4rem;
}

.docs-article li {
    margin: 0.3rem 0;
}

.docs-article code {
    background-color: rgba(0, 0, 0, 0.05);
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    font-family: "Menlo", "Consolas", monospace;
    font-size: 0.88em;
}

.docs-article pre {
    background-color: rgba(0, 0, 0, 0.06);
    padding: 0.9rem 1rem;
    border-radius: var(--corner-radius-sm, 4px);
    overflow-x: auto;
    line-height: 1.4;
}

.docs-article pre code {
    background: none;
    padding: 0;
}

.docs-article kbd {
    display: inline-block;
    padding: 0.05rem 0.45rem;
    background-color: var(--editor-panel-background-color, #fff);
    border: 1px solid var(--editor-control-border-color, #d0d0d0);
    border-bottom-width: 2px;
    border-radius: 3px;
    font-family: "Menlo", "Consolas", monospace;
    font-size: 0.82em;
    color: var(--editor-text-color);
}

/* Inline links inside article body — including the audience-mismatch
 * "Overview" link and any future cross-references. */
.docs-article a {
    color: var(--editor-selected-blue, rgb(16, 151, 226));
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    transition: color 80ms ease-out, background-color 80ms ease-out;
}

.docs-article a:hover {
    color: rgb(13, 121, 181);
    background-color: rgba(16, 151, 226, 0.08);
}

.docs-article a:active {
    color: rgb(9, 92, 138);
    background-color: rgba(16, 151, 226, 0.18);
}

/* ----- Landing-page extras ----- */
.docs-lead {
    font-size: 1.05rem;
    color: var(--editor-text-color);
}

.docs-audience-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin: 1.5rem 0 2rem;
}

.docs-audience-card {
    flex: 1 1 0;
    min-width: 0;
    text-align: left;
    font: inherit;
    color: inherit;
    border: 1px solid var(--editor-panel-separator-color, #ececec);
    border-radius: var(--corner-radius, 6px);
    padding: 0.85rem 0.95rem;
    background-color: rgba(0, 0, 0, 0.015);
    cursor: pointer;
    transition: background-color 80ms ease-out, border-color 80ms ease-out,
        box-shadow 80ms ease-out;
}

.docs-audience-card:hover {
    background-color: rgba(16, 151, 226, 0.06);
    border-color: var(--editor-selected-blue, rgb(16, 151, 226));
}

.docs-audience-card:active {
    background-color: rgba(16, 151, 226, 0.14);
}

.docs-audience-card h3 {
    margin: 0 0 0.3rem;
    font-size: 1rem;
}

.docs-audience-card p {
    margin: 0;
    font-size: 0.9rem;
    color: var(--header-3-color, #6f6e7c);
}

.docs-audience-card-active,
.docs-audience-card-active:hover {
    border-color: var(--editor-selected-blue, rgb(16, 151, 226));
    background-color: rgba(16, 151, 226, 0.08);
}

.docs-topic-group {
    margin: 1rem 0 1.6rem;
}

.docs-topic-group-heading {
    margin: 0 0 0.4rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--header-3-color, #6f6e7c);
    border-bottom: 1px solid var(--editor-panel-separator-color, #ececec);
    padding-bottom: 0.3rem;
}

.docs-topic-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.docs-topic-list li {
    padding: 0.35rem 0;
}

.docs-topic-list a {
    color: var(--editor-selected-blue, rgb(16, 151, 226));
    text-decoration: none;
    font-weight: 500;
    padding: 0.15rem 0.35rem;
    margin: 0 -0.35rem;
    border-radius: var(--corner-radius-sm, 4px);
    transition: background-color 80ms ease-out, color 80ms ease-out;
}

.docs-topic-list a:hover {
    text-decoration: underline;
    background-color: rgba(16, 151, 226, 0.08);
}

.docs-topic-list a:active {
    background-color: rgba(16, 151, 226, 0.18);
    color: rgb(13, 121, 181);
}

/* ----- Audience-mismatch hint ----- */
.docs-audience-mismatch {
    border: 1px dashed var(--editor-control-border-color, #d0d0d0);
    border-radius: var(--corner-radius, 6px);
    padding: 1rem 1.2rem;
    color: var(--header-3-color, #6f6e7c);
    background-color: rgba(0, 0, 0, 0.02);
}

.docs-audience-inline-switch {
    background: transparent;
    border: none;
    padding: 0;
    color: var(--editor-selected-blue, rgb(16, 151, 226));
    cursor: pointer;
    font: inherit;
    font-weight: 600;
    text-decoration: underline;
    transition: color 80ms ease-out;
}

.docs-audience-inline-switch:hover {
    color: rgb(13, 121, 181);
}

.docs-audience-inline-switch:active {
    color: rgb(9, 92, 138);
}

/* ----- Tables (keyboard shortcuts) ----- */
.docs-shortcut-table {
    border-collapse: collapse;
    margin: 0.6rem 0 1.4rem;
    width: 100%;
}

.docs-shortcut-table th,
.docs-shortcut-table td {
    text-align: left;
    padding: 0.45rem 0.7rem;
    border-bottom: 1px solid var(--editor-panel-separator-color, #ececec);
    vertical-align: top;
}

.docs-shortcut-table th {
    font-weight: 600;
    color: var(--header-2-color, #3b3a45);
    background-color: rgba(0, 0, 0, 0.025);
}

/* ----- FAQ ----- */
.docs-faq {
    margin: 0.6rem 0 0;
}

.docs-faq-item {
    padding: 0.9rem 0;
    border-bottom: 1px solid var(--editor-panel-separator-color, #ececec);
}

.docs-faq dt {
    font-weight: 600;
    color: var(--header-2-color, #3b3a45);
    margin-bottom: 0.35rem;
}

.docs-faq dd {
    margin: 0;
}

/* ----- Narrow viewports: collapse sidebar ----- */
@media (max-width: 760px) {
    .docs-body {
        grid-template-columns: 1fr;
    }
    .docs-sidebar {
        border-right: none;
        border-bottom: 1px solid var(--editor-panel-separator-color, #ececec);
        padding: 0.8rem 1rem;
    }
    .docs-content {
        padding: 1.4rem 1.2rem 3rem;
    }
    .docs-header {
        flex-wrap: wrap;
        gap: 0.7rem;
    }
}

/* Callout box in a docs article (e.g. an "Experimental" warning). */
.docs-callout {
    padding: 0.7rem 0.9rem;
    border-radius: 8px;
    line-height: 1.5;
}
.docs-callout-warn {
    color: var(--editor-text-color, #1a1a1f);
    background: color-mix(in srgb, #f5a623 12%, transparent);
    border: 1px solid color-mix(in srgb, #f5a623 42%, transparent);
}

/* Verify-email banner anchored at the top of the viewport above all
 * other content. position: fixed + z-index keeps it above the editor
 * canvas and other absolute-positioned page chrome. */

.verify-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.45rem 0.9rem;
    background-color: #f59e0b;
    color: #1f1100;
    font-size: 0.88rem;
    font-weight: 500;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}

.verify-banner-text { flex: 1 1 auto; }

.verify-banner-button {
    appearance: none;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: var(--corner-radius-sm, 4px);
    background-color: #0a1020;
    color: #ffffff;
    padding: 0.3rem 0.75rem;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

.verify-banner-button:hover:not(:disabled) {
    background-color: #131b2e;
}

.verify-banner-button:disabled {
    opacity: 0.55;
    cursor: default;
}

.verify-banner-status {
    font-size: 0.82rem;
    opacity: 0.85;
}

/* Full-screen overlay shown when the backend server is unreachable.
   It sits above every route via a high z-index so it covers the editor,
   home page, etc. without unmounting them — the user's work is preserved
   underneath and reappears on reconnect. The background is fully opaque
   so the page behind it (login screen, editor, etc.) is hidden: it can't
   be interacted with while offline and is irrelevant until reconnect.
   Colors come from editor theme variables to match the active theme. */

.disconnected-page {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--editor-panel-background-color, #1e1e1e);
  color: var(--editor-text-color, #eee);
  font-family: var(--editor-font-family, Arial, Helvetica, sans-serif);
}

/* Content sits in a bordered box that is darker than the page behind
   it, so it reads as a distinct panel rather than blending into the
   surrounding background. */
.disconnected-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
  width: 22rem;
  max-width: 90vw;
  padding: 2.5rem 2rem;
  border: 1px solid var(--editor-control-border-color, #444);
  border-radius: 12px;
  background-color: var(--editor-input-bg, #15171c);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  text-align: center;
}

/* Spinning accent ring — gives the screen motion and signals that
   reconnection is actively in progress. */
.disconnected-spinner {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 3px solid var(--editor-control-border-color, #444);
  border-top-color: var(--editor-selected-blue, #1097e2);
  animation: disconnected-spin 0.9s linear infinite;
}

@keyframes disconnected-spin {
  to { transform: rotate(360deg); }
}

.disconnected-heading {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
}

.disconnected-message {
  margin: 0;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--editor-muted-text-color, #8e8c9e);
}

/* Matches the standard `.buttons` style used on the login/signup pages. */
.disconnected-retry {
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  margin-top: 0.25rem;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius);
  cursor: pointer;
  background-color: var(--button-bg);
  color: var(--button-text);
}

.disconnected-retry:hover:not(:disabled) {
  background-color: var(--button-bg-hover);
}

.disconnected-retry:disabled {
  opacity: 0.55;
  cursor: default;
}

.disconnected-attempts {
  margin: 0;
  font-size: 0.8rem;
  color: var(--editor-muted-text-color, #8e8c9e);
}

/* Editor design tokens shared by toolbar, panels, and canvas layout. */
:root {
  --tree-width: 255px;
  --details-width: 320px;
  --standard-icon-height: 48px;
  --standard-icon-width: 44px;
  --top-toolbar-height: 48px;
  --left-toolbar-width: 82px;
  --chevron-left: 37px;
  --top-toolbar-left-of-zoom-icons: 120px;
  --top-toolbar-background-color: #282c34;
  --left-toolbar-background-color: #d8d6d6;
  --toolbar-text-color: #dedede;
  --editor-text-color: #5A5964;
  --editor-muted-text-color: #8e8c9e;
  /* header-1 is the most-prominent header; it must be DARKER than the
     panel background in light mode. Old #f4f4f6 was a stray dark-mode
     value that rendered tab text white-on-white. */
  --header-1-color: #2a2935;
  --header-2-color: #3b3a45;
  --header-3-color: #6f6e7c;
  --editor-panel-background-color: white;
  --editor-panel-separator-color: #ececec;
  --editor-control-border-color: #cccbd8;
  --editor-control-border: 1px solid var(--editor-control-border-color);
  --editor-selected-blue: rgb(16, 151, 226);
  /* Per-panel theme accents (each user-configurable in Customize): code green,
     data magenta, prototype amber. Lightened in dark mode for contrast. */
  --code-accent: #15825a;
  --data-accent: #b0208a;
  --prototype-accent: #e07b39;
  /* A filled solid code button uses --code-accent-btn (a muted green that never
     glares) with white --code-accent-fg text. --code-accent itself stays for accent
     TEXT / lines, which need to stay bright on the dark canvas in dark mode. */
  --code-accent-btn: #15825a;
  --code-accent-fg: #fff;
  /* Same split for prototype: --prototype-accent (a light amber) is used for
     accent TEXT / borders / icons, but white text on it fails contrast on a
     filled button — so filled prototype buttons use the darker
     --prototype-accent-btn with white --prototype-accent-fg text (≈4.8:1). */
  --prototype-accent-btn: #b8560f;
  --prototype-accent-fg: #fff;
  /* Subtle 1px hairline for code-view chrome (the editor ↔ console separator, etc.). */
  --editor-border-color: rgb(200, 200, 200);
  --editor-hover-color: #5fd8c0;
  --editor-constraint-line-color: #b2b2b2;
  /* Reference-point badge — kept in sync (by applyPreferences) with the same
     referenceBadgeColor / referenceBadgeAccent options that drive the on-canvas
     marker, so the panel mirror and the canvas badge always match. */
  --reference-badge-color: #29e06c;
  --reference-badge-accent: #1097e2;
  --tools-group-columns: 2;
  --canvas-background-color: var(--editor-panel-separator-color);
  --panel-border-color: rgb(200, 200, 200);
  --tree-selection-bg: rgb(194, 232, 255);
  /* Clickable / editable surface — true white in light mode so buttons
     and inputs stand out against the now-grayish page background.
     Dark mode redefines this further down. */
  --editor-input-bg: #ffffff;
  /* Code-editor pane syntax-highlight palette (light theme). */
  --syn-comment: #6a9955;
  --syn-keyword: #0f3fbd;
  --syn-string: #a3402a;
  --syn-number: #098658;
  --syn-boolean: #0f3fbd;
  --syn-tag: #7a1f1f;
  --syn-attr: #7a4a12;
  --syn-prop: #0451a5;
  --syn-punct: #6b6b76;
  --editor-font-family: Arial, Helvetica, sans-serif;
  --editor-control-font-size: 14px;
  /* Shared height for panel edit boxes + drop-downs: line-height + 2·pad-y +
     2·border ≈ 24px. Kept as line-height/padding (not an explicit `height`) so
     control widths and box-sizing are never disturbed. */
  --editor-control-line-height: 20px;
  --editor-control-pad-y: 2px;
  --editor-icon-muted-opacity: 0.6;
  --editor-small-icon-size: 18px;
  --editor-swatch-size: 18px;
  /* Design-panel row spacing. Rows HUG their content (whatever their tallest
     component needs); the space BETWEEN rows is standardized to --details-row-gap
     via symmetric top/bottom padding of half that on each row, so adjacent rows
     sit exactly --details-row-gap apart. EVERY stacked element must carry this
     half-padding — a row (or graphic block) that omits it only gets its
     neighbour's half, reading as gap/2. Set by the "Inter-row gap" Customize
     control (preferences.ts overrides --details-row-gap at runtime). */
  --details-row-gap: 12px;
  --details-row-pad: calc(var(--details-row-gap) / 2);
  /* List / tree-view row spacing — the same hug-plus-half-padding scheme as
     --details-row-gap, but a SEPARATE knob so dense name lists (Pages / Layers,
     the item / data / prototype / files trees, asset lists, prototype-panel
     lists) can be tighter than the design-panel form rows. Set by the "List &
     tree-view row gap" Customize control (preferences.ts overrides it at
     runtime); defaults a little tighter than --details-row-gap. */
  --list-row-gap: 8px;
  --list-row-pad: calc(var(--list-row-gap) / 2);
  --details-content-width: calc(var(--details-width) - var(--panel-indent));
  --panel-edge-gap: 8px;
  --panel-triangle-size: 12px;
  --panel-triangle-title-gap: 4px;
  /* Single indent step. Level N content lives at N * --panel-indent from the
     panel's left edge. Disclosure triangles for Level N occupy the band from
     (N-1)*panel-indent to N*panel-indent. The 12px image is offset 1px to
     the right of the band's natural center, so the left/right padding around
     it is 7/10 — visible room on each side, slight rightward weight. */
  --panel-indent: 28px;
  --panel-level-2: calc(2 * var(--panel-indent));
  --panel-level-3: calc(3 * var(--panel-indent));
  --panel-triangle-pad-left: 8px;
  --panel-triangle-pad-right: 8px;
  /* Legacy alias — now tracks the single inter-row gap so every row-spacing
     mechanism (flex row-gap, row padding) resolves to one value. */
  --panel-row-gap: var(--details-row-gap);
  --panel-control-gap: 6px;
  --panel-pair-gap: 20px;
  --panel-right-gutter: 12px;
  --panel-checkbox-label-gap: 8px;
  /* Default status-bar height. Overridden by preferences.ts: set to
     0px when the bar is hidden, ~26px when it's visible. Editor panels
     anchor their bottom edges to this value. */
  --status-bar-height: 26px;
  /* Justification of numeric edit boxes. Overridden by preferences.ts. */
  --number-input-align: right;
  /* Corner radii driven by the corner-roundness slider (preferences.ts);
     0px at the square end. */
  --corner-radius: 8px;
  --corner-radius-sm: 3px;
  /* Selection outline/border width for selectable icons. */
  --selection-border-width: 2px;
  /* Action-button surface. Light mode uses a light grey (not white)
     with dark-enough text; dark mode overrides below. */
  --button-bg: #e6e6ea;
  --button-bg-hover: #d8d8de;
  --button-text: #45444e;
}

/* Root application frame. */
p {
  font-size: var(--editor-control-font-size);
}

.App {
  position: absolute;
  overflow: hidden;
  /* The verify-email banner is position: fixed at the viewport top; push
     .App (and every absolute-positioned page inside it) down by the
     banner's height so it doesn't cover the home header / editor top
     toolbar. The variable is set by VerifyBanner when visible, removed
     when hidden — defaulting to 0 keeps every other page intact. */
  top: var(--verify-banner-height, 0px);
  bottom: 0px;
  left: 0px;
  right: 0px;
  background-color: var(--editor-panel-background-color);
}

/* Top toolbar: navigation, project metadata, zoom controls, and account actions. */
/* Home, Tracker and the logo flow relatively in the toolbar's flexbox (see the
   relative-positioning rule below); no per-button left offsets. */
.home-icon {
  position: relative;
}

.tracker-icon {
  position: relative;
}

.logo-icon {
  height: 30px;
  display: block;
}

/* File menu, opened by the top-toolbar logo button. Sits just below the
   toolbar, left-aligned under the logo. */
.logo-menu-div {
  position: absolute;
  top: 44px;
  left: 84px;
  width: 180px;
  z-index: 60;
  padding: 4px 0;
  color: var(--toolbar-text-color);
  background-color: var(--top-toolbar-background-color);
  border-radius: var(--corner-radius-sm);
  border: 1px solid rgba(0, 0, 0, 0.45);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.13), 0 4px 12px rgba(0, 0, 0, 0.35);
}

.logo-menu-item-div {
  padding: 6px 14px;
  cursor: pointer;
}

.logo-menu-item-div:hover {
  background-color: rgba(255, 255, 255, 0.14);
}

.logo-menu-item-div p {
  font-family: var(--editor-font-family);
  font-size: 10pt;
  margin: 0;
  text-align: left;
  user-select: none;
}

.top-toolbar-text {
  color: var(--toolbar-text-color);
  font-family: var(--editor-font-family);
  font-size: 10pt;
  margin: 0px;
}

/* Transparent full-screen layer behind an open top-toolbar menu — a click
   anywhere off the menu lands here and closes it. */
.menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 55;
}

/* Account dropdown, opened by the top-toolbar user icon. Sits just below
   the toolbar, horizontally centred under the user icon: the icon button
   spans right 266..302px (.user-icon right: 266px + .tt-btn 36px wide), so
   its centre is at right 284px; a 180px-wide menu centred there starts at
   right 194px. */
.account-menu-div {
  position: absolute;
  top: 44px;
  right: 194px;
  width: 180px;
  z-index: 60;
  padding: 4px 0;
  color: var(--toolbar-text-color);
  background-color: var(--top-toolbar-background-color);
  border-radius: var(--corner-radius-sm);
  border: 1px solid rgba(0, 0, 0, 0.45);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.13), 0 4px 12px rgba(0, 0, 0, 0.35);
}

.account-menu-item-div {
  padding: 6px 14px;
  cursor: pointer;
}

/* Version label at the foot of the account menu; clickable to open What's New. */
.account-menu-version {
  padding: 6px 14px 4px;
  margin-top: 4px;
  border-top: 1px solid var(--panel-border-color, rgba(255, 255, 255, 0.14));
  font-family: var(--editor-font-family);
  font-size: 9pt;
  text-align: left;
  opacity: 0.55;
  user-select: none;
  cursor: pointer;
}
.account-menu-version:hover {
  opacity: 0.9;
}

/* What's New dialog content (shell reuses the feedback modal). */
.whatsnew-list {
  max-height: 55vh;
  overflow-y: auto;
  margin: 10px 0;
}
.whatsnew-entry {
  margin-bottom: 14px;
}
.whatsnew-version {
  font-weight: 600;
  margin-bottom: 4px;
}
.whatsnew-notes {
  margin: 0;
  padding-left: 18px;
}
.whatsnew-notes li {
  margin: 3px 0;
}

.account-menu-item-div:hover {
  background-color: rgba(255, 255, 255, 0.14);
}

.account-menu-item-div p {
  font-family: var(--editor-font-family);
  font-size: 10pt;
  margin: 0;
  text-align: left;
  user-select: none;
}

.project-name-textbox {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  font-size: 13pt;
  font-weight: 600;
  padding: 0;
  background-color: var(--top-toolbar-background-color)
}

/* Project name flows in .project-info's flex column (justify-center), so it
   sits vertically centred in the toolbar. Bigger than the surrounding toolbar
   text to read as the document title. */
.project-name {
  position: relative;
  font-size: 13pt;
  font-weight: 600;
  line-height: 1.1;
}

.zoom-percentage {
  position: relative;
  user-select: none;
}

.zoom-percentage-textbox {
  /* In-flow (not absolute) so the flex cluster's align-items:center vertically
     centers the edit box in the toolbar — exactly like the static % readout it
     replaces. When absolute, the auto-height .zoom-text-div collapsed and the
     box hung below the centerline. */
  width: 100%;
  padding: 0;
  box-sizing: border-box;
  background-color: var(--top-toolbar-background-color);
  text-align: center;
}

/* Right-side toolbar cluster. Element right-edge offsets are tuned so the
   36px icon buttons, the share button, and the zoom read-out all sit 8px
   apart. Order from the right edge: zoom −, zoom %, zoom +, play, share,
   user, notifications, help. */
.zoom-text-div {
  position: absolute;
  top: 17px;
  right: 56px;
  text-align: center;
  width: 50px;
  height: 50px;
}

.zoom-minus-icon {
  position: absolute;
  right: 114px;
  user-select: none;
}

.zoom-plus-icon {
  position: absolute;
  right: 12px;
  user-select: none;
}

.play-icon {
  position: absolute;
  top: 0;
  right: 158px;
}
/* The inlined play glyph strokes with currentColor so it tracks the configurable Prototype
   accent — the one toolbar button with a colour of its own, because Play IS the prototype.
   Qualified with .tt-btn ON PURPOSE: .tt-btn sets `color` too (further down this file, so it
   wins at equal specificity) to stop the UA's default button colour reaching the glyphs, and
   that quietly turned the play triangle into an ordinary toolbar grey. */
.tt-btn.play-icon {
  color: var(--prototype-accent);
}

/* Share button in the editor's top toolbar. Presented as a plain text
   glyph on the toolbar background — no fill or border — with the same
   size, radius, and hover/active highlight as the icon buttons
   (.tt-btn), so it reads as one of the same family of controls. */
.share-button {
  position: absolute;
  top: 6px;
  right: 202px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 36px;
  padding: 0;
  margin: 0;
  border: none;
  background-color: transparent;
  border-radius: var(--corner-radius);
  font-family: var(--editor-font-family);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--toolbar-text-color);
  cursor: pointer;
  user-select: none;
  -webkit-appearance: none;
  appearance: none;
}

.share-button:hover {
  background-color: rgba(255, 255, 255, 0.14);
}

.share-button:active {
  background-color: rgba(255, 255, 255, 0.22);
}

.user-icon {
  position: absolute;
  top: 0;
  right: 266px;
}

/* Circular initial badge inside the account button. Matches the size and
   fill of the previous static user.svg circle so the toolbar layout is
   unchanged, but the letter is the signed-in user's first initial. */
.account-initial-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* A hollow white circle at the standard toolbar-icon height and line width,
     like the other glyphs — with the initial letter also the standard white.
     The border matches the shared 3px glyph stroke. */
  width: 23px;
  height: 23px;
  border-radius: 50%;
  background-color: transparent;
  border: 3px solid var(--toolbar-text-color);
  color: var(--toolbar-text-color);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  user-select: none;
}

.notifications-icon {
  position: absolute;
  top: 0;
  right: 310px;
}

/* Help-mode toggle, sat just left of the notifications icon. */
.help-mode-icon {
  position: absolute;
  top: 0;
  right: 354px;
  cursor: pointer;
}

/* The Boss-area crown — only rendered when the signed-in user is a
   Boss, so the slot is empty for everyone else and the other right-
   cluster icons keep their existing positions. Sits just left of the
   help-mode toggle. */
.boss-icon {
  position: absolute;
  top: 0;
  right: 398px;
}

/* When help mode is active the question-mark button stays highlighted. */
/* Button-like container for the clickable top-toolbar icons. It is inset
   from the toolbar's top and bottom — leaving roughly equal space above and
   below — and rounds with the corner-roundness preference, like the
   left-toolbar tools. The icon image keeps its own size and is allowed to
   overflow the (transparent) button box. */
.tt-btn {
  /* A <button> does NOT inherit `color` — the UA sets its own (white under a dark
     colour-scheme, black under a light one). The inline SVG glyphs stroke with
     `currentColor`, so without this they came out #fff next to their #dedede
     siblings in dark mode, and BLACK on this permanently-dark toolbar in light
     mode. Anchor it to the toolbar's own text token so every glyph matches. */
  color: var(--toolbar-text-color);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  top: 6px;
  padding: 0;
  margin: 0;
  border: none;
  background-color: transparent;
  border-radius: var(--corner-radius);
  cursor: pointer;
  overflow: visible;
  -webkit-appearance: none;
  appearance: none;
  /* App-wide rule: icon-buttons highlight their FOREGROUND, never a background
     box. Muted at rest, full-brightness glyph on hover (matches the tool / panel
     / align icons). */
  opacity: 0.8;
  transition: opacity 0.1s ease;
}

.tt-btn > img {
  display: block;
}

/* Theme switcher, centred in the toolbar independent of the left/right group widths. */
.top-toolbar-center {
  position: absolute;
  left: 50%;
  top: 6px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
}
.tt-btn.tt-btn-disabled {
  opacity: 0.35;
  cursor: default;
}
.tt-btn.tt-btn-disabled:hover {
  opacity: 0.35;
}

.tt-btn:hover {
  opacity: 1;
}

/* A toggled top-toolbar button stays highlighted while its state is on,
   marked with a selection-coloured border like a selected tool — the
   help-mode toggle while help mode is on, and the account button while
   its menu is open. */
.help-mode-icon-active,
.help-mode-icon-active:hover,
.user-icon-active,
.user-icon-active:hover,
.logo-btn-active,
.logo-btn-active:hover {
  /* Toggled-on state: a selection-blue outline (structural), full-brightness
     glyph, and NO background fill — consistent with the foreground-only rule. */
  opacity: 1;
  outline: var(--selection-border-width) solid var(--editor-selected-blue);
  outline-offset: calc(-1 * var(--selection-border-width));
}

/* Logo button: an icon-button in the same family as the other top-toolbar
   buttons, but width-hugging the (wider-than-tall) logo image. Sits just
   right of the home button and opens the File menu. */
.logo-btn {
  position: relative;
  width: auto;
  padding: 0 8px;
}

/* Icon sizing for the small zoom buttons. */
.tt-zoom-icon {
  height: 16px;
  user-select: none;
}

.standard-top-toolbar-icon {
  /* Rendered at exactly the base height so the 48-unit viewBox maps 1 unit = 1px
     — a clean pixel grid, so axis-aligned strokes stay crisp. The larger "+2px"
     sizing is baked into each glyph's own coordinates (not a CSS scale), so no
     glyph lands on fractional pixels. */
  height: var(--standard-icon-height);
  user-select: none;
}
/* The bug glyph fills more of its 44x48 canvas than the sibling toolbar icons,
   so at the standard height it reads taller — trim it to match the others.
   The glyph also sits high in its canvas (more empty space below than above),
   so nudge it down ~1px to sit vertically centred in the button. */
.bug-icon img {
  height: calc(var(--standard-icon-height) * 0.84);
  transform: translateY(1px);
}

.home-div {
  position: absolute;
  top: 0;
  left: 0;
  user-select: none;
}

.top-toolbar {
  position: absolute;
  box-sizing: border-box;
  background-color: var(--top-toolbar-background-color);
  height: var(--top-toolbar-height);
  width: 100%;
  border-bottom: 1px solid var(--panel-border-color, var(--editor-panel-separator-color));
  /* Above the editor panels and their resize handles (z-index 10..30) so
     the toolbar's dropdown menus (logo / account) layer on top of them. */
  z-index: 40;
  /* Dynamic layout: a left group and a right group flow and space
     themselves instead of being pinned at fixed pixel offsets. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 8px;
  gap: 8px;
}

/* Left group (Home, Tracker, Logo, project info) and right group (Help,
   Notifications, Account, Share, Play, zoom). */
.top-toolbar-group {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* Wraps a menu-trigger button (logo / account) so its dropdown anchors to it. */
.tt-menu-anchor {
  position: relative;
  display: flex;
  align-items: center;
}

/* Zoom out / readout / zoom in, kept together. */
.tt-zoom-cluster {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Project name + date stacked just right of the logo. */
.project-info {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin-left: 4px;
  min-width: 120px;
}

/* The left-side buttons and the project info text flow RELATIVELY in the
   flexbox now; clear any legacy absolute offsets. Higher specificity than the
   original per-element left:/right: rules. */
.top-toolbar-group .tt-btn,
.top-toolbar-group .share-button,
.top-toolbar .project-name {
  position: relative;
  top: auto;
  left: auto;
  right: auto;
}

.top-toolbar .zoom-text-div {
  position: relative;
  top: auto;
  right: auto;
  height: auto;
}

/* Editable name textbox overlays the name within .project-info. */
.top-toolbar .project-name-textbox {
  top: 0;
  left: 0;
}

/* Dropdown menus anchor directly under their trigger button. */
.tt-menu-anchor .logo-menu-div {
  top: 100%;
  left: 0;
}

.tt-menu-anchor .account-menu-div {
  top: 100%;
  right: 0;
}

/* Left tool palette and resizable toolbar rail. */
.left-toolbar {
  position: absolute;
  background-color: var(--left-toolbar-background-color);
  top: var(--top-toolbar-height);
  left: 0px;
  width: var(--left-toolbar-width);
  bottom: var(--status-bar-height, 0px);
  display: flex;
  flex-direction: column;
  z-index: 10;
}

.left-toolbar-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* Always-on cursor-coordinate readout at the foot of the left toolbar. Compact
   grid (axis label + right-aligned value per row, unit below) so it fits the
   narrow toolbar. */
.cursor-coords-readout {
  flex: 0 0 auto;
  padding: 6px 5px;
  border-top: 1px solid var(--editor-control-border-color);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px 4px;
  align-items: baseline;
  font-size: 10px;
  color: var(--editor-muted-text-color);
}
/* Inline form for the editor status bar: one compact row, no border/padding. */
.cursor-coords-inline {
  display: flex;
  padding: 0;
  border-top: none;
  gap: 4px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.cursor-coords-inline .cursor-coords-val { min-width: 0; }
.cursor-coords-axis {
  text-align: left;
}
.cursor-coords-val {
  text-align: right;
  color: var(--editor-text-color);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cursor-coords-unit {
  grid-column: 1 / -1;
  text-align: right;
  opacity: 0.8;
}

/* Coordinate label pinned under the crosshair while the Coordinates tool is
   active. `left`/`top` are the cursor's screen point; the translate nudges the
   label below-right so it doesn't sit under the crosshair itself. */
.cursor-coords-canvas-label {
  position: absolute;
  transform: translate(18px, 18px);
  padding: 5px 10px;
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--editor-text-color);
  background: var(--editor-input-bg);
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  pointer-events: none;
  z-index: 20;
}

/* Ghost pin that replaces the cursor while placing a pin: anchored by its
   bottom-centre (the tip) at the cursor point. */
.pin-ghost-cursor {
  position: absolute;
  transform: translate(-50%, -100%);
  pointer-events: none;
  overflow: visible;
  z-index: 21;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}

/* On-canvas tooltip for an annotation Pin's message, anchored above the marker
   (see PinTooltip). Dark chip so it reads over any design; never intercepts the
   pointer. */
.pin-tooltip {
  position: absolute;
  transform: translate(-50%, calc(-100% - 14px));
  max-width: 340px;
  padding: 9px 13px;
  font-size: 16px;
  line-height: 1.4;
  white-space: pre-wrap;
  color: #fff;
  background: rgba(28, 30, 36, 0.94);
  border-radius: 8px;
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.3);
  pointer-events: none;
  z-index: 21;
}
/* The author suffix on a pin tooltip — dimmer than the message. */
.pin-tooltip-author {
  opacity: 0.7;
  font-style: italic;
}

/* Live collaborator cursors — a coloured pointer + name pill at the peer's
   world position. Non-interactive; sits above the canvas. */
.remote-cursor {
  position: absolute;
  transform: translate(-2px, -2px);
  pointer-events: none;
  z-index: 22;
  will-change: left, top;
}
.remote-cursor svg {
  display: block;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
.remote-cursor-label {
  position: absolute;
  left: 14px;
  top: 12px;
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 11px;
  line-height: 1.5;
  white-space: nowrap;
  color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Share dialog (invite links). Mirrors the feedback modal house style. */
.share-backdrop {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 18, 24, 0.55);
  padding: 24px;
}
.share-modal {
  width: 100%;
  max-width: 460px;
  box-sizing: border-box;
  background: var(--editor-panel-background-color, #fff);
  color: var(--editor-text-color, #1a1a1f);
  border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.15));
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  padding: 22px 24px;
}
.share-title { margin: 0 0 4px; font-size: 1.15rem; font-weight: 700; display: flex; align-items: center; gap: 8px; }
.share-experimental-badge {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 7px;
  border-radius: 999px;
  color: #b5670a;
  background: color-mix(in srgb, #f5a623 22%, transparent);
  border: 1px solid color-mix(in srgb, #f5a623 55%, transparent);
}
.share-experimental-note {
  margin: 8px 0 14px;
  padding: 8px 10px;
  font-size: 0.8rem;
  line-height: 1.45;
  border-radius: 8px;
  color: var(--editor-text-color);
  background: color-mix(in srgb, #f5a623 12%, transparent);
  border: 1px solid color-mix(in srgb, #f5a623 40%, transparent);
}
.share-subtitle { margin: 0 0 16px; font-size: 0.85rem; opacity: 0.7; line-height: 1.45; }
.share-create-row { display: flex; gap: 8px; align-items: center; }
.share-role-select {
  flex: 0 0 auto;
  padding: 6px 8px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg);
  color: var(--editor-text-color);
}
.share-create-btn, .share-copy-btn, .share-close-btn {
  padding: 6px 14px;
  border-radius: var(--corner-radius-sm);
  border: 1px solid var(--editor-selected-blue);
  background: var(--editor-selected-blue);
  color: #fff;
  cursor: pointer;
  font-size: 0.85rem;
}
.share-create-btn:disabled { opacity: 0.6; cursor: default; }
.share-link-row { display: flex; gap: 8px; margin-top: 14px; }
.share-link-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 6px 8px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg);
  color: var(--editor-text-color);
  font-size: 0.8rem;
}
.share-copy-btn { flex: 0 0 auto; }
.share-error { margin: 10px 0 0; font-size: 0.8rem; color: #e5484d; }
.share-list { margin-top: 18px; }
.share-list-head { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.6; margin-bottom: 6px; }
.share-list-row { display: flex; align-items: center; gap: 10px; padding: 5px 0; font-size: 0.85rem; }
.share-list-role { flex: 0 0 auto; font-weight: 600; }
.share-list-meta { flex: 1 1 auto; opacity: 0.6; }
.share-revoke-btn {
  flex: 0 0 auto;
  padding: 3px 10px;
  border-radius: var(--corner-radius-sm);
  border: 1px solid var(--editor-control-border-color);
  background: transparent;
  color: var(--editor-text-color);
  cursor: pointer;
  font-size: 0.8rem;
}
.share-revoke-btn:hover { border-color: #e5484d; color: #e5484d; }
.share-actions { display: flex; justify-content: flex-end; margin-top: 20px; }
.share-close-btn { background: transparent; color: var(--editor-text-color); border-color: var(--editor-control-border-color); }

/* Save-status dot on the top-toolbar Save button (continuous autosave). */
.save-btn-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.save-status-dot {
  position: absolute;
  right: 1px;
  bottom: 3px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--top-toolbar-background-color);
  background: #30a46c;              /* saved (green) */
  pointer-events: none;
}
.save-status-unsaved .save-status-dot { background: #f5a623; }   /* amber */
.save-status-offline .save-status-dot { background: #e5484d; }   /* red */
.save-status-saving .save-status-dot {
  background: #0091ff;                                            /* blue, pulsing */
  animation: save-dot-pulse 1s ease-in-out infinite;
}
@keyframes save-dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* Crash-recovery restore prompt (top-centre of the canvas). */
.restore-prompt {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 24;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  font-size: 13px;
  border-radius: 10px;
  color: var(--editor-text-color);
  background: var(--editor-panel-background-color);
  border: 1px solid var(--editor-selected-blue);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
}
.restore-prompt-text { font-weight: 500; }
.restore-prompt-btn {
  padding: 4px 12px;
  border-radius: var(--corner-radius-sm);
  border: 1px solid var(--editor-control-border-color);
  background: transparent;
  color: var(--editor-text-color);
  cursor: pointer;
  font-size: 12px;
}
.restore-prompt-restore {
  border-color: var(--editor-selected-blue);
  background: var(--editor-selected-blue);
  color: #fff;
}

/* "View only" banner — shown on the canvas for a viewer-role collaborator. */
.view-only-banner {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 23;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 13px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 16px;
  color: #7a4b00;
  background: color-mix(in srgb, #f5a623 88%, #fff);
  border: 1px solid color-mix(in srgb, #f5a623 70%, #000 6%);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  pointer-events: auto;
}
.view-only-eye { font-size: 13px; }

/* On-canvas annotation author filter (top-left chip + popover). */
.annotation-filter {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 20;
}
.annotation-filter-chip {
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 14px;
  border: 1px solid var(--editor-control-border-color);
  background: var(--editor-panel-background-color);
  color: var(--editor-text-color);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.annotation-filter-chip:hover { border-color: var(--editor-selected-blue); }
.annotation-filter-pop {
  margin-top: 6px;
  min-width: 180px;
  max-height: 260px;
  overflow-y: auto;
  padding: 6px;
  border-radius: 8px;
  border: 1px solid var(--editor-panel-separator-color);
  background: var(--editor-panel-background-color);
  box-shadow: 0 8px 28px -10px rgba(0, 0, 0, 0.4);
}
.annotation-filter-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--editor-text-color);
}
.annotation-filter-row:hover { background: color-mix(in srgb, var(--editor-selected-blue) 14%, transparent); }
.annotation-filter-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.annotation-filter-count { opacity: 0.6; font-variant-numeric: tabular-nums; }

/* Read-only "by <name>" attribution row in the annotation panels. */
.annotation-author-name {
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}
.annotation-author-date {
  opacity: 0.75;
}

.left-toolbar-scroll,
.item-tree-scroll,
.details-scroll {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.left-toolbar-scroll::-webkit-scrollbar,
.item-tree-scroll::-webkit-scrollbar,
.details-scroll::-webkit-scrollbar {
  display: none;
}

.tools-group {
  display: grid;
  grid-template-columns: repeat(var(--tools-group-columns, 2), 38px);
  padding-left: 2px;
  padding-right: 2px;
  padding-bottom: 4px;
  gap: 2px;
  border-width: 0 0 1px;
  border-bottom: 1px;
  border-style: solid;
  border-color: #b8b8b8;
}

.tools {
  min-height: min-content;
}

.left-toolbar-resize-handle {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 8px;
  cursor: col-resize;
  z-index: 30;
  touch-action: none;
}

/* Tool button grid and active/hover states. */
.hdr {
  grid-column: 1/-1;
  font: 600 10px/1.2 system-ui;
  letter-spacing: .04em;
  color: #8b93a0;
  opacity: var(--editor-icon-muted-opacity);
  text-transform: uppercase;
  text-align: center;
  margin: 2px 0 2px;
}

/* Tactile press feedback: an enabled button (and a tab) nudges down 1px while
   held, so a click reads as a physical press. Uses the independent `translate`
   property (not the `transform` shorthand) so it composes with any element that
   already sets a transform, and doesn't touch existing transitions. List / tree
   rows are deliberately excluded (they're selection + drag targets, not buttons). */
button:not(:disabled):active,
.tabs h3:active {
  translate: 0 1px;
}

/* Light mode: the left-toolbar section labels read a touch darker. */
[data-theme="light"] .hdr {
  color: #6e7480;
}

.tools button {
  aspect-ratio: 1/1;
  width: 38px;
  padding: 1px;
  display: grid;
  place-items: center;
  border-radius: var(--corner-radius);
  border: 0;
  background: #f4f3f3;
  opacity: 0.5;
}

/* Edit badge: a small "E" marker at the lower-right of a tool's icon while the
   matching item (a line, connection, or pen) is being edited. Colour is a CSS
   var, so it adapts to dark mode. */
.tool-edit-badge {
  position: absolute;
  right: 1px;
  bottom: 1px;
  width: 14px;
  height: 14px;
  display: grid;
  place-items: center;
  pointer-events: none;
  color: var(--editor-selected-blue, #1097e2);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}

.tool-icon {
  position: relative;
  width: 36px;
  margin: 0;
  padding: 0;
  /* Normal at rest; full brightness on hover and for the selected tool. */
  opacity: 0.9;
  border-radius: var(--corner-radius);
  user-select: none;
}

.tool {
  aspect-ratio: 1/1;
  border-radius: var(--corner-radius);
  display: grid;
  place-items: center;
  background: #ffffff14;
  /* default tile */
}

.tool:hover {
  outline: var(--selection-border-width) solid #6ea8ff;
  outline-offset: calc(-1 * var(--selection-border-width));
}

/* Selected tool: keep the icon glyph visible (don't flood the cell
   with a saturated color), and mark the state with a 2px selection
   outline at full opacity plus a slightly lifted neutral background. */
.tool[aria-pressed="true"] {
  background: var(--tool-active-bg, #e3e8f2);
  outline: var(--selection-border-width) solid var(--editor-selected-blue);
  outline-offset: calc(-1 * var(--selection-border-width));
  color: inherit;
}

.tool:focus-visible {
  outline: var(--selection-border-width) solid var(--input-focus-outline, #fff);
  outline-offset: calc(-1 * var(--selection-border-width));
}

.left-toolbar-item-div {
  position: relative;
  border-radius: var(--corner-radius);
}

/* Mouseover highlight for toolbar tools: brighten the glyph (foreground) only,
   no background box (see the .tool-icon opacity rule below). The selected tool
   keeps its .left-toolbar-item-active blue outline. */

/* Hovered and selected tools also get a full-brightness glyph. */
.left-toolbar-item-div:hover .tool-icon,
.left-toolbar-item-active .tool-icon {
  opacity: 1;
}

/* Currently-selected tool. Marked structurally by a 2px selection-blue outline
   and a full-brightness glyph — no background fill (foreground-only rule). */
.left-toolbar-item-active {
  outline: var(--selection-border-width) solid var(--editor-selected-blue);
  outline-offset: calc(-1 * var(--selection-border-width));
}

/* Left layers panel: page list and visual item tree. */
.tree-div {
  position: absolute;
  top: var(--top-toolbar-height);
  left: var(--left-toolbar-width);
  bottom: var(--status-bar-height, 0px);
  width: var(--tree-width);
  text-align: left;
  background-color: var(--editor-panel-background-color);
  border-right: 1px solid var(--panel-border-color);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 10;
}

/* Wrapper around the left panel's content (below the tabs). A flex column that
   fills the remaining height so the tree scroll areas inside still flex; also the
   element the auto-width measurement shrinks to read the content's natural extent. */
.left-panel-content {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* The Flow Diagrams panel is the Code-tab Assets pane and, unlike the other
   tabs, is rendered bare (not inside a plain .item-tree-scroll wrapper) — it owns
   its own header + scroll. It HUGS its content (flex-grow:0) so the Sequences /
   Use-cases / State-machines sections sit directly below it instead of being pushed
   to the bottom of the panel by a greedy fill. It stays a flex column that can still
   SHRINK (flex-shrink:1, min-height:0) when the panel is full, so its tree list
   (.item-tree-scroll, flex:1 1 auto; min-height:0) becomes height-bounded and scrolls
   with a hidden scrollbar rather than pushing the sections below it off-screen. */
.left-panel-content > .flow-diagrams,
.diagrams-panel-body > .flow-diagrams {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.left-panel-content > .flow-diagrams > .details-header,
.diagrams-panel-body > .flow-diagrams > .details-header {
  flex: 0 0 auto;
}

/* Diagrams sub-tabs: the strip stays fixed, the active type panel fills the rest and
   scrolls (the seq-style panels scroll as a whole; the flow panel bounds its own tree). */
.diagrams-panel {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.diagrams-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.diagrams-panel-body > .seq-panel {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.page-div {
  width: 100%;
  color: var(--editor-text-color);
  flex: 0 0 auto;
  /* Bottom padding = half the inter-line gap so the last page row clears the
     divider/spacer below by the standard gap. */
  padding: 5px 0 var(--list-row-pad);
}

.page-triangle-img {
  padding: 4px var(--panel-triangle-pad-right) 4px var(--panel-triangle-pad-left);
  opacity: var(--editor-icon-muted-opacity);
  height: var(--panel-triangle-size);
  width: var(--panel-triangle-size);
  vertical-align: middle;
  cursor: pointer;
  box-sizing: content-box;
}

/* Section (Level-1) disclosure triangle. Element fills the 0..panel-indent
   band; the 12px image sits at 7..19 within it (1px right of the band's
   natural center), with --panel-triangle-pad-right of space to the title. */
.section-triangle-img {
  padding: 4px var(--panel-triangle-pad-right) 4px var(--panel-triangle-pad-left);
  opacity: var(--editor-icon-muted-opacity);
  height: var(--panel-triangle-size);
  width: var(--panel-triangle-size);
  vertical-align: middle;
  cursor: pointer;
  box-sizing: content-box;
  position: relative;
  z-index: 25;
}

.separator {
  border-color: var(--editor-panel-separator-color);
  border-width: 0px 0px 2px 0px;
  border-style: solid;
}

/* Header row holding the disclosure triangle, the "Page" title, and the
   add / delete icons — laid out with flex so everything sits on a shared
   vertical centre line. margin-right: auto on the title pushes the icons
   to the right. padding-right keeps them clear of the 12px-wide
   .left-panel-resize-handle that overlays the panel's right edge, so the
   icons stay hoverable / clickable instead of being captured by it. */
.page-header-row {
  display: flex;
  align-items: center;
  /* 10px right gap nudges the -/+ buttons right (was 14px, then 12px). */
  padding-right: 10px;
}

.page-heading {
  margin: 0 auto 0 0;
  user-select: none;
  vertical-align: middle;
  color: var(--header-2-color);
}

.page-list-plus-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.minus-variable-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.page-list-minus-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.page-list-ul {
  list-style-type: none;
  margin: 0px;
  padding: 0px;
  /* The first page row's own top padding provides the gap under the header;
     no extra margin (that made the under-header gap too big). */
  margin-top: 0px;
  margin-bottom: 0px;
  padding-left: 3px;
  font-size: var(--editor-control-font-size);
}

/* Per-layer disclosure triangle — toggles that layer's opacity + blend sub-row.
   An IN-FLOW slot immediately left of the name (not pinned to the far-left
   gutter) so the triangle + name move together as one level: when group nesting
   adds levels, each row's indent shifts both. The slot is exactly one
   --panel-indent wide (the glyph aligned under the section triangle), so the name
   that follows lands at level 1 (--panel-indent) — its own left padding is zeroed
   (.layer-name below). */
.layer-disclosure {
  flex: 0 0 auto;
  width: var(--panel-triangle-size);
  height: var(--panel-triangle-size);
  margin-left: calc(var(--panel-triangle-pad-left) - 3px);
  margin-right: calc(var(--panel-indent) - var(--panel-triangle-pad-left) - var(--panel-triangle-size));
  opacity: var(--editor-icon-muted-opacity);
  cursor: pointer;
}
[data-theme="dark"] .layer-disclosure {
  filter: invert(1) brightness(1.2);
}
/* Layer name: the triangle slot supplies the level-1 indent, so drop the name's
   own left padding (keep the vertical row padding from .page-list-item-div). */
.page-list-item .layer-name {
  padding-left: 0;
}

/* Small type icon (folder / layer) between the disclosure slot and the name. */
.page-list-item .layer-type-icon {
  flex: 0 0 auto;
  width: 13px;
  height: 13px;
  margin-right: 5px;
  opacity: var(--editor-icon-muted-opacity);
}
[data-theme="dark"] .page-list-item .layer-type-icon {
  filter: invert(1) brightness(1.2);
}

/* A layer's opacity + blend controls, revealed under its row by the disclosure
   triangle. Level 2 (the layer name is level 1): 2 × --panel-indent from the
   panel's left, minus the 3px the .page-list-ul already insets. */
.layer-props-sub {
  padding: 2px 12px 5px calc(2 * var(--panel-indent) - 3px);
  font-size: var(--editor-control-font-size);
}
.layer-props-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0;
}
.layer-props-row > label {
  flex: 0 0 auto;
  width: 46px;
  opacity: 0.7;
}
.layer-props-row .layer-opacity-range {
  flex: 1 1 auto;
  min-width: 0;
}
.layer-props-row .layer-opacity-val {
  flex: 0 0 auto;
  width: 34px;
  text-align: right;
  opacity: 0.7;
}
.layer-props-row .blend-mode-select {
  flex: 1 1 auto;
  width: auto;
}

.page-list-item-div {
  /* Space the page rows on the compact (dense-row) gap (was a fixed 4px). The
     left inset aligns the page / layer name under its section header — the
     header title sits one --panel-indent in (past its disclosure triangle),
     and the list is already inset 3px by .page-list-ul, so the name takes the
     remaining (--panel-indent − 3px). */
  padding: var(--list-row-pad) 0px var(--list-row-pad) calc(var(--panel-indent) - 3px);
}

/* Pages are shown as a GRID OF TILES — a fit-to-content thumbnail with the page
   name below — rather than a text list, so previews can be large without eating
   much vertical room. Own classes (NOT the shared .page-list-item*, which the
   Layers list reuses). The grid reflows by panel width: the min tile width sets
   how many columns fit, and 1fr lets them stretch to fill the row. */
.page-tiles-ul {
  list-style-type: none;
  margin: 0;
  padding: 6px 8px 4px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 10px 8px;
  font-size: var(--editor-control-font-size);
}
.page-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  cursor: pointer;
}
.page-tile-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  box-sizing: border-box;
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.35));
  border-radius: var(--corner-radius-sm, 3px);
  background: #ffffff;
}
.page-tile-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}
.page-tile-empty {
  display: block;
  width: 100%;
  height: 100%;
}
.page-tile-name {
  margin-top: 3px;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--editor-text-color);
}
/* The ACTIVE (current) page: a blue ring on its thumbnail + a tinted name. */
.page-tile.active .page-tile-thumb {
  border-color: var(--editor-selected-blue);
  box-shadow: 0 0 0 1px var(--editor-selected-blue);
}
.page-tile.active .page-tile-name {
  color: var(--editor-selected-blue);
}
.page-tile.tile-dragging {
  opacity: 0.5;
}
/* Vertical insertion indicator in the gap on the left/right edge of the tile the
   cursor is over, while dragging a tile to reorder. */
.page-tile-drop-line {
  position: absolute;
  top: 2px;
  bottom: 2px;
  width: 2px;
  background: var(--editor-selected-blue);
  border-radius: 1px;
  pointer-events: none;
}
.page-tile-drop-line.before {
  left: -5px;
}
.page-tile-drop-line.after {
  right: -5px;
}

/* Page rows carry a visibility eye on the right, matching the Layers-tree eyes. */
.page-list-item {
  display: flex;
  align-items: center;
}
/* The ACTIVE layer/page — the insert target — is highlighted the same way the
   current item is highlighted in the item tree (--tree-selection-bg). */
.page-list-item.active-layer {
  background: var(--tree-selection-bg, rgba(127, 127, 127, 0.2));
  border-radius: 3px;
}
/* The active page/layer NAME is tinted with the selection colour for contrast —
   the subtle highlight background alone reads too faintly. Matches the active
   layer's name in the item tree. */
.page-list-item.active-layer .page-list-item-div {
  color: var(--editor-selected-blue);
}
.page-list-item.page-hidden .page-list-item-div,
.page-list-item.page-hidden .selected-icon,
.page-list-item.page-hidden .selected-line {
  opacity: 0.5;
}
.page-vis-eye {
  flex: 0 0 auto;
  margin-left: auto;
  /* Nudged right again (16px → 15px → 14px). */
  margin-right: 14px;
  width: 14px;
  height: 14px;
  opacity: 0.38;
  cursor: pointer;
}
.page-vis-eye.hidden {
  opacity: 0.8;
}
.page-vis-eye:hover {
  opacity: 1;
}
/* The last visible page/layer's eye can't be hidden (prevention) — dim it and
   show a not-allowed cursor so it reads as intentionally locked. */
.page-vis-eye.locked {
  opacity: 0.18;
  cursor: not-allowed;
}
.page-vis-eye.locked:hover {
  opacity: 0.18;
}
[data-theme="dark"] .page-vis-eye {
  filter: invert(1) brightness(1.2);
}

/* Layer lock — mirrors the visibility eye: a padlock with a diagonal slash when
   UNLOCKED (dim, like a shown layer's eye) and a solid padlock when locked
   (bright, like the crossed-out eye). The padlock is a smaller, denser shape
   than the sprawling eye, so the opacities are nudged past the eye's own values
   (unlocked below the eye's 0.38, locked to full) so the two read at the SAME
   apparent brightness. margin-left:auto right-aligns the lock+eye pair;
   black-stroke SVGs, inverted in dark mode like the eye. */
.page-lock-eye {
  flex: 0 0 auto;
  margin-left: auto;
  margin-right: 8px;
  width: 13px;
  height: 13px;
  /* Slashed (unlocked) lock matches a shown layer's eye brightness (0.38). */
  opacity: 0.38;
  cursor: pointer;
}
.page-lock-eye.on {
  opacity: 1;
}
.page-lock-eye:hover {
  opacity: 1;
}

/* ---- Blueprint page tree (reuses the standard tree classes: page-header-row,
   page-list-item, active-layer, layer-disclosure, layer-type-icon) ------------ */
.bp-tree-row { position: relative; cursor: pointer; user-select: none; padding-top: var(--list-row-pad); padding-bottom: var(--list-row-pad); padding-right: 6px; }
.bp-tree-empty { font-size: 11px; color: var(--editor-muted-text-color); font-style: italic; margin: 1px 0 3px; }
.bp-tree-row .bp-disclosure-spacer { flex: 0 0 auto; width: var(--panel-triangle-size); margin-left: calc(var(--panel-triangle-pad-left) - 3px); margin-right: calc(var(--panel-indent) - var(--panel-triangle-pad-left) - var(--panel-triangle-size)); }
.bp-tree-row .bp-row-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; }
.bp-tree-row.bp-form .bp-row-label { font-weight: 700; }
.bp-tree-row .bp-row-sub { color: var(--editor-muted-text-color); font-weight: 400; }
.bp-tree-row.active-layer .bp-row-label { color: var(--editor-selected-blue); }
.bp-row-badge { flex: 0 0 auto; font-size: 8.5px; font-weight: 700; color: var(--editor-muted-text-color); border: 1px solid var(--editor-control-border-color, var(--editor-border-color)); border-radius: 4px; padding: 0 4px; text-transform: uppercase; margin: 0 4px; }
.bp-start-badge { flex: 0 0 auto; font-size: 8.5px; font-weight: 700; color: var(--editor-muted-text-color); margin-right: 5px; }
.bp-row-btn { flex: 0 0 auto; width: 13px; height: 13px; margin-left: 6px; opacity: var(--editor-icon-muted-opacity); cursor: pointer; }
.bp-row-btn:hover { opacity: 1; }
/* The +/− glyphs are black artwork. Every other icon in the editor flips for dark mode;
   these were missed, so they sat black-on-dark (invisible). Same invert, and a touch more
   opacity than the muted default so a small 13px glyph still reads. */
[data-theme="dark"] .bp-row-btn { filter: invert(1) brightness(1.2); opacity: 0.75; }
[data-theme="dark"] .bp-row-btn:hover { opacity: 1; }
.bp-drop-line { position: absolute; left: 4px; right: 8px; height: 2px; background: var(--editor-selected-blue); pointer-events: none; z-index: 2; }
.bp-drop-line.before { top: -1px; }
.bp-drop-line.after { bottom: -1px; }
.bp-drop-into { position: absolute; inset: 0; border: 1px solid var(--editor-selected-blue); border-radius: 3px; pointer-events: none; }
[data-theme="dark"] .page-lock-eye {
  filter: invert(1) brightness(1.2);
}
/* The eye sits right after the lock, so the lock's margin-left:auto already
   right-aligns the pair. Cancel the eye's OWN margin-left:auto here — otherwise
   the free space splits between the two autos and the lock lands mid-row. */
.page-lock-eye + .page-vis-eye {
  margin-left: 0;
}

/* Per-row visibility eye for the Data-tab and Prototype-tab trees — matches the
   Layers-tree / pages eyes. */
.row-vis-eye {
  flex: 0 0 auto;
  margin-left: auto;
  /* Nudged right again (14px → 13px → 12px). */
  margin-right: 12px;
  width: 14px;
  height: 14px;
  opacity: 0.38;
  cursor: pointer;
}
.row-vis-eye.hidden {
  opacity: 0.8;
}
.row-vis-eye:hover {
  opacity: 1;
}
[data-theme="dark"] .row-vis-eye {
  filter: invert(1) brightness(1.2);
}

.item-tree-div {
  width: 100%;
  color: var(--editor-text-color);
}

.item-tree-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

.item-tree-ul {
  list-style-type: none;
  margin: 0px;
  padding: 0px;
  font-size: var(--editor-control-font-size);
}

.item-tree-item p {
  margin: 0px;
  padding: 0px;
  user-select: none;
  display: inline-block;
  line-height: 1.2;
}

.item-tree-item input {
  padding: 0px;
  width: 140px;
  margin: 5px 3px;
  user-select: none;
}

.item-tree-item img {
  padding: 5px 5px 2px;
  /* the opacity is set in the javascript */
  height: 6px;
  width: 6px;
}

/* Structure-tree rows are interactive controls, not selectable content. Block
   native text/element SELECTION (so you can't rubber-band-highlight the icons /
   disclosure triangles and then drag that browser-selection) and native image
   DRAGGING (images are draggable by default, which otherwise lets you drag an
   item by its type icon even when the row itself isn't draggable — e.g. a locked
   layer's items). The row's own `draggable` attribute stays the ONLY drag source. */
.item-tree-row,
.item-tree-row * {
  user-select: none;
  -webkit-user-select: none;
}
.item-tree-row img {
  -webkit-user-drag: none;
  user-drag: none;
}

/* Shared detail-panel row controls and inline icon controls. */
.align-items-div {
  padding: 0px 6px;
}

.align-icon {
  padding: 2px;
  margin: 0 4px 0 0;
  opacity: 0.7;
  cursor: pointer;
  user-select: none;
  border: var(--selection-border-width) solid transparent;
  border-radius: var(--corner-radius);
  box-sizing: border-box;
}

.align-icon:hover {
  /* Brighten the glyph (foreground) on hover — no background box. */
  opacity: 1;
}

/* Selectable alignment icons (image / text justification) sit inside an
   unfiltered cell, just like a line-end cap. The selection outline lives
   on this cell so it shows the true selection colour in dark mode (the
   icon itself is luminance-inverted), and the selected icon goes to full
   opacity — so a selected alignment icon reads exactly as bright as a
   selected cap. */
.align-icon-cell {
  display: inline-flex;
  /* Tight within-group spacing between adjacent align buttons. */
  margin: 0 2px 0 0;
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  user-select: none;
  box-sizing: border-box;
  outline: var(--selection-border-width) solid transparent;
  outline-offset: calc(-1 * var(--selection-border-width));
}

.align-icon-cell .align-icon {
  margin: 0;
}

.align-icon-cell-selected {
  background-color: var(--tool-active-bg, #e3e8f2);
  outline-color: var(--editor-selected-blue);
}

.align-icon-cell-selected .align-icon {
  opacity: 1;
}

/* Point/area text-type switcher — a compact two-cell segmented control that
   reuses the align-cell selected highlight, but the cells hold a text label
   (Area / Point) instead of an icon, so they need their own padding. */
.text-type-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin-left: var(--panel-indent);
  margin-right: var(--panel-right-gutter);
}

.text-type-label {
  /* Fixed-width label column so the Type (Area/Point) and Height (Fixed/Auto)
     segmented controls start at the same X and line up as a stacked pair. */
  flex: 0 0 52px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}

.text-type-cell {
  padding: 2px 10px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
}

.text-type-cell.align-icon-cell-selected {
  color: var(--editor-text-color);
}

.groups-add-remove-div {
  display: inline-flex;
  align-items: center;
  margin: 0 var(--panel-control-gap);
}

.add-group-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.remove-groups-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

/* Right details panel shell and resizer. */
.details-div {
  position: fixed;
  text-align: left;
  top: var(--top-toolbar-height);
  right: 0;
  bottom: var(--status-bar-height, 0px);
  width: var(--details-width);
  background-color: var(--editor-panel-background-color);
  color: var(--editor-text-color);
  border-left: 1px solid var(--panel-border-color);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 10;
}

.details-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

.left-panel-resize-handle,
.details-resize-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 12px;
  cursor: col-resize;
  z-index: 20;
  touch-action: none;
}

.left-panel-resize-handle {
  right: 0;
}

.details-resize-handle {
  left: 0;
}

/* Details panel form rows, inputs, and disclosure affordances. */
.section-content-row {
  margin-left: var(--panel-indent);
}

/* Content revealed by a secondary disclosure (stroke options, line options,
   corners) is indented to Level 2 so the visual hierarchy matches the
   disclosure tree. Both the disclosure-toggled title row and its expanded
   content land at the same X. */
.details-line-group,
.stroke-options-group {
  margin-left: var(--panel-level-2);
}

/* Marker (pencil/highlighter) section: its Width + caps are level-1 content, so
   indent them one step like every other section's rows. The label is sized to
   its text (with the standard label gap) so the field sits right next to it. */
.marker-div {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

/* Note (sticky) styling section: a labelled row per control (Background / Text / Padding). */
.note-row {
  display: flex;
  align-items: center;
  /* Wrap so the swatch row can drop to its own full-width line under the
     label instead of squeezing beside it and orphaning a lone swatch. */
  flex-wrap: wrap;
  gap: 8px;
  box-sizing: border-box;
  max-width: 100%;
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
.note-label {
  flex: 0 0 auto;
  width: 72px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
/* The swatch row: a custom picker (left, so its native popup opens inward) + preset swatches. */
.note-color-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  /* Full-width basis so the swatches take their own line (the whole panel
     width) rather than the narrow gap beside the label — avoids the orphan. */
  flex: 1 1 100%;
  min-width: 0;
}
.note-swatch {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
}
.note-swatch.selected {
  outline: 2px solid var(--editor-selected-blue);
  outline-offset: 1px;
}
.note-color-custom {
  flex: 0 0 auto;
  width: 24px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background: transparent;
  cursor: pointer;
}
.note-pad-input {
  /* flex-basis pins the width so `.details-scroll input { width: 100% }`
     can't stretch it off the panel edge. */
  flex: 0 0 64px;
  width: 64px;
  box-sizing: border-box;
  padding: 3px 6px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg);
  color: var(--editor-text-color);
  text-align: var(--number-input-align);
}
/* Emote section — a grid of preset emojis + a custom-emoji field. */
.emote-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 4px;
  box-sizing: border-box;
  max-width: 100%;
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
.emote-swatch {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  min-width: 0;
  padding: 0;
  font-size: 18px;
  line-height: 1;
  border: 1px solid transparent;
  border-radius: var(--corner-radius-sm);
  background: transparent;
  cursor: pointer;
}
.emote-swatch:hover {
  background: var(--editor-hover-bg, rgba(127, 127, 127, 0.18));
}
.emote-swatch.selected {
  outline: 2px solid var(--editor-selected-blue);
  outline-offset: -1px;
}
.emote-custom-input {
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
  padding: 3px 6px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg);
  color: var(--editor-text-color);
}
.marker-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
.marker-label {
  font-size: var(--editor-control-font-size);
  margin-right: var(--panel-checkbox-label-gap);
}

/* One (label + control) pair inside a stroke-options sub-section. Wrapper
   is --details-row-height tall; children stay at their natural height and
   are centered vertically. */
.stroke-options-div {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

/* Wrapper for the Dimensions grid (X/Y/W/H/Corners/Angle).
   Shifts the column-cell layout right so the first column aligns with
   title-text. The cells themselves remain inline-block at 40% width. */
.dim-grid {
  padding-left: var(--panel-indent);
  /* Standard right gutter so the rightmost fields (Y, H) stop 8px short
     of the panel edge rather than running flush against it. */
  padding-right: 8px;
}

/* X|Y and W|H pairs: the second field packs flush against the first
   instead of sitting out at a fixed column. */
.dim-row {
  display: flex;
  align-items: center;
  gap: var(--panel-pair-gap, 20px);
}

/* Wider X / Y edit boxes: tighten the column gap and lift the input cap so each
   field claims more of the row. */
.dim-row-xy {
  /* Between-group gap: the X and Y label+control groups sit further apart than
     a label sits from its own control (that inner gap is 4px, set below), and
     tighter than the 20px .dim-row default so both still fit. The inputs
     flex-shrink to absorb it. */
  gap: 12px;
}
/* Within-group gap: on the X/Y line a dimension label hugs its control (closer
   than the between-group gap above), overriding the wider
   --panel-checkbox-label-gap. Scoped to the X/Y row only — the W/H labels keep
   the standard gap so their edit boxes line up with the corner / angle boxes
   (which sit a full --panel-checkbox-label-gap past their 14px icon). */
.dim-row-xy .details-line-half-div p {
  margin-right: 4px;
}
/* Trim each X/Y control so the pair fits at the deeper level-2 indent (the X
   field now starts a full --panel-indent past the reference disclosure triangle)
   without X/Y crowding the position lock at the row's right edge. */
.dim-row-xy .details-line-half-div input {
  max-width: calc(100% - 28px);
}

/* Project section: a row with a label and a unit dropdown, under the
   "Project" disclosure header. Indented to match the rest of the design panel. */
.units-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  padding-left: var(--panel-indent);
  padding-right: var(--panel-right-gutter);
  gap: 8px;
}
.units-label {
  /* Fixed-width label column so each row's select starts at the same x —
     otherwise the wider "Units" label pushes its dropdown right of "Angle". */
  flex: 0 0 44px;
  font-weight: 600;
  font-size: var(--editor-control-font-size);
  color: var(--header-3-color);
  user-select: none;
  white-space: nowrap;
}
.units-select {
  flex: 0 0 auto;
}
/* The Units / Angle / Y-axis dropdowns share one width so they line up, and get
   the standard control height (line-height + vertical padding + border) instead
   of the browser's default select height. (The project-name input, which also
   carries .units-select, keeps its own width from .project-name-field.) */
select.units-select {
  box-sizing: border-box;
  width: 116px;
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  line-height: var(--editor-control-line-height);
  padding: var(--editor-control-pad-y) 4px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  color: var(--editor-text-color);
  background-color: var(--editor-input-bg);
}
/* Coordinate-mode radio group (World / Screen) in the Project section. */
.units-radio-group {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}
.units-radio {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  cursor: pointer;
  user-select: none;
}
.units-radio input {
  margin: 0;
  cursor: pointer;
}
/* Read-only value (Created / Last saved) shown beside its units-label. */
.units-value {
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  user-select: text;
  white-space: nowrap;
}
/* Editable project-name field in the Project tab — a standard text box. */
.project-name-field {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
  padding: 2px 4px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
}

.dim-row .details-line-half-div {
  width: auto;
  /* Split the row evenly so each field (X|Y, W|H) — all formula-capable
     — claims half the available width and its input can grow into it. */
  flex: 1 1 0;
  min-width: 0;
}

/* The X/Y line carries a disclosure triangle for its reference sub-options.
   The triangle occupies the level-1 -> level-2 indent band (the row's base is
   level 1, the dim-grid padding), so the X field starts at the level-2
   boundary. W/H and corners have no sub-disclosure, so they stay at level 1. */
.dim-subtriangle {
  flex: 0 0 auto;
  width: var(--panel-triangle-size);
  height: var(--panel-triangle-size);
  cursor: pointer;
  /* Span one --panel-indent before X: triangle width + the row's 12px flex gap +
     this margin = --panel-indent, landing the X field at --panel-level-2. */
  margin-right: calc(var(--panel-indent) - var(--panel-triangle-size) - 12px);
}
/* The W/H row no longer aligns under X/Y — it sits at level 1 like corners — so
   its leading spacer contributes nothing. */
.dim-subtriangle-spacer {
  display: none;
}
/* Disclosed reference options (Relative / Bounding Box / Reference Point) line up
   under the X/Y fields at the level-2 boundary. The row already sits at level 1
   (dim-grid's padding), so one more --panel-indent lands it at --panel-level-2. */
.dim-row-indent {
  padding-left: var(--panel-indent);
}

/* Reference-point marker badge before the Relative / Bounding Box / Reference
   Point labels — mirrors the on-canvas badge (green ring + dot on white) so
   it reads as "reference point" and is distinct from the override dots. */
.ref-badge {
  display: inline-block;
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--reference-badge-accent);
  border: 1.5px solid var(--reference-badge-color);
  box-sizing: border-box;
  position: relative;
  vertical-align: middle;
  margin-right: 5px;
}
.ref-badge::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--reference-badge-color);
  transform: translate(-50%, -50%);
}
/* In the flex checkbox labels the row gap already spaces the badge. */
.ref-flag-option .ref-badge {
  margin-right: 0;
}

/* Reference-point picker — a small box with a clickable dot at each corner and
   the center. It sits inside .dim-grid, so it inherits the section's
   --panel-indent and lines up with the X/Y fields below it. */
.ref-point-row {
  /* Hug the reference-point grid, but carry the half-gap like a row so it sits
     a full inter-row gap from its neighbours. */
  min-height: 0;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
/* X/Y measurement checkboxes (Relative / Bounding Box) — per-item properties —
   sit on their own row above the reference-point picker. Laid out in a row that
   wraps if the panel is too narrow, so neither gets clipped. */
.ref-flags-row {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
.ref-flags-group {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: 4px 18px;
  width: 100%;
}
.ref-flag-option {
  display: flex;
  align-items: center;
  gap: var(--panel-checkbox-label-gap);
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  user-select: none;
  white-space: nowrap;
  cursor: pointer;
}
.ref-flag-option input {
  margin: 0;
  cursor: pointer;
}
.ref-point-group {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.ref-point-caption {
  /* Flex so the badge vertically centers with the label text on its line. */
  display: inline-flex;
  align-items: center;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  user-select: none;
  white-space: nowrap;
}
/* "Reference Point" label sitting to the left of the picker box. */
.ref-point-field {
  display: flex;
  align-items: center;
  gap: 10px;
}
.ref-point-box {
  display: block;
  overflow: visible;
}
/* The five cells (four L-shaped corners + a rectangular center) tile the box
   into one shape. A thin background-colored seam between them is drawn by each
   cell's own stroke, so the pieces read as separate buttons that fit together
   to form the rectangle. */
.ref-point-cell {
  cursor: pointer;
  outline: none;
  stroke: var(--editor-panel-background-color);
  stroke-width: 1.5;
  stroke-linejoin: round;
  transition: fill 0.1s ease;
  /* a faint fill so the tiling seams are visible at rest */
  fill: color-mix(in srgb, var(--toolbar-text-color) 18%, var(--editor-panel-background-color));
}
.ref-point-cell:hover {
  fill: color-mix(in srgb, var(--toolbar-text-color) 34%, var(--editor-panel-background-color));
}
.ref-point-cell.ref-point-cell-on {
  fill: var(--editor-selected-blue);
}
.ref-point-cell.ref-point-cell-on:hover {
  fill: var(--editor-selected-blue);
}
/* A reference point used by SOME (not all) of a mixed selection — dimmed. */
.ref-point-cell.ref-point-cell-mixed {
  fill: color-mix(in srgb, var(--editor-selected-blue) 45%, var(--editor-panel-background-color));
}
.ref-point-cell.ref-point-cell-mixed:hover {
  fill: color-mix(in srgb, var(--editor-selected-blue) 60%, var(--editor-panel-background-color));
}
.ref-point-cell:focus-visible {
  stroke: var(--editor-selected-blue);
  stroke-width: 2;
}

/* Flex row so children center on the geometric midline (matches every
   other panel row — .stroke-options-div, .color-details-div, etc.).
   Using line-height + vertical-align:middle here drifted the contents
   off-center relative to the surrounding flex rows. */
.details-line-div {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  width: 100%;
}

/* Multi-pair rows (west/east adornment selects, west/east cap selects,
   west/east size sliders). The label (icon) keeps its intra-pair gap to
   its control via its own margin-right; we add --panel-pair-gap as left
   margin to the start of each subsequent pair so the pairs visibly
   separate. */
.details-line-div > .arrow-icon ~ .arrow-icon,
.details-line-div > .stroke-cap ~ .stroke-cap,
.details-line-div > .line-cap ~ .line-cap,
.details-line-div > .adornment-size-div ~ .adornment-size-div {
  margin-left: var(--panel-pair-gap);
}

.details-line-half-div {
  display: inline-flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* Standalone rows (Angle, Corner Count, Corners) span the panel so the
     formula input can stretch; the X|Y / W|H pairs override this in the
     `.dim-row` rule above. */
  width: 100%;
  vertical-align: middle;
}

/* Inside a half-div, the .vi-dim wrapper would force a non-flex child box
   that prevents the label/input from centering directly. Collapse it with
   display: contents so the label + input become flex items of the
   .details-line-half-div and get vertically centered by align-items. */
.details-line-half-div > .vi-dim {
  display: contents;
}

.details-line-sides-div {
  display: inline-flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* Claim the row space left of the Equilateral checkbox (40%) so the
     formula-capable Side input has room to grow. */
  width: 58%;
  vertical-align: middle;
}

.details-line-checkbox {
  display: inline-block;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  width: 40%;
  line-height: normal;
  vertical-align: middle;
}

.details-line-star-div {
  /* Flex so the slider absorbs the remaining width and the text field keeps a
     fixed basis — otherwise `.details-scroll input { width: 100% }` stretches
     both the range and the text input to 100% and the row runs off the panel. */
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  line-height: normal;
}
.details-line-star-div > .star-depth-slider {
  flex: 1 1 0;
  min-width: 0;
}
.details-line-star-div > .star-depth {
  flex: 0 0 42px;
  width: 42px;
}

/* W / E adornment-size control: an E/W label + slider that line up
   with the line-end ADORNMENT row above — the label occupies the same
   width as the arrow icon (10px) and the slider the same width as the
   adornment select (86px), with the standard 8px gap between. */
.adornment-size-div {
  display: inline-flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.adornment-size-label {
  flex: none;
  width: 17px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  color: var(--editor-muted-text-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  user-select: none;
}

/* Inherits the label's currentColor, so it adapts to light/dark mode. */
.adornment-size-icon {
  display: block;
}

/* The W / E adornment-size sliders share the star-ratio slider class;
   size them to match the adornment select (86px). */
.adornment-size-div .star-depth-slider {
  flex: none;
  width: 86px;
  margin: 0;
}

.vi-dim {
  display: inline-block;
  vertical-align: middle;
}

/* Formula indicator (ƒ) shown on a Design-tab numeric field whose value is
   driven by a Code-tab formula. Small, green (code accent), muted until hover;
   clicking jumps to the Code tab. Rendered only when a formula is present. */
.formula-badge {
  flex: 0 0 auto;
  margin-left: 3px;
  padding: 0 3px;
  border: none;
  background: transparent;
  color: var(--code-accent);
  font-style: italic;
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
  opacity: 0.75;
  cursor: pointer;
  user-select: none;
}
.formula-badge:hover {
  opacity: 1;
}

.details-div p {
  display: inline-block;
  margin: 0px var(--panel-checkbox-label-gap) 0px 0;
  width: 14px;
  font-size: var(--editor-control-font-size);
  line-height: normal;
  text-align: left;
  color: var(--editor-muted-text-color);
  user-select: none;
  vertical-align: middle;
}

/* Collapsible "Scale / Skew" sub-section header in the dimensions panel. */
.scale-skew-header {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.scale-skew-title {
  font-weight: 600;
  font-size: var(--editor-control-font-size);
  color: var(--header-3-color);
  user-select: none;
}

.scale-skew-normal {
  margin-left: 6px;
  color: var(--editor-muted-text-color);
}

/* Scale / skew rows in the dimensions panel: label, slider, and a
   small percentage edit box, each control on its own line, indented
   one step (level 2) past the panel's level-1 content. */
.scale-skew-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* Right edge pinned 8px from the panel edge so the edit boxes line up there. */
  margin: 0 8px 0 var(--panel-indent);
  gap: var(--panel-checkbox-label-gap);
}

/* Reset (Scale / Skew → defaults) on its own line under the controls, left-
   aligned with the Skew label (inherits the control rows' margin-left, and the
   button drops .angle-reset's auto right margin). */
.scale-skew-reset-row .scale-skew-reset {
  margin-left: 0;
}

/* Auto width so the gap after the label equals the gap after the
   slider (both are just the row's flex gap). */
.scale-skew-label {
  flex: none;
  /* Fixed width so every row's icon, slider and percentage input line up in a
     column. Holds the H / V / U / Skew direction icon, left-aligned. */
  display: flex;
  align-items: center;
  width: 24px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  user-select: none;
  white-space: nowrap;
}

.scale-skew-icon {
  width: 16px;
  height: 16px;
  display: block;
}

.scale-skew-slider {
  /* Fixed 95px and NON-shrinking, so the width is actually honored: the slider
     keeps its size by taking room from the edit box. On a wider panel the box
     grows (the slider stays put); when the row is tight the box yields, not the
     slider. */
  flex: 0 0 auto;
  width: 95px;
  vertical-align: middle;
}

/* Design-panel range sliders tint with the editor selection color, so
   they restyle along with it when it is changed in Customize | Colors. */
.scale-skew-slider,
.star-depth-slider {
  accent-color: var(--editor-selected-blue);
}

.scale-skew-input {
  /* Grows with the panel on horizontal resize; the right edge stays pinned 8px
     from the panel edge via the row's right margin. Yields room to the slider
     (lower min-width) so the slider's width is honored on a tight panel. */
  flex: 1 1 auto;
  min-width: 44px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

/* Numeric edit boxes. Justification follows the --number-input-align
   preference (Customize → Layout); defaults to right so digits line up.
   The `input[type="number"]` selector applies it everywhere — including
   the Customize page's own number fields. */
input[type="number"],
.details-line-div input,
.details-line-half-div input,
.details-line-sides-div input,
.corner-sub-line input,
.details-line-star-div input,
.line-width-input,
.stroke-width-input,
.miter-limit-text-input,
.scale-skew-input,
.star-depth,
.alpha-input,
.color-part-input,
.gradient-stop-position-input,
.gradient-offset-input,
.shadow-offset-input,
.delay-input,
.font-div-size,
.stroke-dashes-text-input,
.line-dashes-text-input {
  text-align: var(--number-input-align, right);
}

/* Secondary (Level-2) disclosure triangle. The triangle element fills the
   panel-indent..panel-level-2 band (its parent row's margin-left is
   panel-indent, so the triangle starts there). Inside the element, the
   12px image sits at the same offset as the Level-1 section triangle —
   nudged 1px right of the band's natural center — and the title that
   follows starts at panel-level-2. */
.corners-triangle,
.line-width-triangle {
  margin: 0;
  padding: 4px var(--panel-triangle-pad-right) 4px var(--panel-triangle-pad-left);
  box-sizing: content-box;
  height: var(--panel-triangle-size);
  width: var(--panel-triangle-size);
  opacity: var(--editor-icon-muted-opacity);
  vertical-align: middle;
  cursor: pointer;
  position: relative;
  z-index: 25;
}

.section-triangle {
  margin: 0px 0px 0px 3px;
  /* opacity is set in the code */
  padding: 3px;
  height: 12px;
  width: 12px;
  position: relative;
  z-index: 25;
}

#item-dim-0 {
  width: 45px;
}

#item-dim-side {
  width: 45px;
}

.corners-icon {
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  opacity: var(--editor-icon-muted-opacity);
  /* Reserve a dimension-label-width (14px) box so the edit box lines up with
     the W/H / angle boxes, but render the corner glyph at its native ~8px size
     (object-fit: none) centered in that box — spacing, not a bigger icon. */
  width: 14px;
  height: 14px;
  object-fit: none;
  object-position: center;
  vertical-align: middle;
}

/* Per-corner radius list (VIDimensions): one corner on its own line, indented a
   step under the main corner field (level 2). Each line is the corner's label —
   a corner icon for rectangles, "Corner N" text for every other 3-12-sided
   shape — followed by a roomy edit box. */
.corner-sub-line {
  padding-top: var(--details-row-pad);
  padding-bottom: var(--details-row-pad);
  padding-left: var(--panel-indent);
  padding-right: var(--panel-right-gutter);
}
.corner-sub-line .vi-dim {
  display: flex;
  align-items: center;
  gap: var(--panel-checkbox-label-gap);
}
.corner-sub-line .vi-dim input {
  flex: 1 1 0;
  min-width: 0;
  max-width: 150px;
  box-sizing: border-box;
  padding: var(--editor-control-pad-y) 4px;
  font-size: var(--editor-control-font-size);
  line-height: var(--editor-control-line-height);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}
.corner-sub-line .corners-icon {
  flex: 0 0 auto;
}
/* "Corner N" text label — fixed column so the edit boxes line up. Beats the
   generic `.details-div p` width via the two-class selector. */
.corner-sub-line .corner-sub-label {
  flex: 0 0 auto;
  width: 60px;
  margin: 0;
  font-size: var(--editor-control-font-size);
  line-height: normal;
  color: var(--editor-muted-text-color);
  user-select: none;
  white-space: nowrap;
}

.star-depth-slider[type="range"]::after,
.adornment-size-slider[type="range"]::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 8px;
  transform: translate(-1px, -50%);
  background: currentColor;
  opacity: .35;
  pointer-events: none;
}

.details-line-star-div input {
  display: inline-block;
  position: relative;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
}

.star-depth {
  display: inline-block;
  width: 42px;
  margin-left: 10px;
}

.details-line-div input,
.details-line-half-div input,
.details-line-sides-div input {
  display: inline-block;
  width: 60px;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

/* Formula-capable dimension inputs (X / Y / W / H, angle, corner radius,
   corner count, side) grow to use leftover row width so a longer
   expression like 50{(count+5)*5} stays readable — but `max-width` caps
   the growth so a lone field in a wide row doesn't stretch the whole
   panel. A descendant selector is required: the VIDimension input sits
   inside a `display:contents` `.vi-dim` wrapper, so a `>` child
   combinator wouldn't match it. */
.details-line-half-div input,
.details-line-sides-div input {
  flex: 1 1 0;
  width: auto;
  min-width: 44px;
  max-width: 150px;
}

/* The Angle row's edit box grows with the panel (no 150px cap), so its right
   edge always sits 8px to the left of the Reset button's left edge. The Reset
   button keeps its place at the row's right; the box fills the gap up to it. */
.details-line-half-div.details-line-angle input {
  max-width: none;
}
.details-line-angle .angle-reset {
  margin-left: 8px;
}

/* W / H rows: the box grows to fill (no 150px cap) so the size-token link is
   pushed to the row's right edge, leaving the standard pair-gap between it and
   the brace — otherwise a capped input leaves a variable gap to the bracket. */
.details-line-half-div.dim-size-line input {
  max-width: none;
}
/* The token link's own right padding would otherwise sit ON TOP of the pair-gap,
   pushing the glyph ~3px further from the brace than the standard spacing. Trim
   it on the W/H rows so the link is flush at the lines' edge and there is only
   the standard pair-gap between it and the brace. */
.details-line-half-div.dim-size-line .token-link-btn {
  padding-right: 0;
}

/* Per-dimension lock toggle (X / Y / W / H / angle). Faded open padlock when
   unlocked; solid when locked. */
.dim-lock {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  margin-left: 2px;
  border: none;
  background: transparent;
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  opacity: 0.4;
  transition: opacity 0.1s ease, background-color 0.1s ease;
}

.dim-lock:hover {
  opacity: 1;
}

.dim-lock-on,
.dim-lock-on:hover {
  opacity: 1;
}

.dim-lock img {
  width: 14px;
  height: 14px;
  display: block;
}

/* The size padlock (lock.svg) ships as neutral grey #a8a8a8 and reads well in
   both themes. The aspect chain (linked/unlinked.svg) ships as BLACK, so it's
   low-contrast in dark mode. Recolour the chain to that same grey — invert(1)
   turns black to white, brightness(0.659) drops it to #a8a8a8 — so both locks
   match in light AND dark mode. */
.dim-aspect-lock img {
  filter: invert(1) brightness(0.659);
}

/* Size (W/H) row: the two dimension lines stack vertically (each full-width so both
   have room), and the size lock sits vertically centred to their right — kept at the
   same right edge as the X/Y position lock — with a brace showing it groups both. */
.dim-size-row {
  align-items: center;
}
.dim-size-lines {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--details-row-gap);
  /* W↔H are spaced by the row-gap above; the W/H lines drop their own padding.
     Carry the half-gap on the block's outer edges so the Reference-Point→W and
     H→Angle gaps are a full inter-row gap, not just the neighbour's half. */
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
/* Each W/H line now spans the whole lines column (overrides the side-by-side flex:1
   the plain `.dim-row .details-line-half-div` rule would otherwise apply). */
.dim-size-lines .details-line-half-div.dim-size-line {
  flex: 0 0 auto;
  width: 100%;
  /* The W/H rows are spaced by the .dim-size-lines row-gap, so drop their own
     row padding to avoid doubling it. */
  padding-top: 0;
  padding-bottom: 0;
}
.dim-size-lock {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1px;
  /* The row's flex gap is the wide --panel-pair-gap (for separating the X|Y /
     W|H pairs). The brace is not a pair separator — it hugs the size fields — so
     pull it in to the standard adjacent-control gap. The lines column (flex:1)
     absorbs the reclaimed width, so the link slides toward the brace while the
     lock stack stays right-aligned with the X/Y position lock above. */
  margin-left: calc(var(--panel-control-gap) - var(--panel-pair-gap));
}
.dim-size-brace {
  flex: 0 0 auto;
  color: var(--editor-muted-text-color);
}
/* Size padlock stacked over the aspect-ratio link, both centred on the brace. */
.dim-size-lock-stack {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.details-div-heading,
.prototype-div-heading {
  text-align: left;
  margin: 0;
  user-select: none;
  display: inline-block;
  vertical-align: middle;
  color: var(--header-2-color);
}

/* Sections without a disclosure triangle render the heading as the first
   child of .details-header. Indent it to match the title-text position of
   triangled sections (the triangle is panel-indent wide, so triangled
   headings start at panel-indent automatically). */
.details-header > .details-div-heading:first-child,
.details-header > .prototype-div-heading:first-child {
  margin-left: var(--panel-indent);
}

.details-div-heading-descr {
  font-size: var(--editor-control-font-size);
  vertical-align: middle;
}

.details-div-group,
.prototype-div-group {
  padding: 10px 0;
  line-height: normal;
  /* Without this the whole prototype panel inherits the browser-default serif (Times New Roman)
     — the design panel sets it, the prototype panel didn't. */
  font-family: var(--editor-font-family);
}

/* Vertical breathing room between consecutive rows inside a section,
   so lines don't crowd against each other.
.details-div-group > .details-line-div,
.details-div-group > .details-line-half-div,
.details-div-group > .stroke-details-div,
.details-div-group > .line-details-div,
.details-div-group > .image-details-div,
.details-div-group > .stroke-options-group,
.details-div-group > .color-details-div,
.details-div-group > .shadow-div,
.details-div-group > .section-content-row {
  margin-top: var(--panel-row-gap);
}
*/
/* Floating toolbar submenus and editor canvas containers. */
.chevron-icon {
  position: absolute;
  top: 22px;
  left: var(--chevron-left);
  opacity: var(--editor-icon-muted-opacity);
  user-select: none;
}

.toolbar-submenu {
  position: absolute;
  left: var(--left-toolbar-width);
  background-color: var(--left-toolbar-background-color);
  height: var(--standard-icon-height);
  /* top is calculated in the javascript */
  z-index: 100;
}

#canvas-div {
  position: absolute;
  overflow: hidden;
  top: var(--top-toolbar-height);
  left: calc(var(--left-toolbar-width) + var(--tree-width));
  bottom: 0px;
  right: var(--details-width);
  z-index: 0;
  background-color: var(--canvas-background-color);
  /* The canvas is a drawing surface — never a text field. Without this, a
     click-drag on it (e.g. across an entity node's rendered text on the Data
     tab) starts a native browser text selection. Inherited by the <canvas>. */
  user-select: none;
}

/* Floating save/load status pill centered near the top of the canvas. */
.canvas-notification {
  position: absolute;
  top: 1.2rem;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(24, 24, 28, 0.80);
  color: #fff;
  padding: 0.4rem 1.1rem;
  border-radius: 999px;
  font-size: 0.88rem;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  z-index: 50;
  letter-spacing: 0.02em;
}

/* Blank-canvas message shown when no page is visible (all pages hidden, or the
   single active page is hidden). Centred over the empty canvas. */
.canvas-empty-message {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #555555;
  font-size: 1.25rem;
  font-weight: 700;
  pointer-events: none;
  z-index: 40;
  text-align: center;
}

#prototype-canvas-div {
  position: absolute;
  overflow-y: auto;
  overflow-x: auto;
  /* Anchor below the top toolbar (matches #canvas-div). Otherwise the
     canvas extends behind the toolbar, and a frame stretched to fill the
     canvas vertically tucks its top under the toolbar. */
  top: var(--top-toolbar-height);
  left: 0;
  bottom: 0;
  right: 0;
  background-color: black;
}

/* When the page hides the prototype top toolbar, the canvas takes the
   full viewport height (no toolbar offset to compensate for). Escape
   stops playback in this mode. */
.prototype-no-toolbar #prototype-canvas-div {
  top: 0;
}

.canvas,
.prototype-canvas {
  position: absolute;
  display: block;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  outline: none;
}

/* Frame-to-frame transition overlay: laid exactly over the playback canvas,
   click-through, shown only while a transition tween is running. */
.prototype-transition-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

/* Focus indicator: shows when the editor canvas has keyboard focus so the user
   knows that canvas-only shortcuts (arrow nudge, eyedropper Enter, etc.) will
   fire. The prototype-canvas is excluded — during playback the canvas is the
   "screen" the user is interacting with, and a focus ring around it reads as
   a stray editor chrome leak. outline-offset: -2px keeps the ring inside the
   canvas so layout doesn't shift. Color matches TColor.selection (paint.ts). */
.canvas:focus {
  outline: 2px solid var(--editor-selected-blue);
  outline-offset: -2px;
}

/* Hidden assets and custom cursor images used by the canvas. */
.selected-icon {
  display: inline-block;
  flex: 0 0 auto;
  width: 16px;
  height: 12px;
  background-color: var(--selection-color, var(--editor-selected-blue, #1097e2));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* Layers-mode indicator: a selection-coloured VERTICAL line filling the row's
   full height in the caret's 16px slot. Rows abut with no gap, so each row's
   segment joins its neighbours into ONE continuous line down the whole list.
   A direct flex child of .page-list-item (align-self stretch = full height). */
.selected-line {
  flex: 0 0 auto;
  align-self: stretch;
  width: 16px;
  position: relative;
  cursor: pointer;
}
.selected-line::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  transform: translateX(-50%);
  background-color: var(--selection-color, var(--editor-selected-blue, #1097e2));
  transition: width 0.08s ease, filter 0.08s ease;
}
/* Hovering the line over a row highlights just that row's segment — the bar
   brightens and thickens so you can see which layer you're pointing at. */
.selected-line:hover::before {
  width: 4px;
  filter: brightness(1.5);
}

#rotation-cursor {
  position: relative;
  left: -99999px;
  height: 20px;
  width: 20px;
}

#pen-cursor {
  position: relative;
  left: -99999px;
  height: 25px;
  width: 14px;
}

#eyedropper-cursor {
  height: 25px;
  user-select: none;
  z-index: 750;
}

/* Page, fill, stroke, gradient, behavior, and ring add/remove controls.
   The page add/delete divs are flex items of .page-header-row, centred on
   its line — no float. The right-edge gap comes from the row's
   padding-right; the plus (rightmost) needs no margin of its own. */
.page-add-div {
  display: flex;
  align-items: center;
  margin: 0;
}

.fill-add-div,
.stroke-add-div,
.gradient-add-div {
  display: inline-flex;
  align-items: center;
  margin: 0 var(--panel-control-gap) 0 0;
}

.add-fill-icon,
.add-palette-color-icon,
.add-stroke-icon,
.add-variable-icon,
.unify-paint-icon,
.add-trigger-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.page-delete-div {
  display: flex;
  align-items: center;
  margin: 0 5px 0 0;
}

/* Extra layer tools (Group, Add-folder) sit left of the delete/add (−/+) pair;
   a right gap keeps them from reading as part of that pair. */
.layer-tool-div {
  margin-right: 11px;
}

.fill-delete-div,
.stroke-delete-div,
.gradient-delete-div,
.delete-gradient-color-div,
.delete-behavior-div,
.delete-ring-div {
  display: inline-flex;
  align-items: center;
  margin: 0 var(--panel-control-gap) 0 0;
}

.ring-shift-div {
  display: inline-flex;
  align-items: center;
  /* Up/down arrows start 8px to the right of the "Ring N" name. */
  margin: 0 var(--panel-control-gap) 0 8px;
}

/* The "Ring N" name sits right after the disclosure triangle, so it lands at level 1
   (one --panel-indent from the left) like every other section heading — no extra shift. */
.details-header > .ring-heading {
  margin-left: 0;
}

.add-behavior-div,
.variable-add-div,
.trigger-add-div {
  display: inline-flex;
  align-items: center;
  margin: 0 var(--panel-control-gap) 0 0;
}

.delete-color-icon,
.delete-stroke-icon,
.delete-gradient-icon,
.delete-gradient-color-icon,
.delete-behavior-icon,
.delete-ring-icon,
.variables-delete-icon,
.delete-trigger-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

.add-behavior-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  user-select: none;
  vertical-align: middle;
}

/* Standard accent add/remove button: an inline +/- glyph stroked in the theme
   accent (see AccentIcon.tsx) — only the glyph is coloured, not a box. Sized to
   the standard small-icon box so all +/- buttons match; muted at rest and
   brightened on hover, like the left-panel page-list +/- buttons. */
.accent-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--editor-small-icon-size);
  height: var(--editor-small-icon-size);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  vertical-align: middle;
  opacity: var(--editor-icon-muted-opacity);
}
/* Hover brightens the glyph itself (muted -> full), matching the left-panel
   page-list +/- buttons — not a painted background behind it. */
.accent-icon-btn:hover { opacity: 1; background-color: transparent; }
/* The glyph fills the standard small-icon box, so themed +/- match the size of
   the image-based add/remove icons everywhere. */
.accent-icon-btn > svg { display: block; width: var(--editor-small-icon-size); height: var(--editor-small-icon-size); }

/* Color, fill, stroke, line, and selection color controls. */
/* Color swatch that opens the color picker — sized and styled to match
   the gradient color-stop swatches. */
.color-div {
  height: 20px;
  width: 28px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  display: inline-block;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  flex: 0 0 auto;
  cursor: pointer;
}

.fill-details-div label {
  display: inline;
  margin: 0px;
  position: relative;
  font-size: 14pt;
  top: -10px;
  user-select: none;
}

.color-text-input {
  width: 72px;
  box-sizing: border-box;
  padding: 2px 4px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

/* Opacity %. Styled and behaving like the scale / skew percentage
   boxes — the "%" lives inside the box (no trailing label). */
.alpha-input {
  width: 52px;
  box-sizing: border-box;
  padding: 2px 4px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

.gradient-stop-position-input {
  position: relative;
  width: 25px;
  margin: 0 3px;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
}

/* Level-1 row: width is left auto so it fills the panel content area
   live as the panel resizes, keeping the right-aligned sight controls
   pinned to the panel's right edge. */
.color-details-div {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin-left: var(--panel-indent);
  position: relative;
}
/* The Selection Colors rows reuse .color-details-div, so they already inherit
   the design-panel inter-row gap (--details-row-pad) — the same as the Fill /
   Stroke colour rows. They are NOT treated as a dense name list (Pages /
   Layers), so they honour the standard inter-line gap, not --list-row-gap. */

/* Token link/unlink indicator. Absolutely placed (out of flow) so the colour
   swatch stays flush at panel-indent — lined up with the section heading text —
   while the icon is horizontally centred in the indent gutter between the panel
   edge and the swatch. High z-index so a slider handle never covers it.
   Faint when unlinked. */
.token-link-icon {
  position: absolute;
  left: calc(var(--panel-indent) / -2 - 6px);
  top: 50%;
  transform: translateY(-50%);
  width: 12px;
  height: 12px;
  opacity: 0.3;
  cursor: default;
  z-index: 30;
}
.token-link-icon.linked {
  opacity: 1;
  cursor: pointer;
}

/* Generic Level-1 row wrapper: --details-row-height tall (min), flex with
   align-items: center, indented to panel-indent. Use this for single-control
   rows and for icon rows whose icons fill the row height (like the Text
   align icons). The vertical padding adds breathing room above and below
   the children, so a row of full-height icons reads with the same visual
   spacing as a row of text + input. */
.section-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin-left: var(--panel-indent);
}

.stroke-details-div,
.line-details-div,
.image-details-div {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin-left: var(--panel-indent);
  /* Right gutter so the width input (which now grows to fill the row)
     stops short of the panel edge. */
  margin-right: var(--panel-right-gutter);
}

.fill-details-div p {
  width: 100%;
  text-align: left;
}

.stroke-details-div p {
  width: 100%;
  text-align: left;
}

.line-width-icon,
.stroke-width-icon {
  width: 16px;
  height: 16px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  opacity: var(--editor-icon-muted-opacity);
  vertical-align: middle;
}

.line-width-input,
.stroke-width-input {
  position: relative;
  /* Formula-capable — grow into spare row width but cap the growth so a
     lone width field doesn't stretch across the whole panel. */
  flex: 1 1 0;
  width: auto;
  min-width: 40px;
  max-width: 150px;
  margin: 0 var(--panel-control-gap) 0 0;
  vertical-align: middle;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
}

/* .line-width-triangle shares its layout rule with .corners-triangle above. */

.stroke-dashes-label,
.line-dashes-label {
  display: inline-block;
  width: auto;
  /* Keep the "D, Gap (unit)" label on one line — it sat in a flex row that let
     it shrink and wrap. The room it needs is taken off the input's left (see
     the narrower .*-dashes-text-input width below). */
  flex-shrink: 0;
  white-space: nowrap;
  font-size: var(--editor-control-font-size);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  text-align: left;
  vertical-align: middle;
}

/* Dash / gap row: small label→input gap, modest input→Auto gap, and
   every item vertically centered. The shared is-auto-dashes rules add
   stray top offsets, so re-flatten them within the dash rows. */
.stroke-details-div .is-auto-dashes-label,
.line-details-div .is-auto-dashes-label {
  display: inline-flex;
  align-items: center;
  margin: 0 0 0 13px;
}

.stroke-details-div .is-auto-dashes-checkbox,
.line-details-div .is-auto-dashes-checkbox {
  position: static;
  top: 0;
  margin: 0 4px 0 0;
}

.stroke-dashes-text-input,
.line-dashes-text-input {
  position: relative;
  /* Narrowed from 110px to give the "D, Gap (unit)" label a little more room on
     its left so it never wraps; a dash/gap value is short and still fits. The
     label holds its width (flex-shrink: 0 above), so if a row is ever tighter
     still, this input yields rather than the label wrapping. */
  width: 100px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

/* Match count + sight icon, pushed to the right edge of the color row.
   Flex (not float) so the count and icon align on the row's centre line;
   flex: none so the group keeps its natural width and never clips. */
.sight-div {
  display: flex;
  align-items: center;
  /* Fill the row's free space (after the swatch + hex + alpha) so the count
     inside can right-align against the icon instead of sitting content-width. */
  flex: 1 1 auto;
  /* No vertical padding: the enclosing .color-details-div row already supplies
     the inter-row gap. Padding here made the sight-div the tallest child and
     inflated every selection-colour row by an extra 2 × --details-row-pad. */
}

.sight-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: 20px;
  /* Keep a comfortable click target horizontally, but don't let the vertical
     padding inflate the color row taller than the swatch/hex it sits beside. */
  padding: 2px 7px;
  user-select: none;
}


/* Clickable panel icons — the section plus / minus add & delete icons,
   the selection-colors targeting icon, the path-operation icons, and the
   pen-ring icons — get a top-toolbar-style hover background. It sits on
   the icon element itself so it hugs the icon's own box and never shifts
   the surrounding layout the way a padded toolbar button would. */
.add-fill-icon,
.add-palette-color-icon,
.add-stroke-icon,
.add-variable-icon,
.unify-paint-icon,
.add-trigger-icon,
.delete-color-icon,
.delete-gradient-color-icon,
.delete-gradient-icon,
.delete-ring-icon,
.delete-stroke-icon,
.variables-delete-icon,
.delete-trigger-icon,
.page-list-plus-icon,
.page-list-minus-icon,
.sight-icon,
.group-icon,
.union-icon,
.outline-icon,
.subtract-icon,
.exclude-icon,
.intersect-icon,
.mask-icon,
.pen-icon,
.ring-icon {
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
}

.add-fill-icon:hover,
.add-palette-color-icon:hover,
.unify-paint-icon:hover,
.add-stroke-icon:hover,
.add-variable-icon:hover,
.add-trigger-icon:hover,
.delete-color-icon:hover,
.delete-gradient-color-icon:hover,
.delete-gradient-icon:hover,
.delete-ring-icon:hover,
.delete-stroke-icon:hover,
.variables-delete-icon:hover,
.delete-trigger-icon:hover,
.page-list-plus-icon:hover,
.page-list-minus-icon:hover,
.sight-icon:hover,
.group-icon:hover,
.union-icon:hover,
.outline-icon:hover,
.subtract-icon:hover,
.exclude-icon:hover,
.intersect-icon:hover,
.mask-icon:hover,
.pen-icon:hover,
.ring-icon:hover {
  background-color: transparent;
  opacity: 1;
}

/* Plus / minus add & delete icon-buttons: a slightly larger clickable area,
   and a hover that brightens only the glyph rather than painting a background. */
.add-fill-icon,
.add-palette-color-icon,
.unify-paint-icon,
.add-stroke-icon,
.add-behavior-icon,
.add-variable-icon,
.add-trigger-icon,
.delete-color-icon,
.delete-stroke-icon,
.delete-gradient-icon,
.delete-gradient-color-icon,
.delete-behavior-icon,
.delete-ring-icon,
.variables-delete-icon,
.delete-trigger-icon,
.page-list-plus-icon,
.page-list-minus-icon,
.minus-variable-icon,
.remove-groups-icon {
  box-sizing: content-box;
  padding: 1px;
  cursor: pointer;
}

.add-fill-icon:hover,
.add-palette-color-icon:hover,
.unify-paint-icon:hover,
.add-stroke-icon:hover,
.add-behavior-icon:hover,
.add-variable-icon:hover,
.add-trigger-icon:hover,
.delete-color-icon:hover,
.delete-stroke-icon:hover,
.delete-gradient-icon:hover,
.delete-gradient-color-icon:hover,
.delete-behavior-icon:hover,
.delete-ring-icon:hover,
.variables-delete-icon:hover,
.delete-trigger-icon:hover,
.page-list-plus-icon:hover,
.page-list-minus-icon:hover,
.minus-variable-icon:hover,
.remove-groups-icon:hover,
.ring-icon:hover,
.sight-icon:hover {
  background-color: transparent;
  opacity: 1;
}

.corner-count-icon {
  opacity: var(--editor-icon-muted-opacity);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  height: 14px;
  user-select: none;
  vertical-align: middle;
}

/* Angle dimension glyph — replaces the old "A" text label. */
.angle-icon {
  opacity: var(--editor-icon-muted-opacity);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  width: 14px;
  height: 14px;
  user-select: none;
  vertical-align: middle;
}

.star-ratio-icon {
  opacity: var(--editor-icon-muted-opacity);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  height: 14px;
  user-select: none;
  vertical-align: middle;
}

/* Text, typography, media, alignment, and shape option controls. */
#text-area {
  font-family: var(--editor-font-family);
  position: absolute;
  display: block;
  border: none;
  outline: none;
  padding: 0;
  background: transparent;
  font-size: var(--editor-control-font-size);
  font-weight: normal;
  line-height: 1.25em;
  resize: none;
  color: black;
  z-index: 100;
  user-select: all;
  overflow: hidden;
  white-space: break-spaces;
  overflow-wrap: normal;
}

.font-div {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin-left: var(--panel-indent);
  /* Leave the standard right gutter so a row's last control (the size-unit combo,
     the Italic label, the Letter box) can't run to or past the panel edge. */
  margin-right: var(--panel-right-gutter);
}

.font-div label {
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}

.font-div input {
  border: var(--editor-control-border);
  outline-color: var(--editor-text-color);
  color: var(--editor-text-color);
}

.font-div input.font-div-font {
  margin-right: var(--panel-pair-gap);
}

.font-div input.font-div-size {
  margin-right: var(--panel-control-gap);
}

/* Line / letter spacing row. The Line label sits at the full level-1 indent
   (like the Font label), and the Letter label gets the same gap that separates
   the Font and Size boxes (--panel-pair-gap), placed before it via the line
   input's right margin. */
.text-spacing-div {
  margin-left: var(--panel-indent);
}
/* Keep the two-word labels ("¶ Space", "Indent", "Letter") on one line — a flex
   item shrinks to min-content by default, which broke "¶ Space" onto two lines. */
.text-spacing-div label {
  white-space: nowrap;
  flex: 0 0 auto;
}
.text-spacing-input {
  width: 52px;
}
.text-spacing-div input.line-spacing-input {
  margin-right: var(--panel-pair-gap);
}

/* The text alignment row's .section-row already provides the level-1 indent;
   cancel the nested .align-div's own indent so the icons start at level 1
   instead of stacking to level 2. The vertical-align group keeps its gap. */
.text-align-row > .align-div:first-child {
  margin-left: 0;
}
/* Between-group gap to the vertical-align group — matches the Image section's
   groups (was a full --panel-indent, which read as too large). */
.text-align-row > .align-div:last-child {
  margin-left: 16px;
}

.is-vertex-up-checkbox,
.is-equilateral-checkbox,
.is-even-odd-checkbox,
.is-closed-checkbox,
.is-auto-dashes-checkbox {
  position: relative;
  top: 2px;
  margin: 0 var(--panel-checkbox-label-gap) 0 0px;
}

.is-vertex-up-label,
.is-equilateral-label,
.is-even-odd-label,
.is-is-closed-label,
.is-auto-dashes-label {
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  margin: 0 0 0 3px;
  color: var(--editor-muted-text-color);
  user-select: none;
}

.is-italic-checkbox {
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  vertical-align: middle;
}

.is-radial-checkbox {
  position: relative;
  top: 2px;
  margin: 0 var(--panel-checkbox-label-gap) 0 12px;
}

#is-italic-label,
#is-radial-label {
  font-size: var(--editor-control-font-size);
  margin: 0;
  user-select: none;
  vertical-align: middle;
}

.font-div-font {
  width: 120px;
}

/* The font-family field fills its row (font names run long — "Franklin Gothic
   Medium", "Segoe UI Historic"), with the size box fixed on the right. The row
   leaves the standard right gutter, and the Style dropdown above fills to the
   same edge so the two wide controls line up. */
.font-family-row {
  margin-right: var(--panel-right-gutter);
}
.font-family-row .font-div-font {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
}
/* Size box sits at the row's right edge — drop its trailing gap so its right
   edge lines up with the Style dropdown above (both at the gutter). Needs the
   `input` to out-specify `.font-div input.font-div-size`. */
.font-family-row input.font-div-size {
  margin-right: 0;
}

.font-div-size {
  width: 50px;
  /* flex-basis (not width) wins in the flex .font-div row, so the broad
     `.details-scroll input { width: 100% }` override can't stretch the
     size box off the panel edge. */
  flex: 0 0 50px;
}

/* Size combo: the number field + a caret that opens the common-sizes dropdown. */
.sizepicker {
  display: inline-flex;
  align-items: center;
  position: relative;
  flex: 0 0 auto;
  margin-right: var(--panel-control-gap);
}
/* No gap between the field and its caret — they read as one control. */
.font-div .sizepicker input.font-div-size {
  margin-right: 0;
}
.sizepicker-caret {
  flex: 0 0 auto;
  width: 16px;
  height: 22px;
  margin-left: 2px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg);
  color: var(--editor-text-color);
  cursor: pointer;
  font-size: 10px;
  line-height: 1;
}
.sizepicker-caret:hover { color: var(--editor-selected-blue); }
/* Right-align the numbers so they line up with the field's value. */
.sizepicker-item {
  justify-content: flex-end;
  font-variant-numeric: tabular-nums;
}

.font-weight-types {
  /* Fill the row and SHRINK if needed. flex-basis (in the shorthand) beats the
     `.details-scroll select { width: 100% }` rule, which would otherwise make
     this select 100% wide and push its row-mates (Italic, the decoration
     buttons) off the panel edge. */
  flex: 1 1 0;
  min-width: 0;
  margin-right: var(--panel-pair-gap);
  border: var(--editor-control-border);
  outline-color: var(--editor-text-color);
  color: var(--editor-text-color);
  vertical-align: middle;
}

/* Font-size unit combo — sits right after the size box on the Size line. Fixed width +
   no-grow so a long unit name can't stretch the Size row past the panel gutter.
   flex-basis (not `width`) pins it, since `.details-scroll select { width: 100% }`
   out-specifies a plain width and would otherwise blow the size unit off the edge. */
.font-unit-types {
  flex: 0 0 56px;
  box-sizing: border-box;
  min-width: 0;
  border: var(--editor-control-border);
  outline-color: var(--editor-text-color);
  color: var(--editor-text-color);
  vertical-align: middle;
}

/* ---- Measurement rows (Size / Line / Letter / ¶ Space / Indent) ----
   Each measurement sits on its OWN line as a 3-column grid — label | value |
   unit ("measurement type") — so the value fields and the unit controls line up
   down the whole group. Size uses a dropdown (many units); the others use a
   two-cell segmented toggle (like the Area/Point type switcher). Overrides the
   .font-div flex layout for these rows only. */
.measure-row.font-div {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 62px;
  align-items: center;
  column-gap: var(--panel-control-gap, 8px);
}
.measure-row > label {
  margin: 0;
  white-space: nowrap;
  justify-self: start;
}
.measure-row .measure-input {
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  /* Numeric field — honour the Number-alignment preference (Customize) like the
     other numeric edit boxes (the unit now lives in the toggle, so these hold a
     bare number). */
  text-align: var(--number-input-align, right);
}
select.measure-unit {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  margin: 0;
  border: var(--editor-control-border);
  outline-color: var(--editor-text-color);
  color: var(--editor-text-color);
  vertical-align: middle;
}
/* Segmented unit toggle (× / % and px / em) — two equal cells filling the unit
   column, reusing the align-cell selected highlight from the alignment icons. */
.measure-unit-seg {
  display: flex;
  width: 100%;
  gap: 2px;
}
.measure-unit-cell.align-icon-cell {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  padding: 1px 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  line-height: 1.4;
}
/* The Size row's FontSizePicker fills the value column like the plain inputs;
   its inner number field grows to fill the picker, leaving room for the caret. */
.measure-row .sizepicker {
  width: 100%;
  margin: 0;
}
.measure-row .sizepicker input.font-div-size {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
}

/* ---- Font picker (replaces the old font-family datalist input) ---- */
/* Trigger looks like the other row controls and fills the family row, with the
   current family previewed in its own typeface. */
.fontpicker-trigger {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  height: var(--editor-control-height, 24px);
  padding: 0 6px;
  background: var(--editor-panel-background-color);
  border: var(--editor-control-border);
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  cursor: pointer;
  text-align: left;
}
.fontpicker-trigger.mixed .fontpicker-trigger-label { color: var(--editor-muted-text-color); }
.fontpicker-trigger-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.fontpicker-caret {
  flex: 0 0 auto;
  font-size: 10px;
  color: var(--editor-muted-text-color);
}

/* Popover (portaled to <body>, fixed-positioned to the trigger). */
.fontpicker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 999;
}
.fontpicker-pop {
  z-index: 1000;
  display: flex;
  flex-direction: column;
  max-height: 330px;
  background: var(--editor-panel-background-color);
  border: 1px solid var(--editor-panel-separator-color);
  border-radius: 6px;
  box-shadow: 0 8px 28px -10px rgba(0, 0, 0, 0.4);
  overflow: hidden;
}
.fontpicker-search {
  flex: 0 0 auto;
  margin: 6px;
  padding: 5px 8px;
  border: var(--editor-control-border);
  border-radius: 4px;
  background: var(--editor-panel-background-color);
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  outline-color: var(--editor-selected-blue);
}
.fontpicker-list {
  flex: 1 1 auto;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0 0 6px;
}
.fontpicker-group { list-style: none; }
.fontpicker-group-label {
  position: sticky;
  top: 0;
  padding: 5px 10px 3px;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--editor-muted-text-color);
  background: var(--editor-panel-background-color);
}
.fontpicker-group-items { list-style: none; margin: 0; padding: 0; }
.fontpicker-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  cursor: pointer;
  color: var(--editor-text-color);
  font-size: 15px;
  line-height: 1.25;
}
.fontpicker-item:hover { background: color-mix(in srgb, var(--editor-selected-blue) 18%, transparent); }
.fontpicker-item.selected { background: color-mix(in srgb, var(--editor-selected-blue) 30%, transparent); }
.fontpicker-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.fontpicker-badge {
  flex: 0 0 auto;
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--editor-muted-text-color);
  font-family: var(--editor-font-family);
}
.fontpicker-empty { padding: 12px; color: var(--editor-muted-text-color); font-size: var(--editor-control-font-size); }
.fontpicker-spin {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border: 1.5px solid var(--editor-muted-text-color);
  border-top-color: transparent;
  border-radius: 50%;
  animation: fontpicker-spin 0.7s linear infinite;
}
.fontpicker-err { flex: 0 0 auto; color: #c0392b; font-weight: 700; }
.fontpicker-footer {
  flex: 0 0 auto;
  border-top: 1px solid var(--editor-panel-separator-color);
  padding: 6px;
}
.fontpicker-upload {
  width: 100%;
  padding: 6px 8px;
  background: transparent;
  border: 1px dashed var(--editor-panel-separator-color);
  border-radius: 4px;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  font-family: var(--editor-font-family);
  cursor: pointer;
}
.fontpicker-upload:hover:not(:disabled) { border-color: var(--editor-selected-blue); color: var(--editor-selected-blue); }
.fontpicker-upload:disabled { opacity: 0.6; cursor: default; }
@keyframes fontpicker-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .fontpicker-spin { animation: none; } }

/* Variable-weight slider + OpenType (small caps / kerning / width) rows. */
.variable-weight-row { gap: 8px; }
.variable-weight-slider {
  flex: 1 1 auto;
  min-width: 0;
  accent-color: var(--editor-selected-blue);
}
.variable-weight-value {
  flex: 0 0 auto;
  min-width: 28px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}
.opentype-row .opentype-label {
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  user-select: none;
  margin: 0 14px 0 3px;
}
/* Wraps a checkbox + its label so the pair can carry one data-help entry (the
   Checkbox component itself drops unknown props). Inline-flex keeps the original
   inline layout; inner margins (checkbox gap, label 14px trailing) are unchanged. */
.opentype-toggle {
  display: inline-flex;
  align-items: center;
}
.deco-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: 8px;
  border: var(--editor-control-border);
  border-radius: 3px;
  cursor: pointer;
  font-size: 13px;
  color: var(--editor-text-color);
  user-select: none;
}
/* The B/I/U/S buttons are TOGGLES: a subtle resting state, and a clear filled
   "engaged" state (blue fill + white glyph) so an active style reads at a glance
   — the standard formatting-toggle convention. */
.deco-btn:hover:not(.deco-btn-on) {
  border-color: var(--editor-selected-blue);
  color: var(--editor-selected-blue);
}
.deco-btn-on {
  border-color: var(--editor-selected-blue);
  background: var(--editor-selected-blue);
  color: #fff;
}
.deco-btn-b { font-weight: 800; }

/* Rich-text formatting toolbar (B / I / U / S) — the visible entry point for
   styling text, or a selected range while editing on the canvas. */
.text-format-row { gap: 4px; }
.text-format-row .deco-btn { margin-left: 0; }
.text-rich-hint {
  flex: 1 1 0;
  min-width: 0;
  margin-left: 8px;
  font-size: 10.5px;
  line-height: 1.25;
  color: var(--editor-muted-text-color);
  user-select: none;
}

.align-div {
  display: inline-flex;
  align-items: center;
  margin: 0 0 0 var(--panel-indent);
}

.align-items-section {
  padding: 6px 0;
}
/* Both align groups (horizontal / vertical) sit on ONE line at the standard row
   height. A bit more space between the two groups than between their icons. */
.align-items-section .align-div {
  display: inline-flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
.align-items-section .align-div + .align-div {
  margin-left: 8px;
}

.image-align-div {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* The X/Y offset row follows directly below, so no extra bottom margin
     is needed to separate the align icons from the next line. */
  margin: 0 4px 0 var(--panel-indent);
  display: block;
}

/* Frame Layout (prototype): give the align-icons row vertical breathing room,
   and widen the Width/Height label column so the labels clear their sliders —
   the flex-grow % edit box yields that width (so it shrinks). Scoped to the
   frame layout so the shared design-panel scale/skew rows are untouched. */
.frame-align-div {
  margin-top: 0;
  margin-bottom: 0;
}
.frame-scale-row .scale-skew-label {
  width: 52px;
  margin-right: 6px;
}

/* Data panel — Database Schema. A wide, monospace SQL box (paste a schema.sql or a dump),
   its buttons, and the notes underneath. The width override is deliberate: the panel's
   `.details-scroll input { width: 100% }` rule doesn't reach a textarea, so this sets its own. */
.db-schema-body {
  margin-left: var(--panel-indent);
  padding-top: var(--details-row-pad);
  padding-bottom: var(--details-row-pad);
  padding-right: 6px;
}
.db-schema-input {
  box-sizing: border-box;
  width: 100%;
  resize: vertical;
  font-family: var(--editor-mono-font-family, monospace);
  font-size: 11px;
  line-height: 1.35;
  padding: 5px 6px;
  color: var(--editor-text-color);
  background-color: var(--editor-input-bg, var(--button-bg));
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  white-space: pre;
  overflow: auto;
}
.db-schema-migration {
  margin-top: 6px;
}
.db-schema-row {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.db-schema-btn {
  flex: 0 0 auto;
  padding: var(--editor-control-pad-y) 10px;
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  font-weight: 600;
  line-height: var(--editor-control-line-height);
  color: var(--button-text);
  background-color: var(--button-bg);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
}
.db-schema-btn:hover:not(:disabled),
.db-schema-btn:active:not(:disabled) {
  background-color: var(--button-bg-hover);
}
.db-schema-btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.db-schema-note {
  margin-top: 5px;
  font-size: 11px;
  color: var(--editor-muted-text-color);
}
.db-schema-skip {
  opacity: 0.85;
}

/* Prototype backdrop: one row per theme (light / dark). The label sits at the section's
   level-1 indent and the swatch keeps its own .color-details-div indent under it. */
.proto-bg-row {
  display: block;
}
.proto-bg-label {
  display: block;
  margin-left: var(--panel-indent);
  padding-top: var(--details-row-pad);
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
/* "in use" marker on whichever theme the editor is currently viewing. */
.proto-bg-live {
  color: var(--prototype-accent);
}

/* Frame alignment X/Y offset row (prototype Frame Layout). */
.frame-offset-row {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  /* Standard inter-row gap (was a fixed 6px bottom margin, out of step with the
     other prototype rows). */
  margin: 0 4px 0 var(--panel-indent);
  padding-top: var(--details-row-pad);
  padding-bottom: var(--details-row-pad);
}
.frame-offset-field {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.frame-offset-label {
  color: var(--editor-muted-text-color);
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
}
.frame-offset-input {
  width: 52px;
  /* flex-basis (not width) survives the `.details-scroll input { width:
     100% }` override in the flex .frame-offset-field row. */
  flex: 0 0 52px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  text-align: var(--number-input-align, right);
  vertical-align: middle;
}

/* The Image section's align group sits inside .image-align-div, which
   already provides the Level-1 indent — cancel the shared .align-div indent
   here so the group starts at Level 1 rather than stacking to Level 2. */
.image-align-div .align-div {
  margin-left: 0;
}

/* The picture X/Y offset row. Sits at Level-1 indent like the rest of the
   Image section; labels and inputs use the panel's normal control font and
   the Reset button matches the other panel buttons (.export-button). */
.image-offset-div {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  column-gap: 14px;
  row-gap: 4px;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

.image-offset-field {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}

.image-offset-input {
  width: 44px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  background-color: var(--editor-input-bg);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

.image-offset-reset,
.proto-bg-reset,
.angle-reset {
  margin-left: auto;
  flex: none;
  /* Size to the same height as the edit fields: same line-height + vertical
     padding + border, so the reset button and the number box line up. */
  padding: var(--editor-control-pad-y) 12px;
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  font-weight: 600;
  line-height: var(--editor-control-line-height);
  text-align: center;
  color: var(--button-text);
  background-color: var(--button-bg);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  user-select: none;
}

.image-offset-reset:hover,
.image-offset-reset:active,
.proto-bg-reset:hover:not(:disabled),
.proto-bg-reset:active:not(:disabled),
.angle-reset:hover:not(:disabled),
.angle-reset:active:not(:disabled) {
  background-color: var(--button-bg-hover);
}

.angle-reset:disabled,
.proto-bg-reset:disabled {
  opacity: 0.45;
  cursor: default;
}

/* The backdrop rows put their swatch and Reset on one line; the swatch keeps its own
   indent and Reset sits at the far end (margin-left: auto, from the shared rule). */
.proto-bg-row .color-details-div {
  padding-right: 4px;
}

.offscreen-image {
  position: relative;
  left: -99999px;
}

.video {
  position: absolute;
  top: 100px;
  left: 200px;
}

.arrow-types {
  width: 86px;
  vertical-align: middle;
}

.arrow-icon {
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  width: 10px;
  opacity: var(--editor-icon-muted-opacity);
  vertical-align: middle;
}

/* Line-end cap picker: three selectable icons (butt / round / square)
   replacing the old cap dropdown. The selection outline lives on the
   (unfiltered) cell so it shows the true selection colour — the icon
   image itself carries the dark-mode invert filter. */
.cap-selector {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  vertical-align: middle;
}

/* A cap picker for a line end that carries an adornment — the cap is
   irrelevant there, so it is shown greyed-out and non-interactive. */
.cap-selector-disabled {
  opacity: 0.35;
  pointer-events: none;
}

.cap-icon-cell {
  display: inline-flex;
  padding: 1px;
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  user-select: none;
  outline: var(--selection-border-width) solid transparent;
  outline-offset: calc(-1 * var(--selection-border-width));
}

.cap-icon-cell:hover {
  outline-color: var(--editor-control-border-color);
}

.cap-icon-cell-selected:hover {
  outline-color: var(--editor-selected-blue);
}

/* Selected cap: identical to a pressed left-toolbar tool — same active
   background and same selection outline. The outline lives on this
   (unfiltered) cell, so it shows the true selection colour in dark
   mode rather than the brightened tint the icon filter produced. */
.cap-icon-cell-selected {
  background-color: var(--tool-active-bg, #e3e8f2);
  outline-color: var(--editor-selected-blue);
}

.cap-icon-img {
  display: block;
  width: 18px;
  height: 18px;
  opacity: var(--editor-icon-muted-opacity);
}

.cap-icon-cell-selected .cap-icon-img {
  opacity: 1;
}

/* West-end caps: rotate the icon 180° so the end faces left. */
.cap-icon-west {
  transform: rotate(180deg);
}

/* Link / unlink toggle between west and east cap selectors. */
.cap-link-toggle {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin: 0 4px;
  opacity: var(--editor-icon-muted-opacity);
  cursor: pointer;
  user-select: none;
  border-radius: var(--corner-radius-sm);
  padding: 1px;
  box-sizing: content-box;
}

.cap-link-toggle:hover {
  background-color: transparent;
  opacity: 1;
}

.cap-link-toggle-disabled {
  opacity: 0.35;
  pointer-events: none;
}

/* (icon + cap selector) pair. The second pair on a row is nudged right
   so the two ends read as two distinct groups. */
.line-end-pair {
  display: inline-flex;
  align-items: center;
}

.line-end-pair ~ .line-end-pair {
  margin-left: var(--panel-pair-gap);
}

/* Aligned two-column rows for the line section's west/east controls.
   The first (west) column is a fixed width so every east control —
   and its label / icon — starts at the same x. */
.line-pair-row {
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.adornment-autosize-label {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 var(--panel-right-gutter) 0 0;
  /* Give the autosize toggle the standard inter-row gap; it had none. */
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  cursor: pointer;
  user-select: none;
}

.line-pair-row > .line-pair-col {
  display: flex;
  align-items: center;
}

.line-pair-row > .line-pair-col:first-child {
  width: 128px;
  flex: none;
}

/* Cap row: two equal halves with the link/unlink toggle centred between them.
   Unlike the other line-pair-rows, this row does not use a fixed-width first
   column — both sides flex to equal width so the icon lands exactly between
   the two CapSelector groups. */
.cap-link-row {
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.cap-link-row > .cap-link-west,
.cap-link-row > .cap-link-east {
  flex: 1;
  display: flex;
  align-items: center;
}

/* In the line-end context only: inset matches arrow-icon (10px) +
   gap so cap icons left-align with the selects and sliders below. */
.details-line-group .cap-link-west,
.details-line-group .cap-link-east {
  padding-left: calc(10px + var(--panel-checkbox-label-gap));
}

/* Line style (solid / dashed) radio group, indented to level 1. */
.line-style-section {
  margin-left: var(--panel-indent);
}
/* The orthogonal-routing toggle is a bare radio directly under the section
   (unlike the Solid/Dashed pair, which sit in a padded .line-style-radios), so
   it had no vertical gap — give it the standard inter-row gap. */
.line-style-section > .line-style-radio {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

/* The dashes row nested under the (already level-1) line-style section
   adds one more indent step so the dash / gap line sits at level 2. */
.line-style-section .line-details-div {
  margin-left: var(--panel-indent);
}

.line-style-radios {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.line-style-radio {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  user-select: none;
  cursor: pointer;
}

/* Zero the browser-default margin on BOTH the radio and the checkbox that share
   this class (Solid/Dashed radios + the Orthogonal-routing checkbox), so every
   toggle control's left edge sits at the section's level-1 indent and lines up
   with each other and the labels. `input[type="radio"]` alone left the checkbox
   ~4px to the right. */
.line-style-radio input {
  margin: 0;
}

.stroke-cap,
.line-cap {
  margin: 0 var(--panel-control-gap) 0 0;
  vertical-align: middle;
}

.palette {
  position: relative;
  padding: 1px;
  height: 12px;
  width: var(--editor-swatch-size);
  opacity: var(--editor-icon-muted-opacity);
}

/* ── Item-tree drag and drop ──────────────────────────────────────────
   A blue line marks a sibling drop; a tinted, outlined row marks a drop
   *into* a container; the row being dragged is dimmed. */
.tree-drop-line {
  height: 2px;
  margin-right: 6px;
  background-color: var(--editor-selected-blue, #1097e2);
  border-radius: 1px;
  pointer-events: auto;
}

/* A small knob at the start of the insertion line for extra clarity. */
.tree-drop-line::before {
  content: '';
  display: block;
  width: 6px;
  height: 6px;
  margin: -2px 0 0 -3px;
  border-radius: 50%;
  background-color: var(--editor-selected-blue, #1097e2);
}

.tree-drop-into {
  background-color: rgba(16, 151, 226, 0.22) !important;
  outline: 1px solid var(--editor-selected-blue, #1097e2);
  outline-offset: -1px;
}

.tree-row-dragging {
  opacity: 0.4;
}

/* ── Help mode panel ──────────────────────────────────────────────────
   Shown in the left panel, in place of the layers tree, while help mode
   is on. Describes whatever element the pointer is over. */
.help-panel {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 12px 14px;
  color: var(--editor-text-color);
}

/* Help mode is view-only: force the question-mark help cursor everywhere
   so it's obvious the pointer describes things rather than operating them.
   The help-mode toggle button is the one exception — it stays a pointer
   so the user can click it to exit. */
body.help-mode,
body.help-mode * {
  cursor: help !important;
}

body.help-mode .help-mode-icon,
body.help-mode .help-mode-icon * {
  cursor: pointer !important;
}

/* "Help mode" header: a recessed band near the top of the panel, with a
   light background and an even 7px gap above, below, and on either side.
   The negative margins cancel the .help-panel padding (12px 14px) down to
   that 7px inset — hence -5px top and -7px sides. */
.help-panel-badge {
  display: block;
  margin: -5px -7px 7px -7px;
  padding: 8px 14px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  color: var(--editor-muted-text-color);
  background-color: var(--editor-panel-separator-color);
}

.help-panel-title {
  margin: 0 0 6px 0;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  color: var(--header-2-color);
}

/* Sub-heading inside the help panel — used for the "Customizable" block
   that names where a field's default lives in Customize → Engine Defaults. */
.help-panel-subtitle {
  margin: 10px 0 6px 0;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  color: var(--header-2-color);
}

/* The description is indented under the title, left-aligned, with a
   selection-coloured accent line down its left edge. */
.help-panel-body {
  margin: 0 0 10px 0;
  padding-left: 12px;
  border-left: 2px solid var(--editor-selected-blue, #1097e2);
  font-size: 12.5px;
  line-height: 1.5;
  text-align: left;
  opacity: 0.85;
}

/* Floating help tooltip that follows the cursor in help mode. Shows the
   title and (when present) a body summary — the prototype canvas uses the
   body to describe the hovered item's type and interactions. */
.help-tooltip {
  position: fixed;
  left: -9999px;
  top: -9999px;
  z-index: 10000;
  max-width: 380px;
  padding: 8px 12px;
  font-size: 15px;
  line-height: 1.4;
  color: #ffffff;
  background-color: rgba(20, 22, 28, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--corner-radius-sm);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  pointer-events: none;
  white-space: normal;
  overflow-wrap: anywhere;
}

.help-tooltip-title {
  font-size: 16px;
  font-weight: 600;
}

.help-tooltip-body {
  margin-top: 5px;
  font-size: 14px;
  font-weight: 400;
  opacity: 0.85;
  white-space: pre-line;
}

/* Subhead inside the tooltip — used for "Customizable" before the
   default-location sentence. Sits above its own body block. */
.help-tooltip-subtitle {
  margin-top: 8px;
  font-size: 16px;
  font-weight: 600;
}

/* A second, distinct help entry below the first (e.g. an edit-badged tool
   describes the tool AND the badge), set off by a divider. */
.help-tooltip-extra {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--panel-border-color, #b8b8b8);
}

.help-tooltip-hidden {
  display: none;
}

.group-icon,
.union-icon,
.outline-icon,
.exclude-icon,
.intersect-icon,
.subtract-icon,
.mask-icon {
  margin: 0 3px 0 0;
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  vertical-align: middle;
}

/* Gap separating the regular group icon from the special-group icons,
   and the special-group cluster (mask is its last icon) from the add/remove
   icons. */
.group-icon {
  margin-right: 7px;
}

.mask-icon {
  margin-right: 7px;
}

.path-operations-div {
  display: inline-flex;
  align-items: center;
}

/* ── Grouping section (under Align): template / group / boolean / mask / ungroup.
   Icon-buttons sized like the Align buttons, with a gap between the logical
   clusters (template | group | boolean specials | ungroup). ── */
.grouping-div {
  margin-left: var(--panel-indent);   /* level-1 indent, like the other rows */
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
/* Uniform 24px square boxes (a touch bigger, like the Align icons); the glyph
   scales to fit while keeping its aspect, so every button is the same size. */
.grouping-icon {
  width: 24px;
  height: 24px;
  padding: 1px;
  margin: 0 4px 0 0;
  opacity: 0.7;
  cursor: pointer;
  user-select: none;
  box-sizing: border-box;
  vertical-align: middle;
  object-fit: contain;
}
/* Brighten the glyph (foreground) on hover — no background box. */
.grouping-icon:hover {
  opacity: 1;
}
/* The black glyph icons invert for dark mode; the template diamond carries its
   own accent colour, so it's excluded from the filter. */
[data-theme="dark"] .grouping-icon:not(.grouping-template) {
  filter: invert(0.94) hue-rotate(180deg) brightness(1.02);
}
/* Gaps separating the clusters: template | group | boolean specials | ungroup. */
.grouping-template,
.grouping-icon-group,
.grouping-icon-mask {
  margin-right: 12px;
}
/* Make-Template button: a purple diamond like the Layers tree's template badge
   ([[.tree-instance-badge]]), scaled up to the grouping-icon box. */
.grouping-template {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
}
.grouping-template-diamond {
  width: 14px;
  height: 14px;
  border: 2px solid var(--accent-color, #7a5cff);
  transform: rotate(45deg);
  box-sizing: border-box;
}
/* The diamond is already full-opacity, so brighten its foreground (the purple
   border) on hover rather than the opacity. */
.grouping-template:hover .grouping-template-diamond {
  border-color: #a58cff;
}
[data-theme="dark"] .grouping-template-diamond {
  border-color: #b9a7ff;
}
[data-theme="dark"] .grouping-template:hover .grouping-template-diamond {
  border-color: #d8ccff;
}

/* ── Type-header canvas-visibility (eye) toggle + Layers-tree hidden indicator ── */
.type-visibility-btn {
  order: 2;   /* pushed to the right of the header by the ::after spacer */
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-left: 4px;
  margin-right: var(--panel-control-gap);   /* standard right gutter, like the header add/delete icons */
  border: none;
  background: transparent;
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  opacity: 0.38;   /* match the Layers-panel eyes' brightness */
}
.type-visibility-btn.hidden-on {
  opacity: 0.8;
}
.type-visibility-btn:hover {
  opacity: 1;
}
.type-visibility-icon {
  width: 16px;
  height: 16px;
  display: block;
}
[data-theme="dark"] .type-visibility-icon {
  filter: invert(1) brightness(1.2);   /* match the Layers-panel eyes in dark mode */
}
/* The eye-closed glyph shown at the right of a hidden Layers-tree row. Scoped
   under .item-tree-item so it beats the generic `.item-tree-item img { 6px }`
   rule (same trick as .tree-type-icon) — otherwise it renders at 6px. Sized like
   the type icon, vertically centred, full-contrast, with room from the row edge. */
/* Per-row visibility toggle: eye-open when shown (a quiet default), the slashed
   eye-closed when hidden (prominent). Scoped under .item-tree-item so it beats
   the generic `.item-tree-item img { 6px }` rule (like .tree-type-icon). */
.item-tree-item .tree-vis-eye {
  flex: 0 0 auto;
  display: block;
  align-self: center;
  margin-left: auto;
  /* Nudged right again (14px → 13px → 12px). */
  margin-right: 12px;
  padding: 0;
  width: 14px;
  height: 14px;
  opacity: 0.38;
  cursor: pointer;
}
.item-tree-item .tree-vis-eye.hidden {
  opacity: 0.8;
}
.item-tree-item .tree-vis-eye:hover {
  opacity: 1;
}
/* Full invert to white for solid contrast against the dark tree rows. */
[data-theme="dark"] .item-tree-item .tree-vis-eye {
  filter: invert(1) brightness(1.2);
}

/* Layer lock in the item tree — identical to the Layers-list lock
   (.page-lock-eye): a slashed padlock when unlocked, a solid padlock when
   locked. Its brightness tracks the tree eye — the slashed (unlocked) lock is
   the same 0.38 as a shown layer's eye; the solid (locked) lock is full, like
   the crossed-out eye. Sits just left of the tree eye; margin-left:auto
   right-aligns the lock+eye pair. */
.item-tree-item .tree-lock-eye {
  flex: 0 0 auto;
  display: block;
  align-self: center;
  margin-left: auto;
  margin-right: 8px;
  padding: 0;
  width: 13px;
  height: 13px;
  opacity: 0.38;
  cursor: pointer;
}
.item-tree-item .tree-lock-eye.on {
  opacity: 1;
}
.item-tree-item .tree-lock-eye:hover {
  opacity: 1;
}
/* The lock's margin-left:auto already right-aligns the pair, so cancel the
   eye's own margin-left:auto when it follows a lock (layer rows only). */
.item-tree-item .tree-lock-eye + .tree-vis-eye {
  margin-left: 0;
}
[data-theme="dark"] .item-tree-item .tree-lock-eye {
  filter: invert(1) brightness(1.2);
}

/* Section header group: disclosure triangle + title + (optional) descriptor
   + (optional) add/delete icon buttons. Everything lives on one row, full
   width, vertically centered. The triangle, title, and descriptor sit on
   the left at order 0; icon buttons (add/delete, ring shift, group ops)
   are tagged order 2 so they're pushed to the right; a ::after spacer at
   order 1 with flex: 1 absorbs all the free space in between. */
.details-header {
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.details-header::after {
  content: '';
  flex: 1 1 auto;
  order: 1;
}

.details-header > [class*="-add-div"],
.details-header > [class*="-delete-div"],
.details-header > .delete-ring-div,
.details-header > .sight-div,
.details-header > .groups-add-remove-div {
  order: 2;
  /* Keep the section's +/- centred on the header line. */
  align-self: center;
}

/* The Selection Colours target button moved from every colour row into the section
   HEADER (one button, acting on the picked row), so it sits with the other header
   icon-buttons instead of stretching to fill a row. */
.details-header > .sight-div {
  flex: 0 0 auto;
}

.palette-options {
  position: relative;
  display: inline-block;
  padding: 3px;
  margin: 0 3px;
  top: -9px;
  opacity: var(--editor-icon-muted-opacity);
}

.palette-options-menu {
  position: absolute;
  transition: 0s visibility;
  z-index: 50;
}

.palette-options-div {
  position: absolute;
  background-color: var(--top-toolbar-background-color);
  color: #fff;
  padding: 8px 12px;
  border-radius: 3px;
  width: 170px;
}

.palette-options-span {
  display: block;
  color: #fff;
  font-size: var(--editor-control-font-size);
  text-align: left;
  border-radius: var(--corner-radius-sm);
  padding: 1px 3px;
}

.inline-block {
  display: inline-block;
}

.palette-options-span:hover {
  color: #fff;
  background-color: var(--editor-selected-blue);
}

.palette-options-menu .palette-options-div::after {
  content: " ";
  position: absolute;
  bottom: 100%;
  right: 26px;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: transparent transparent var(--top-toolbar-background-color) transparent;
}

/* Pen mode toolbar and canvas context menu. Block-level with no side
   margin so the .separator bottom border spans the full panel width,
   matching the other design-panel sections. */
.pen-mode-div {
  display: block;
  /* Standard section padding so the header isn't crowded against the divider
     above it (matches .details-div-group). */
  margin: 0;
  padding: 10px 0;
}

/* Connector-insertion exit button: sits inline to the right of the section
   title (the details-header centers it vertically). */
.connector-create-cancel {
  margin-left: 8px;
}

.pen-mode-heading-div {
  /* The DisclosureTriangle before it already supplies the panel-indent, so the
     heading must NOT add another (it was double-indented vs other sections). */
  margin: 0 0px 0 0px;
  user-select: none;
  display: block;
}

.pen-icons-div {
  /* Flex row so the "Ring" name + prev/next triangles vertically center with
     the sub-mode icon buttons; wraps gracefully on a very narrow panel. */
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

/* Pen editing rides its Select / Insert / Curve / Exit buttons on the header line. Like the
   standard +/- header slot, order 2 sits it AFTER the .details-header::after spacer, which
   grows and pushes it to the panel's right edge — with an 8px gutter so it doesn't butt
   against the edge. (margin-left:auto alone does NOT work: the flex-grow ::after eats the
   free space first, so the group would sit left, right after the title.) */
.pen-mode-header-icons {
  order: 2;
  margin-right: 8px;
  display: inline-flex;
  align-items: center;
}

.connector-mode-help {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  color: var(--editor-muted-text-color);
  font-size: var(--editor-control-font-size);
  line-height: 1.45;
}

.pen-icon {
  display: block;   /* drop the inline baseline gap so the wrapper's selection
                       border hugs the icon instead of leaving space below it */
  width: 24px;
  height: 24px;
  padding: 2px;
  opacity: 60%;
}

.pen-icon-disabled {
  opacity: 20%;
  pointer-events: none;
  cursor: default;
}

.wrapper {
  display: inline-block;
  /* A transparent border on every button keeps the row from shifting when the
     active button's blue selection border appears, and makes the selection box
     snug and identical for every sub-mode icon. */
  border: 1px solid transparent;
  border-radius: var(--corner-radius-sm);
  margin-right: 1px;
}

.canvas-context-menu-div {
  position: absolute;
}

.canvas-context-menu-ul {
  position: absolute;
  background-color: var(--top-toolbar-background-color);
  color: white;
  border-radius: 4px;
  width: 200px;
  margin: 10px;
  list-style: none;
  padding: 5px;
  z-index: 100;
  /* No overflow/scroll on the top-level menu: setting overflow-y also coerces
     overflow-x to `auto` (CSS spec), which would CLIP the flyout submenus that
     sit at `left: 100%` — showing a scrollbar'd sliver instead of the submenu.
     The menu itself is a short, bounded set of actions; the long LISTS live in
     the flyouts, which scroll on their own (.canvas-context-menu-submenu). The
     fixed position is already clamped to the viewport edges. */
}

.canvas-context-menu-li {
  background: none;
  height: 20px;
  width: 190px;
  margin: 0;
  padding: 5px;
  cursor: pointer;
  z-index: 150;
  font-size: 12pt;
}

.canvas-context-menu-li:hover {
  background: var(--editor-selected-blue);
}

/* Flyout sub-menu (e.g. Add control ▸) — opens to the right on hover. */
.canvas-context-menu-li.has-submenu {
  position: relative;
}
.canvas-context-menu-submenu {
  position: absolute;
  left: 100%;
  top: 0;
  margin: 0;
  padding: 5px;
  list-style: none;
  background-color: var(--top-toolbar-background-color);
  border-radius: 4px;
  width: 200px;
  display: none;
  z-index: 200;
  /* A long flyout (e.g. Add data with many entities) scrolls instead of
     running off the bottom of the page. */
  max-height: calc(100vh - 12px);
  overflow-y: auto;
}
/* When the parent menu sits on the right half of the screen it carries
   `submenu-left`, so its flyouts open to the LEFT and stay on-page. */
.canvas-context-menu-ul.submenu-left .canvas-context-menu-submenu {
  left: auto;
  right: 100%;
}
/* A row low on the screen carries `open-up` (set on hover in ContextMenu.tsx),
   so its flyout is bottom-aligned to the row and grows upward instead of off the
   bottom of the page. */
.canvas-context-menu-li.has-submenu.open-up > .canvas-context-menu-submenu {
  top: auto;
  bottom: 0;
}
.canvas-context-menu-li.has-submenu:hover > .canvas-context-menu-submenu {
  display: block;
}

.add-gradient-span {
  position: relative;
  top: -10px;
  font-size: var(--editor-control-font-size);
  background-color: var(--editor-muted-text-color);
  color: white;
  border-radius: 3px;
  padding: 0px 3px 1px;
  margin: 0 9px;
}

/* Gradient, shadow, image, export, and tab controls. */
.gradient-colors-heading {
  margin: 0 12px;
}

.gradient-color-div {
  margin: 0;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.color-picker-div {
  position: fixed;
  text-align: left;
  padding: 6px 11px 8px;
  border: 2px solid var(--editor-control-border-color);
  border-radius: 9px;
  background-color: var(--editor-panel-background-color);
  width: 190px;
  z-index: 1000;
  user-select: none;
}

/* Thin drag-handle strip at the top of the floating picker.
   Extends wall-to-wall inside the border by negating the parent's padding.
   The ::before shows a row of dots so the user can see it is draggable. */
.color-picker-header {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 -11px 0 -11px;
  padding: 4px 6px;
  border-radius: 7px 7px 0 0;
  background-color: rgba(128, 128, 128, 0.1);
  border-bottom: 1px solid var(--editor-control-border-color);
  cursor: grab;
  height: 18px;
  box-sizing: content-box;
}

.color-picker-title {
  font-size: var(--editor-control-font-size);
  /* Match the Design/Prototype tab heading colour. */
  color: var(--customize-tab-color-active, var(--editor-text-color));
  user-select: none;
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  /* Keep the title clear of the centered drag-handle dots. */
  max-width: calc(50% - 26px);
  padding-right: 6px;
}

.color-picker-header::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 36px;
  height: 8px;
  background-image: radial-gradient(circle, currentColor 1.5px, transparent 1.5px);
  background-size: 6px 4px;
  opacity: 0.3;
  pointer-events: none;
}

.color-picker-header:active {
  cursor: grabbing;
}

/* Red × close button — styled like the Share toolbar button but in panel context. */
.color-picker-close {
  background-color: transparent;
  border: none;
  border-radius: var(--corner-radius-sm);
  padding: 1px 4px;
  font-family: var(--editor-font-family);
  font-size: 0.78rem;
  font-weight: 600;
  color: #e53935;
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
  -webkit-appearance: none;
  appearance: none;
  opacity: var(--editor-icon-muted-opacity);
}

.color-picker-close:hover {
  background-color: transparent;
  opacity: 1;
}

.color-picker-close:active {
  background-color: rgba(128, 128, 128, 0.32);
  opacity: 1;
}

.gradient-location-div {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

#gradient-start-label,
#gradient-end-label {
  display: inline-block;
  font-size: var(--editor-control-font-size);
  width: 30px;
  margin: 0 0 0 12px;
  user-select: none;
}

.gradient-offset-label {
  display: inline-block;
  font-size: var(--editor-control-font-size);
  width: 14px;
  margin: 0 6px 0 2px;
  user-select: none;
}

.shadow-offset-label {
  display: inline-block;
  font-size: var(--editor-control-font-size);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  user-select: none;
  vertical-align: middle;
  text-align: left;
}

/* The single-cell shadow rows (Blur and Type) get a fixed-width label so
   their inputs line up at the same X. X/Y stay auto-width — they're
   intentionally not aligned with Blur/Type. */
.shadow-offset-row > .shadow-offset-div:only-child > .shadow-offset-label {
  width: 32px;
}
/* "Source" is a full word, so it keeps its natural width and gets the standard
   label→control gap before the Fill / Stroke toggle (not the 32px column the
   short X/Y/Blur labels use, which would crowd it). */
.shadow-type-row > .shadow-offset-label {
  margin-right: var(--panel-checkbox-label-gap);
}

/* X and Y labels (the multi-cell shadow row) get the standard
   --panel-checkbox-label-gap of right margin to their input — a bit wider
   than the default --panel-control-gap so the short labels don't crowd
   their fields. */
.shadow-offset-row > .shadow-offset-div:not(:only-child) > .shadow-offset-label {
  margin-right: var(--panel-checkbox-label-gap);
}

/* Wrapper for one (label + input) pair in a shadow offset row. The wrapper
   is --details-row-height tall and centers its children at their natural
   height — neither the label nor the input is forced to a row height. */
.shadow-offset-div {
  display: inline-flex;
  align-items: center;
  /* No vertical pad here — the enclosing .shadow-offset-row already supplies the
     single inter-line gap. Padding both would double it on the X/Y and Blur rows
     (they'd sit taller than the colour and Type rows). */
  margin: 0;
  /* Each offset cell shares the flex row so its formula input can grow. */
  flex: 1 1 0;
  min-width: 0;
}

.gradient-location-types {
  font-size: var(--editor-control-font-size);
  margin: 0 6px 0 6px;
  border: var(--editor-control-border);
  outline-color: var(--editor-text-color);
  color: var(--editor-text-color);
}

.gradient-offset-input {
  position: relative;
  width: 25px;
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  margin: 0 3px 0 0;
}

.shadow-offset-input {
  position: relative;
  /* Formula-capable (Blur, and the X/Y offsets) — grow into spare row
     width, capped so a lone Blur field doesn't span the whole panel. */
  flex: 1 1 0;
  width: auto;
  min-width: 35px;
  max-width: 150px;
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  margin: 0;
}

.image-div {
  display: inline-block;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* Between-group gap separating the vertical-align group from the horizontal
     one — clearly wider than the within-group spacing, but not a full indent. */
  margin-left: 16px;
}

.export-div {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  line-height: normal;
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

/* The shadow X/Y + Blur rows live in this wrapper; it's just the indent — the
   rows inside set their own height, so they stack with normal spacing. */
.shadow-div {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

/* Shadow tree — three levels (Shadows root → item → shadow leaf). Rows use the
   customizable inter-row spacing (--details-row-pad); each level indents by 14px
   (set inline); the selected row gets the selection blue. */
ul.shadow-tree {
  list-style: none;
  /* Indent the whole tree to level 1 (one --panel-indent), like other nested
     panel content; per-row level nesting is added on top via inline paddingLeft. */
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  padding: 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.shadow-tree-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: var(--details-row-pad) 4px;
  cursor: pointer;
}
.shadow-tree-row:hover {
  background: color-mix(in srgb, var(--editor-selected-blue) 10%, transparent);
}
.shadow-tree-row.selected {
  background: color-mix(in srgb, var(--editor-selected-blue) 16%, transparent);
  box-shadow: inset 2px 0 0 var(--editor-selected-blue);
}
.shadow-tree-row.drop-before { box-shadow: inset 0 2px 0 var(--editor-selected-blue); }
.shadow-tree-row.drop-after { box-shadow: inset 0 -2px 0 var(--editor-selected-blue); }
/* Dropping a dragged shadow ONTO a whole row (an item, or the Shadows root) to copy it. */
.shadow-tree-row.drop-onto {
  box-shadow: inset 0 0 0 2px var(--editor-selected-blue);
  background: color-mix(in srgb, var(--editor-selected-blue) 12%, transparent);
}
.shadow-tree-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Per-row colour swatch (its background colour is set inline to the canvas colour
   so a partially transparent shadow composites correctly). */
.shadow-row-swatch {
  flex: 0 0 16px;
  height: 16px;
  border-radius: 3px;
  border: var(--editor-control-border);
}
/* An IMAGE fill's swatch: a picture TYPE SYMBOL centred in the swatch box rather than a
   colour. The glyph is an inner <img> so its dark-mode invert doesn't touch the box border. */
.paint-image-swatch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.paint-image-symbol {
  width: 12px;
  height: 12px;
  object-fit: contain;
}
[data-theme="dark"] .paint-image-symbol {
  filter: invert(1) brightness(1.2);
}
/* A Fill / Stroke entry row with NO paint — a ring that inherits, a fill switched off.
   It takes the swatch's place and its box, but reads as a cancel glyph: an empty
   swatch just looks like a colour that matches the panel behind it. */
.paint-row-none {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  opacity: var(--editor-icon-muted-opacity);
}

/* A Fill / Stroke entry row's value, after the item's name: "#3366ff 80%", "Linear
   gradient, 3 stops", "Image fill". Muted and pushed right, so the column of names
   stays the thing you scan. Truncates before the name does. */
.paint-row-summary {
  margin-left: auto;
  padding-left: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.7;
}

/* Fill / Stroke source glyph — used both in a tree leaf and in the toggle cells. */
.shadow-source-icon {
  flex: 0 0 14px;
  width: 14px;
  height: 14px;
  opacity: 0.9;
}
[data-theme="dark"] .shadow-source-icon {
  filter: invert(1) brightness(1.2);
}

/* Fill / Stroke source — a two-cell segmented toggle of icons (reuses .align-icon-cell). */
.shadow-source-seg {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}
.shadow-source-cell {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border: var(--editor-control-border);
}

/* The Type-selector row: a standard label + control row (like every other
   panel row) — flex, centred, one row tall. */
.shadow-type-row {
  display: flex;
  align-items: center;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

/* Shadow X/Y row + Blur row: each row is a flex container so its items
   wrap if the panel is too narrow. The rows themselves are block-level,
   so Blur naturally lands on the line below X/Y. All rows align to the
   shadow-div's left content edge (panel-indent). */
.shadow-offset-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: calc(var(--panel-pair-gap) + 12px);
  row-gap: var(--panel-row-gap);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  margin: 0;
}

.get-image-div {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

.get-image-btn {
  margin: 0 0 0 12px;
  font-size: var(--editor-control-font-size);
}

/* Export action button — a subtle bordered button styled to match the
   share button on the top toolbar. The .export-div parent already
   supplies the panel indent / right gutter. */
.export-button {
  display: block;
  width: 100%;
  margin: 0 0 0 0;
  padding: 6px 12px;
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  font-weight: 600;
  line-height: normal;
  text-align: center;
  color: var(--button-text);
  background-color: var(--button-bg);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  user-select: none;
}

.export-button:hover,
.export-button:active {
  background-color: var(--button-bg-hover);
}

.export-button:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Export rows: name on its own row; format + size share a row. Proximity —
   each label hugs its own control with the tight --panel-checkbox-label-gap
   (like every other panel section), and the wider --panel-pair-gap is reserved
   for separating the Format | Size pair (see .export-field + .export-field). The
   same tight gap here means the Name input (row 1) and the Format select (row 2)
   still start at the same x. */
.export-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--panel-checkbox-label-gap);
  row-gap: var(--panel-row-gap);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}

/* A label + select pair that sits inline with its sibling pair. */
.export-field {
  display: inline-flex;
  align-items: center;
  column-gap: var(--panel-checkbox-label-gap);
}

/* The second pair on the Format | Size row sits a full pair-gap from the first,
   so the two groups read as distinct (the row's own gap is the tight label gap). */
.export-field + .export-field {
  margin-left: calc(var(--panel-pair-gap) - var(--panel-checkbox-label-gap));
}

.export-row select,
.export-field select {
  vertical-align: middle;
}

/* Natural-width labels that hug their own control (the tight label→control gap
   comes from the row / field column-gap). No fixed label column — aligning the
   Name and Format controls at a shared x would force a gap after the shorter
   labels, and proximity to the control matters more than that column. */
/* Name (row 1) and Format (row 2, first column) are aligned DOWN their column —
   the one case that earns a fixed-width label. 45px hugs the widest of the two,
   "Format" (~44px at Arial 14px), so the only separation left is the standard
   8px label→control gap and the Name input lines up under the Format select. */
.export-label {
  display: inline-block;
  flex: 0 0 auto;
  box-sizing: border-box;
  width: 45px;
  white-space: nowrap;
  font-size: var(--editor-control-font-size);
}
/* Size is the SECOND pair on the Format | Size row — it aligns with nothing
   below it, so its label stays natural width and hugs its own control. */
.export-field + .export-field .export-label {
  width: auto;
}


/* The name field stretches to fill the rest of its row, and is styled to
   match the other edit fields in the design panel. */
.export-name-input {
  /* flex-basis 0 (not auto) so it grows into the leftover row width instead of
     inheriting the global `.details-scroll input { width: 100% }` as its basis —
     that 100% basis wouldn't fit beside the label and wrapped the input to the
     next line. min-width 0 lets it shrink rather than wrap on a narrow panel. */
  flex: 1 1 0;
  min-width: 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  background-color: var(--editor-input-bg);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

/* SVG-only "Rasterize text" toggle row. Inherits the export-div indent;
   the label wraps the checkbox + text with a small gap between them. */
.export-check-label {
  display: inline-flex;
  align-items: center;
  column-gap: 6px;
  font-size: var(--editor-control-font-size);
  cursor: pointer;
  user-select: none;
}

.export-check-label input {
  margin: 0;
  vertical-align: middle;
}

/* Resulting pixel dimensions, shown below the size selector. */
.export-dims {
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  line-height: normal;
  font-size: var(--editor-control-font-size);
  opacity: 0.7;
}

/* Multi-selection export: one file-name field per selected item, stacked. The
   other parameters (format, size, rasterize) stay single below the list. */
.export-names {
  display: flex;
  flex-direction: column;
}
.export-names-head {
  padding-top: var(--details-row-pad);
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}

/* Design / Prototype tab strip. Styled to match the Customize page tabs
   exactly: a flat strip with an underline-style active tab. Each tab is
   only as wide as its label. */
.tabs {
  display: flex;
  gap: 2px;
  padding: 0 1.2rem;
  background-color: var(--customize-tab-strip-bg, var(--editor-panel-separator-color));
  border-bottom: 1px solid var(--panel-border-color);
  flex: 0 0 auto;
}

/* Editor tabs (Design/Prototype + the left panel's Layers/Assets/Project) are
   sized ~20% smaller than the default so a third tab fits without crowding. */
.tabs h3 {
  padding: 0.48rem 1rem;
  margin: 0;
  border: none;
  background: var(--customize-tab-bg-inactive, transparent);
  /* The Design / Prototype tabs are the panel's top-level headers. Unselected
     tabs sit muted (opacity, so it composes with the per-tab accent colours);
     the active tab and a hovered unselected one go full. */
  color: var(--header-1-color);
  font-size: 0.76rem;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  user-select: none;
  opacity: 0.62;
  transition: opacity 0.1s ease;
}

/* Unselected, non-disabled tab: brighten the label (foreground) on hover — same
   foreground-highlight rule as the icon-buttons, no background tint. */
.tabs h3:not(.active):not(.disabled):hover {
  opacity: 1;
}

.tabs .active,
.tabs .active:hover {
  color: var(--header-1-color);
  opacity: 1;
  border-bottom-color: var(--editor-selected-blue);
  background-color: var(--customize-tab-bg-active, var(--editor-input-bg, var(--editor-panel-background-color)));
}

/* Diagrams tab sub-tabs — one per diagram type (Flows / Sequences / Use cases /
   State machines). A compact, wrapping second-level strip below the main tab row;
   the active tab underlines in the code-accent green (the Diagrams tab's colour). */
.diagram-subtabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 4px;
  padding: 4px 6px 0;
  border-bottom: 1px solid var(--panel-border-color);
  flex: 0 0 auto;
}
.diagram-subtab {
  padding: 0.28rem 0.5rem;
  margin: 0;
  border: none;
  background: transparent;
  color: var(--code-accent);
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  user-select: none;
  opacity: 0.6;
  transition: opacity 0.1s ease;
}
.diagram-subtab:not(.active):hover { opacity: 1; }
.diagram-subtab.active {
  opacity: 1;
  border-bottom-color: var(--code-accent);
}

/* The left panel's Layers / Assets / Project tab group is centred within the
   panel; the tabs themselves stay left-to-right (left-aligned) within it. */
/* The left panel's tabs (Structure / Assets / Project, etc.) fill the panel width so
   the tab strip's right edge lines up with the list below it — instead of a centred
   group that stopped short of the panel's right edge. The 6px side padding matches the
   list rows' inset so the edges line up. */
.left-panel-tabs {
  justify-content: stretch;
  padding: 0 6px;
}
.left-panel-tabs h3 {
  flex: 1 1 0;
  min-width: 0;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  text-align: center;
  /* Keep each label inside its own equal-width cell: a long single-word label
     (Variables / Diagrams) must not overflow and overlap a short neighbour like
     Files — clip with an ellipsis instead, staying centred. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Prototype interaction controls. */
.activation-types {
  display: inline-block;
  font-size: 13px;
  margin: 0 0px 0 12px;
  user-select: none;
}

.action-types {
  display: inline-block;
  font-size: 13px;
  margin: 0 6px 0 6px;
  user-select: none;
}

/* Plain-text stand-in for the action dropdown on a Connection row.
   Connections only run Navigate, so the dropdown becomes a label that
   sits in the same row position as the trigger row's select. */
.action-label {
  display: inline-block;
  font-size: 13px;
  margin: 0 6px 0 6px;
  user-select: none;
}

/* Connections / Triggers section content: indented to Level 1, under
   the section heading. */
.connections-content,
.triggers-content {
  margin-left: var(--panel-indent);
}

/* Triggers are grouped by item; leave a gap before each new item group so
   the groups don't run together (one full inter-row gap, a touch more than
   the gap between rows inside a group). */
.trigger-group:not(:first-child) {
  margin-top: var(--details-row-gap);
}

.interaction-start-end-heading {
  display: flex;
  align-items: center;
  margin: 0 0px 0 0px;
  user-select: none;
  /* A connection/trigger GROUP label (e.g. "Frame 1 → Frame 6"), not a section heading — it's an
     <h4>, so without an explicit size it falls back to the browser's big/bold default and reads
     as a major heading. Only .trigger-group styled it before, leaving the Connections list big. */
  font-size: var(--editor-control-font-size);
  font-weight: 600;
  color: var(--header-3-color);
}

/* Trigger item-name heading: same structural role as the connection
   start→end heading, but a level dimmer so it doesn't visually compete
   with the parent "Triggers" section heading. Carry the standard row
   padding so the heading sits one inter-line gap above its behaviour rows
   (the shared .interaction-start-end-heading has no vertical rhythm). */
.trigger-group .interaction-start-end-heading {
  font-size: var(--editor-control-font-size);
  font-weight: 600;
  color: var(--header-3-color);
  padding-top: var(--details-row-pad);
  padding-bottom: var(--details-row-pad);
}

/* In a trigger row, the activation-types select sits flush with the
   row's left edge — no need for the connection rows' 12px indent to
   line up under a separate start→end heading. */
.trigger-group .activation-types {
  margin-left: 0;
}

/* Heading text + arrow as one flex item; takes the available width so
   the add-behavior control is pushed to the right edge of the panel. */
.interaction-title {
  flex: 1;
  min-width: 0;
  display: inline-flex;
  align-items: center;
}

/* Connector arrow between the start and end item names. */
.interaction-arrow {
  flex: none;
  width: 22px;
  height: 8px;
  margin: 0 6px;
  fill: none;
  stroke: var(--editor-muted-text-color, #8e8c9e);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Add-behavior (+) and delete-connection (-) controls: grouped at the
   right edge of the connection heading, vertically centered. */
.connection-controls {
  display: inline-flex;
  align-items: center;
  gap: var(--panel-control-gap);
  margin-left: auto;
  margin-right: var(--panel-control-gap);
}

.connection-controls .routing-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--header-2-color);
  cursor: pointer;
  white-space: nowrap;
}

.connection-controls .routing-toggle input {
  margin: 0;
  cursor: pointer;
}

/* Section-wide routing toggle at the end of the Connections list —
   flips every selected connection between orthogonal and straight. */
.connections-routing-all {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--header-2-color);
  cursor: pointer;
  white-space: nowrap;
  margin-top: 0;
  padding-top: 8px;
  border-top: 1px solid var(--panel-border-color, rgba(128, 128, 128, 0.2));
}

.connections-routing-all input {
  margin: 0;
  cursor: pointer;
}

/* Behavior row: activation + action selects, with the delete (-)
   control pushed to the right edge and vertically centered. */
.interaction-behavior-row {
  display: flex;
  align-items: center;
  /* Standard gap between the row's controls (activation select, action
     select/label, delete) so a trigger's two adjacent selects aren't flush. */
  column-gap: var(--panel-control-gap);
  /* Same inter-row gap the other prototype rows use, so the activation/action row
     lines up with the property rows below it. */
  padding-top: var(--details-row-pad);
  padding-bottom: var(--details-row-pad);
}
/* The activation / action selects must shrink (not overflow) in a narrow panel. */
.interaction-behavior-row > select {
  min-width: 0;
  max-width: 100%;
}

.interaction-behavior-row .delete-behavior-div {
  margin-left: auto;
  flex: 0 0 auto;
}

.miter-limit-text-input {
  width: 40px;
  margin: 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
}

.miter-limit-label,
.stroke-join-label {
  display: inline-block;
  width: 74px;
  font-size: var(--editor-control-font-size);
  margin: 0 var(--panel-checkbox-label-gap) 0 0;
  text-align: left;
  vertical-align: middle;
}

#stroke-join {
  margin: 0;
  vertical-align: middle;
}

p.file-name-p {
  display: block;
  line-height: normal;
  margin: 0 0 0 6px;
  text-align: left;
  word-wrap: normal;
  width: 140px;
}

/* Detailed color editor and constraint controls. */
/* Row that holds R/G/B inputs on the left and the palette area on the right. */
/* Stack the picker's lower sections vertically: RGB row, then the palette,
   then the colour tokens. Tight gap so the RGB sits close to the palette. */
.color-picker-bottom-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  margin-top: 0;
}

.color-picker-palette-area {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* RGB across, centred, with breathing room on the left and right of the line. */
.color-parts-div {
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 10px;
  padding: 0 10px;
}

/* Colour-tokens section at the bottom of the picker. The swatch grid wraps to
   only as many rows as needed. The margin-top adds room between the palette
   (colours) line above and this section's divider. */
.color-picker-tokens {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 0;
  border-top: 1px solid var(--editor-panel-separator-color, var(--editor-control-border-color));
  padding-top: 6px;
}
.color-picker-tokens-label {
  font-size: var(--editor-control-font-size);
  opacity: 0.7;
}
.color-picker-token-link {
  display: flex;
  align-items: center;
  gap: 6px;
}
.color-part-div {
  display: flex;
  align-items: center;
  gap: 6px;
}

.color-part-label {
  flex-shrink: 0;
  width: 12px;
  text-align: right;
  font-size: var(--editor-control-font-size);
}

.color-part-percentage-label {
  flex-shrink: 0;
  font-size: var(--editor-control-font-size);
}

.color-part-input {
  width: 30px;
  flex-shrink: 0;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
}

.color-picker-div .add-palette-color-icon {
  height: 12px;
}

/* Palette swatches are a uniform 14px swatch size across the picker. */
.palette-color-div {
  height: 14px;
  width: 14px;
  flex-shrink: 0;
  border: 2px solid var(--editor-control-border-color);
  border-radius: 2px;
}

.palette-colors-div {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  position: relative;
  margin: 0;
  width: 100%;
}

.missing-triangle-div {
  display: inline-block;
  height: 10px;
  width: 8px;
}

.constraints-div {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Layout / Override chooser shown when the selected item is inside an auto-layout
   frame — sits above the constraint grid, spanning the panel width. */
.constraints-layout-note {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}
.constraints-mode-radio {
  display: flex;
  align-items: center;
  gap: 16px;
}
.constraints-radio {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  white-space: nowrap;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}
.constraints-radio input {
  margin: 0;
}
/* Scoped past the panel-wide `.details-div p` rule (0,1,1), which forces every panel <p>
   to a 14px inline-block glyph label — that collapsed this caption to one word per line. */
.constraints-layout-note .constraints-note-text {
  display: block;
  width: auto;
  margin: 0 0 0 0;
  color: var(--editor-muted-text-color);
  font-size: var(--editor-control-font-size);
  line-height: 1.35;
  text-align: left;
}
/* Per-child auto-layout sizing (Fill/Stretch + Fill limits), under the Layout/Override
   radio. Wide gap BETWEEN the two field groups; tight gap between each label + control. */
.layout-child-sizing-row {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-top: 0;
}
.layout-child-field {
  display: flex;
  align-items: center;
  gap: 5px;
}
.layout-child-field label {
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  white-space: nowrap;
}
.layout-child-sizing-row .layout-input {
  width: 48px;
}

/* 3×3 grid: corner cells empty, edge cells hold the constraint handles,
   center cell holds the inner bordered box. */
.constraints-outer-box {
  flex-shrink: 0;
  box-sizing: border-box;
  width: 60px;
  height: 57px;
  border: 2px solid var(--editor-control-border-color);
  display: grid;
  grid-template-columns: 1fr 32px 1fr;
  grid-template-rows: 1fr 31px 1fr;
}

.constraints-top-box {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 1px;
  cursor: pointer;
}

.constraints-top {
  width: 3px;
  height: 9px;
  background-color: var(--editor-constraint-line-color);
}

.constraints-bottom-box {
  grid-column: 2;
  grid-row: 3;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  padding-bottom: 1px;
  cursor: pointer;
}

.constraints-bottom {
  width: 3px;
  height: 9px;
  background-color: var(--editor-constraint-line-color);
}

.constraints-left-box {
  grid-column: 1;
  grid-row: 2;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding-left: 1px;
  cursor: pointer;
}

.constraints-left {
  height: 3px;
  width: 9px;
  background-color: var(--editor-constraint-line-color);
}

.constraints-right-box {
  grid-column: 3;
  grid-row: 2;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 1px;
  cursor: pointer;
}

.constraints-right {
  height: 3px;
  width: 9px;
  background-color: var(--editor-constraint-line-color);
}

.constraints-inner-box {
  grid-column: 2;
  grid-row: 2;
  box-sizing: border-box;
  border: 2px solid var(--editor-control-border-color);
  position: relative;
}

/* Vertical and horizontal center handles overlap inside the inner box.
   Each is absolutely positioned to occupy its own axis-centered strip,
   with a shared 3px bar in the middle rendered by the inner element. */
.vertical-center-box {
  position: absolute;
  inset: 0 35% 0 35%;
  display: flex;
  justify-content: center;
  cursor: pointer;
}

.vertical-center {
  width: 3px;
  background-color: var(--editor-constraint-line-color);
}

.horizontal-center-box {
  position: absolute;
  inset: 35% 0 35% 0;
  display: flex;
  align-items: center;
  cursor: pointer;
}

.horizontal-center {
  width: 100%;
  height: 3px;
  background-color: var(--editor-constraint-line-color);
}

/* Label + select pairs laid out as a two-column grid. */
.constraints-details-div {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 4px 6px;
}

.constraints-label {
  font-family: var(--editor-font-family);
  color: var(--editor-muted-text-color);
  font-size: var(--editor-control-font-size);
}

#horizontal-constraint,
#vertical-constraint {
  color: var(--editor-text-color);
  width: 106px;
}

/* Eyedropper and color-picker mode controls. */
.eyedropper {
  height: 20px;
  display: block;
}

.color-picker-mode-cancel-icon {
  position: relative;
  top: -2px;
  height: 25px;
}

.color-picker-eyedropper-btn {
  background: none;
  border: none;
  cursor: pointer;
  border-radius: var(--corner-radius-sm);
  padding: 3px 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: var(--editor-icon-muted-opacity);
  margin: 0 0 3px;
}

.color-picker-eyedropper-btn:hover {
  background-color: transparent;
  opacity: 1;
}

.color-picker-eyedropper-active {
  background-color: var(--tool-active-bg, #e3e8f2);
  outline: var(--selection-border-width) solid var(--editor-selected-blue);
  outline-offset: calc(-1 * var(--selection-border-width));
  opacity: 1;
}

/* Interaction targets, modifiers, variables, and conditional fields.
   Labels in this group baseline-align with their adjacent text input via
   `vertical-align: middle` (the inputs already use it from the shared
   text-input rule), so the label text sits centered to the input box. */
.drop-target-label,
.scroll-target-label,
.delay-label,
.set-to-label {
  vertical-align: middle;
  font-size: var(--editor-control-font-size);
  margin: 0 6px 0 12px;
}

.drop-targets,
.scroll-targets {
  font-size: var(--editor-control-font-size);
}

.snap-back-label,
.select-target-label,
.show-toolbar-label,
.allow-zoom-label,
.allow-scroll-label {
  position: relative;
  top: -2px;
  font-size: var(--editor-control-font-size);
}

.snap-back-checkbox,
.select-target-checkbox,
.show-toolbar-checkbox,
.allow-zoom-checkbox,
.allow-scroll-checkbox {
  margin: 0 var(--panel-checkbox-label-gap) 0 12px;
}

.hovering-select-checkbox,
.ctrl-checkbox {
  position: relative;
  top: 1px;
  margin: 0 var(--panel-checkbox-label-gap) 0 12px;
}

.ctrl-checkbox,
.shift-checkbox,
.alt-checkbox,
.caps-lock-checkbox,
.num-lock-checkbox {
  position: relative;
  top: 1px;
  margin: 0 var(--panel-checkbox-label-gap) 0 12px;
}

/* When a checkbox starts a new group on the same row, widen its left margin
   so adjacent [checkbox][label] pairs read as visually separated groups
   rather than a continuous strip. The first checkbox in each row keeps its
   smaller leading indent (above). */
.ctrl-checkbox,
.alt-checkbox,
.num-lock-checkbox,
.select-target-checkbox {
  margin-left: var(--panel-pair-gap);
}

.additional-ib-properties,
.additional-var-properties {
  /* Indent the rows to level 1, under the section heading, and space them on
     the shared inter-row gap (was a fixed 3px bottom margin). A flex row so a
     wide text field fills the remaining width and shrinks instead of running off
     the panel; wrap keeps multi-checkbox rows tidy when the panel is narrow. */
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 2px;
  margin: 0 var(--panel-right-gutter, 12px) 0 var(--panel-indent);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
}
/* The single wide field in a property row (a URL, an expression, a target select)
   fills the space left of the label and shrinks with the panel — no overflow. */
.additional-ib-properties > .link-input,
.additional-ib-properties > .set-to-text-input,
.additional-ib-properties > .if-condition,
.additional-ib-properties > .then-statement,
.additional-ib-properties > .else-statement,
.additional-ib-properties > .drop-targets,
.additional-ib-properties > .scroll-targets {
  flex: 1 1 90px;
  min-width: 0;
  width: auto;
  box-sizing: border-box;
}

/* Shared visual styling for editable text inputs in the prototype panel —
   matches the design-panel text inputs (color hex, stroke width, etc.).
   Width and margin remain per-instance since they're content-specific. */
.delay-input,
.key-down-input,
.playback-zoom-input,
.user-variable-name-input,
.user-variable-initial-value-input,
.link-input,
.set-to-text-input,
.if-condition,
.then-statement,
.else-statement {
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  vertical-align: middle;
  font-size: var(--editor-control-font-size);
}

.delay-input {
  position: relative;
  top: -1px;
  width: 40px;
  /* flex-basis pins the width against the `.details-scroll input { width:
     100% }` override in the flex .additional-ib-properties row. */
  flex: 0 0 40px;
}

.star-depth-slider {
  display: inline-block;
  position: relative;
  margin: 0 var(--panel-control-gap) 0 0;
  width: 100px;
  vertical-align: middle;
}

.hovering-select-label {
  font-size: var(--editor-control-font-size);
}

/* Match the variable-name label column (fixed width, inline-block) so the
   key input lines up under the variable inputs above it. */
.key-down-label {
  display: inline-block;
  margin: 0 3px 0 12px;
  width: 42px;
  font-size: var(--editor-control-font-size);
}

/* Playback "Zoom %" label — wider than the standard 42px column and
   no-wrap so the input doesn't get pushed to a second line. */
.playback-zoom-label {
  display: inline-block;
  margin: 0 3px 0 12px;
  width: 60px;
  white-space: nowrap;
  font-size: var(--editor-control-font-size);
}

.key-down-input,
.playback-zoom-input {
  margin: 0 3px;
  width: 70px;
  /* flex-basis pins the width against the `.details-scroll input { width:
     100% }` override in the flex .additional-ib-properties row. */
  flex: 0 0 70px;
  box-sizing: border-box;
}

.ctrl-label,
.shift-label,
.alt-label,
.caps-lock-label,
.num-lock-label {
  font-size: var(--editor-control-font-size);
}

/* Frame-transition sub-group (navigate / back behaviors). Selects are fluid so
   the `.details-scroll select { width: 100% }` override can't push them off the
   panel; the duration box pins a small flex-basis (flex-basis beats width). */
.transition-label {
  margin: 0 3px 0 12px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.transition-type-select,
.transition-dir-select,
.transition-easing-select {
  flex: 1 1 90px;
  min-width: 0;
  max-width: 100%;
}
.transition-duration-input {
  flex: 0 0 56px;
  width: 56px;
  box-sizing: border-box;
}
.transition-ms-label {
  margin: 0 3px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}

/* Animate action (property animation) controls. Numeric boxes pin a small
   flex-basis so the width override can't stretch them; the easing select is
   fluid. */
.animate-check {
  flex: 0 0 auto;
  margin: 0 2px 0 12px;
}
/* Track label after a checkbox (Fade to / Move to / …): standard gap to its
   control on the right; small gap after the checkbox on the left. */
.animate-label {
  margin: 0 var(--panel-control-gap) 0 4px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
/* A leading label with no checkbox (Duration / Easing) lines up with the
   checkbox column above it rather than the row's left edge. */
.animate-lead-label {
  margin-left: 12px;
}
.animate-axis-label {
  margin: 0 2px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}
.animate-num-input {
  flex: 0 0 48px;
  width: 48px;
  box-sizing: border-box;
  text-align: var(--number-input-align, right);
}
.animate-easing-select {
  flex: 1 1 90px;
  min-width: 0;
  max-width: 100%;
}

/* Move-to coordinates: x and y each on their own line, indented one level
   under the "Move to" checkbox. */
.animate-subrow {
  margin-left: calc(var(--panel-indent) * 2);
}
.animate-sub-label {
  margin-right: var(--panel-control-gap);
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}
/* Coordinate box holds a value WITH its unit as part of the control
   (e.g. "120 mm"), so it's wider; honors the number-alignment preference. */
.animate-move-input {
  flex: 0 0 96px;
  width: 96px;
  box-sizing: border-box;
  text-align: var(--number-input-align, right);
}

/* Preview progress: a temporary status bar shown only while a preview plays. */
.animate-preview-status {
  align-items: center;
}
.animate-preview-track {
  flex: 1 1 auto;
  min-width: 0;
  height: 6px;
  margin-left: 12px;
  background: var(--editor-input-bg);
  border: 1px solid var(--editor-control-border-color);
  border-radius: 3px;
  overflow: hidden;
}
.animate-preview-fill {
  height: 100%;
  background: var(--prototype-accent);
  transition: width 0.05s linear;
}
.animate-preview-status-label {
  flex: 0 0 auto;
  margin: 0 12px 0 8px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}

/* Preview button: plays the animation once in the editor. Sits at the row's
   left edge under the animate tracks. */
.animate-preview-btn {
  flex: 0 0 auto;
  margin-left: 12px;
  padding: 2px 10px;
  font-size: var(--editor-control-font-size);
  color: var(--prototype-accent);
  background: transparent;
  border: 1px solid var(--prototype-accent);
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
}
.animate-preview-btn:hover {
  background: color-mix(in srgb, var(--prototype-accent) 12%, transparent);
}

.link-label {
  margin: 0 var(--panel-control-gap) 0 12px;
  font-size: var(--editor-control-font-size);
}

.link-input {
  position: relative;
  margin: 0 3px;
  width: 180px;
}

.user-variable-list,
.user-variable-type-list {
  max-width: 160px;
  margin: 0 3px;
  font-size: var(--editor-control-font-size);
}

.user-variable-name-label,
.user-variable-list-label,
.user-variable-type-label,
.user-variable-initial-value-label {
  display: inline-block;
  margin: 0 3px 0 12px;
  width: 42px;
  font-size: var(--editor-control-font-size);
}

.user-variable-name-input {
  margin: 0 3px;
  width: 140px;
}

.user-variable-initial-value-input {
  margin: 0 3px;
  width: 140px;
}

/* ── Variables section (prototype panel) ─────────────────────────────────
   Row-per-variable layout. The header has a "+" button to add; each row
   carries inputs for name, type, initial value, and a delete button. */
.variables-empty {
  margin: 0 0 0 var(--panel-indent);
  margin-right: 12px;
  font-size: var(--editor-control-font-size);
  line-height: 1.35;
  opacity: 0.7;
}

.variables-table {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 12px 0 var(--panel-indent);
}

.variables-row {
  display: grid;
  /* Fixed delete column (icon box = 18px + 1px padding) so the header row's
     empty delete cell and the data rows' minus button share the same width —
     otherwise the `auto` column is 0 in the header and the columns don't line
     up with the inputs below. */
  grid-template-columns: 1fr 84px 1fr 20px;
  column-gap: 6px;
  align-items: center;
}

.variables-row > .variables-delete-icon {
  justify-self: end;
}

.variables-header-row {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--editor-muted-text-color);
  text-transform: uppercase;
  margin-bottom: 0;
}

.variables-name-input,
.variables-value-input {
  width: 100%;
  min-width: 0;
  padding: 1px 4px;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  box-sizing: border-box;
}

.variables-type-select {
  width: 100%;
  min-width: 0;
  font-size: var(--editor-control-font-size);
  box-sizing: border-box;
}


.set-to-text-input {
  width: 180px;
}

.conditional-label {
  display: inline-block;
  width: 32px;
  margin: 0 var(--panel-control-gap) 0 12px;
  font-size: var(--editor-control-font-size);
}

.if-condition,
.then-statement,
.else-statement {
  width: 170px;
}

.vi-textarea-text {
  display: block;
  box-sizing: border-box;
  width: calc(100% - var(--panel-indent) - var(--panel-right-gutter));
  font-family: var(--editor-font-family);
  font-size: var(--editor-control-font-size);
  /* Carry the half inter-row gap top/bottom so the text box isn't cramped
     against the align row above and the next section below. */
  margin: var(--details-row-pad) var(--panel-right-gutter) var(--details-row-pad) var(--panel-indent);
}

/* The Text panel's rich-text editing area: a contentEditable that renders the
   item's styled runs so you can select a range and restyle just that part. */
.vi-rich-text {
  display: block;
  box-sizing: border-box;
  width: calc(100% - var(--panel-indent) - var(--panel-right-gutter));
  min-height: 3.5em;
  max-height: 220px;
  overflow-y: auto;
  padding: 6px 8px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  /* Fallback; the component sets the exact canvas colour inline (ge.vc.backgroundColor). */
  background: var(--canvas-background-color);
  white-space: pre-wrap;
  word-break: break-word;
  outline: none;
  margin: var(--details-row-pad) var(--panel-right-gutter) var(--details-row-pad) var(--panel-indent);
}
.vi-rich-text:focus {
  border-color: var(--editor-selected-blue);
}
/* Placeholder for an empty editor (contentEditable has no native placeholder). */
.vi-rich-text:empty::before {
  content: attr(data-placeholder);
  color: var(--editor-text-muted-color, #888);
  pointer-events: none;
}

/* Pen ring controls and generic rotation helpers. */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

.rings-div {
  /* Relative flow (not absolutely nudged) so the prev/next triangles line up
     inline with the ring name and the rest of the pen-mode row. */
  display: inline-flex;
  align-items: center;
  margin-left: 5px;
}

.ring-descr-div {
  display: inline-flex;
  align-items: center;
  /* Prev/next triangles sit well clear of the "Ring" label. */
  margin-right: 18px;
}

#ring-p {
  font-size: 12px;
  font-weight: bold;
  margin: 0;
}

.ring-icon {
  display: inline-block;
  width: var(--editor-small-icon-size);
  /* Dim at rest, brighten on hover — same as the plus/minus icon-buttons
     (the :hover rule already sets opacity:1). */
  opacity: var(--editor-icon-muted-opacity);
}

.rotate-90 {
  transform: rotate(90deg);
}

.rotate-180 {
  transform: rotate(180deg);
}

.rotate-270 {
  transform: rotate(270deg);
}

.stroke-align-select {
  margin-left: 0;
  vertical-align: middle;
}

p.sides-p {
  width: 35px;
}

.sides-dim {
  width: 100px;
}

/* Dark theme overrides. Colors come from CSS variables that the
   PreferencesProvider sets on :root. The non-color tweaks here adjust
   the few hard-coded swatches, borders, and form-control surfaces that
   wouldn't track those variables on their own. */
[data-theme="dark"] {
  color-scheme: dark;
  --canvas-background-color: #0c0e12;
  --panel-border-color: #2a2c33;
  --code-accent: #4ec78e;
  --data-accent: #e05cc0;
  --prototype-accent: #f0a35e;
  /* Buttons use a MUTED green here (not the bright text accent above) with white
     text, so a filled code button doesn't glare on the dark canvas. */
  --code-accent-btn: #1a805a;
  --code-accent-fg: #fff;
  /* Darker amber fill so white text passes contrast on the dark canvas
     (the light --prototype-accent above stays for accent text/lines). */
  --prototype-accent-btn: #bd5a12;
  --prototype-accent-fg: #fff;
  --editor-border-color: #2a2c33;
  /* Code-editor pane syntax-highlight palette (dark theme). */
  --syn-comment: #6a9955;
  --syn-keyword: #569cd6;
  --syn-string: #ce9178;
  --syn-number: #b5cea8;
  --syn-boolean: #569cd6;
  --syn-tag: #569cd6;
  --syn-attr: #9cdcfe;
  --syn-prop: #9cdcfe;
  --syn-punct: #b8b8c0;
  /* Form-control surface and a section-title color that sits midway
     between the bright body text and the muted labels so titles read
     as a quieter "structural" element instead of glare. */
  --editor-input-bg: #15171c;
  --editor-input-bg-disabled: #1f2126;
  --editor-input-text-color: #b9b7c5;
  --header-1-color: #d9d8e3;
  --header-2-color: #c9c7d6;
  --header-3-color: #8f8d9e;
  --tree-list-bg: #0e1014;
  --tool-active-bg: #383b44;
  --tool-button-bg: #34373f;
  --tree-selection-bg: rgba(16, 151, 226, 0.30);
  /* Focused-control ring. Sits clearly above the input-bg / panel
     surfaces but well below body text, so the focus state reads as
     "marked" without the bright white glare the browser default
     produces on top of the dark panels. */
  --input-focus-outline: #4a4d57;
  /* Dark-mode action-button surface. */
  --button-bg: #23252b;
  --button-bg-hover: #2e3038;
  --button-text: var(--editor-text-color);
}

[data-theme="dark"] .tools-group {
  border-color: #2f323a;
}

[data-theme="dark"] .tools button {
  background: var(--tool-button-bg);
}

[data-theme="dark"] .tool {
  background: #ffffff08;
}

[data-theme="dark"] #text-area {
  color: #e8e8ee;
}

[data-theme="dark"] .hdr {
  color: #6c707b;
  opacity: 1;
}

/* Tree panel reads as the darkest "structural" surface so its content
   stands out from the brighter details panel. */
[data-theme="dark"] .tree-div {
  background-color: var(--tree-list-bg);
}

/* Tool/details/tree icons ship as dark glyphs on a light surface. On
   dark theme, invert their luminance so the strokes become near-white
   against the now-dark panels, with a hue-rotate to keep colored
   accents roughly where they were. Top-toolbar icons (play, share,
   user, notifications, zoom-plus/minus, etc.) are NOT inverted —
   they're already drawn as light glyphs and the top toolbar stays
   dark in both themes. */
[data-theme="dark"] .tool-icon,
[data-theme="dark"] .pen-icon,
[data-theme="dark"] .align-icon,
[data-theme="dark"] .arrow-icon,
[data-theme="dark"] .cap-icon-img,
[data-theme="dark"] .corners-icon,
[data-theme="dark"] .corner-count-icon,
[data-theme="dark"] .angle-icon,
[data-theme="dark"] .star-ratio-icon,
[data-theme="dark"] .line-width-icon,
[data-theme="dark"] .stroke-width-icon,
[data-theme="dark"] .add-fill-icon,
[data-theme="dark"] .unify-paint-icon,
[data-theme="dark"] .paint-row-none,
[data-theme="dark"] .add-palette-color-icon,
[data-theme="dark"] .add-stroke-icon,
[data-theme="dark"] .add-behavior-icon,
[data-theme="dark"] .add-variable-icon,
[data-theme="dark"] .add-trigger-icon,
[data-theme="dark"] .add-group-icon,
[data-theme="dark"] .remove-groups-icon,
[data-theme="dark"] .delete-color-icon,
[data-theme="dark"] .delete-stroke-icon,
[data-theme="dark"] .delete-gradient-icon,
[data-theme="dark"] .delete-gradient-color-icon,
[data-theme="dark"] .delete-behavior-icon,
[data-theme="dark"] .delete-ring-icon,
[data-theme="dark"] .variables-delete-icon,
[data-theme="dark"] .delete-trigger-icon,
[data-theme="dark"] .page-list-plus-icon,
[data-theme="dark"] .page-list-minus-icon,
[data-theme="dark"] .templates-add-icon,
[data-theme="dark"] .templates-delete-icon,
[data-theme="dark"] .minus-variable-icon,
[data-theme="dark"] .page-triangle-img,
[data-theme="dark"] .section-triangle-img,
[data-theme="dark"] .dim-subtriangle,
[data-theme="dark"] .tree-triangle-img,
[data-theme="dark"] .tree-type-icon,
[data-theme="dark"] .corners-triangle,
[data-theme="dark"] .line-width-triangle,
[data-theme="dark"] .sight-icon,
[data-theme="dark"] .eyedropper,
[data-theme="dark"] .color-picker-mode-cancel-icon,
[data-theme="dark"] .ring-icon,
[data-theme="dark"] .group-icon,
[data-theme="dark"] .union-icon,
[data-theme="dark"] .outline-icon,
[data-theme="dark"] .exclude-icon,
[data-theme="dark"] .intersect-icon,
[data-theme="dark"] .subtract-icon,
[data-theme="dark"] .mask-icon,
[data-theme="dark"] .palette,
[data-theme="dark"] .selected-icon,
[data-theme="dark"] .scale-skew-icon,
[data-theme="dark"] .cap-link-toggle,
[data-theme="dark"] .token-link-icon {
  filter: invert(0.94) hue-rotate(180deg) brightness(1.02);
}

/* ── Standard control sizing (Design + Prototype panels) ───────────────────
   Every edit box (text/number) and drop-down in the right-hand panels shares
   ONE height and ONE text size, so rows read as a consistent grid. Widths are
   deliberately left per-control (a font name needs more room than a px value),
   so this rule never touches `width` or `box-sizing` — height is pinned by
   font-size + line-height + vertical padding + border, which lands at the same
   outer height whether a control was content-box or border-box. Selects that
   were unstyled (native) also pick up the shared border/radius here. Excludes
   checkbox/radio/color/range (not listed) and textarea (multi-line). */
.details-scroll input[type="text"],
.details-scroll input[type="number"],
.details-scroll input[type="search"],
.details-scroll input:not([type]),
.details-scroll select,
/* Left-panel edit boxes that need the SAME flat control look (the flat border/
   radius is otherwise scoped to .details-scroll, so these fell back to the
   browser's inset 3-D input) — e.g. the flow inspector's node / branch labels. */
.flow-node-label,
.flow-conn-label,
.flow-condition {
  /* Fill the inspector's width (leaving its padding as the right gutter) instead
     of the browser's intrinsic input width — matching every other panel field. */
  box-sizing: border-box;
  width: 100%;
  font-size: var(--editor-control-font-size);
  line-height: var(--editor-control-line-height);
  padding-top: var(--editor-control-pad-y);
  padding-bottom: var(--editor-control-pad-y);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
}

/* The Diagrams-mode FlowNode inspector renders real paragraph captions (condition
   hints, variable lists, validation notes). Exempt them from the panel-wide
   `.details-div p` rule (0,1,1) that forces every panel <p> into a 14px inline-block
   glyph-label box — that collapsed these captions to one word per line. The two-class
   selector (0,2,1) beats it; each <p> keeps its own inline margin. */
.details-div .flow-node-section p {
  display: block;
  width: auto;
}

/* Segmented Manual / Automatic layout toggle in the diagram inspector (right panel). */
.flow-layout-toggle {
  display: flex;
  width: fit-content;
  border: 1px solid var(--editor-border-color);
  border-radius: 5px;
  overflow: hidden;
}
.flow-layout-btn {
  padding: 3px 12px;
  border: none;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  background: transparent;
  color: var(--editor-text-color);
}
.flow-layout-btn.active {
  background: var(--code-accent-btn);
  color: var(--code-accent-fg);
}

/* Give EVERY left-panel (.tree-div) edit box the app's flat control border — the
   .details-scroll flat style above is right-panel-scoped, so left-panel inputs
   otherwise fall back to the browser's inset 3-D input. Border/radius only (no
   width or size assumptions), so it just flattens without reshaping any field. */
.tree-div input[type="text"],
.tree-div input[type="number"],
.tree-div input[type="search"],
.tree-div input:not([type]) {
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
}

/* Native <select> combo boxes render a hair taller than a text input with the
   same line-height/padding (UA min-block-size + dropdown metrics). Pin them to
   the exact standard control height so every edit box and combo box in the
   panel is the same size. Height = line-height + 2·pad-y + 2·1px border. */
.details-scroll select {
  box-sizing: border-box;
  height: calc(var(--editor-control-line-height) + 2 * var(--editor-control-pad-y) + 2px);
}

/* Form-control surface: every editable text/number input and select
   inside the editor uses the panel-input variable for a dark
   background. Input text is a touch dimmer than body text so the
   labels (which use --editor-muted-text-color) and section titles
   read with a clean hierarchy. Range sliders are excluded — the
   browser's color-scheme: dark on :root re-skins them automatically. */
[data-theme="dark"] input[type="text"],
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="search"],
[data-theme="dark"] input[type="email"],
[data-theme="dark"] input[type="password"],
[data-theme="dark"] input:not([type]),
[data-theme="dark"] textarea,
[data-theme="dark"] .flow-node-label,
[data-theme="dark"] .flow-conn-label,
[data-theme="dark"] .flow-condition,
[data-theme="dark"] select {
  background-color: var(--editor-input-bg);
  color: var(--editor-input-text-color);
  border-color: var(--editor-control-border-color);
}

[data-theme="dark"] input[type="text"]:disabled,
[data-theme="dark"] input[type="number"]:disabled,
[data-theme="dark"] input:not([type]):disabled,
[data-theme="dark"] textarea:disabled,
[data-theme="dark"] select:disabled {
  background-color: var(--editor-input-bg-disabled);
  color: var(--editor-muted-text-color);
}

/* Color swatch borders need to read against the dark panel. */
[data-theme="dark"] .color-div,
[data-theme="dark"] .palette-color-div,
[data-theme="dark"] .constraints-outer-box,
[data-theme="dark"] .constraints-inner-box {
  border-color: #4a4d57;
}

/* Item-tree row text & file-name text — explicit color so it sits
   correctly on the darker tree panel surface. */
[data-theme="dark"] .item-tree-item p,
[data-theme="dark"] p.file-name-p {
  color: var(--editor-text-color);
}

/* Project-image placeholder background on home page. */
[data-theme="dark"] .project-img-placeholder {
  background-color: rgba(255, 255, 255, 0.03);
}

/* Top-toolbar glyphs ship in near-white (#DEDEDE) and read as overly
   loud against the very dark toolbar. Dim them a touch in dark mode
   so they sit at roughly the same visual weight as the rest of the
   chrome. The standard-top-toolbar-icon class is the umbrella used by
   most of these icons, so this single rule covers the bulk of them. */
[data-theme="dark"] .standard-top-toolbar-icon,
[data-theme="dark"] .tt-zoom-icon,
[data-theme="dark"] .logo-icon {
  opacity: 0.85;
}

/* Disclosure triangles originally use --editor-icon-muted-opacity (0.6);
   combined with the dark-theme invert filter that's too faint, so push
   them up to stay readable. The page-list add/remove icons deliberately
   stay at the muted 0.6 (via .page-list-plus-icon/.page-list-minus-icon)
   so they recede like the design-panel section icons and titles. */
[data-theme="dark"] .page-triangle-img,
[data-theme="dark"] .section-triangle-img,
[data-theme="dark"] .corners-triangle,
[data-theme="dark"] .line-width-triangle,
[data-theme="dark"] .minus-variable-icon {
  opacity: 0.9;
}

/* Zoom percentage reads as toolbar text by default — very bright in
   dark mode. Match the design-panel input text color so it doesn't
   draw the eye as much as the rest of the toolbar chrome. */
[data-theme="dark"] .zoom-percentage,
[data-theme="dark"] .zoom-percentage-textbox {
  color: var(--editor-input-text-color);
}

/* Focused-control outline. Default browser behavior renders a bright
   ring; the editor's per-input rules also set outline-color to the
   bright editor-text-color. In dark mode, swap both to a softer
   mid-gray that reads as "focused" without glaring. Buttons get the
   same treatment so the focus ring across the Home / Customize /
   Login / Signup / Images pages stays consistent. */
[data-theme="dark"] input:focus,
[data-theme="dark"] input:focus-visible,
[data-theme="dark"] textarea:focus,
[data-theme="dark"] textarea:focus-visible,
[data-theme="dark"] select:focus,
[data-theme="dark"] select:focus-visible,
[data-theme="dark"] button:focus-visible {
  outline: 2px solid var(--input-focus-outline);
  outline-offset: -1px;
  border-color: var(--input-focus-outline);
}

/* Page-level surface. The .App element already paints the panel
   background across the whole viewport, but if any page is ever
   sized smaller than the window, html/body fall back to the same
   surface so the user never sees the browser's default white. */
html[data-theme="dark"],
html[data-theme="dark"] body {
  background-color: var(--editor-panel-background-color);
}

html[data-theme="light"],
html[data-theme="light"] body {
  background-color: var(--editor-panel-background-color);
}

/* ============================================================
   Fill / stroke gradient editor
   ============================================================ */

.gradient-editor {
  margin: 0 var(--panel-right-gutter, 12px) 0 var(--panel-indent);
  /* Carry the half-gap like a row so it sits a full inter-row gap from its
     neighbours (graphic blocks otherwise only get the neighbour's half). */
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  display: flex;
  flex-direction: column;
  gap: var(--details-row-gap);
}

/* Fill-type combo box, sat at the end of the color line. */
.gradient-type-select {
  /* flex-basis (max-content) pins the width to the combo's own content so the
     global `.details-scroll select { width: 100% }` rule can't stretch it to the
     full panel width (which pushed it off the edge). All four fill controls —
     swatch, hex, alpha, type — then fit on one line. */
  flex: 0 0 max-content;
  margin-left: auto;
  margin-right: 8px;
  padding: 2px 4px;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}

/* Image-fill editor (Fill section, when the fill type is Image): a fit-mode row and a
   "Select image" button that opens the gallery. A block below the colour line. */
.image-fill-editor {
  margin: 0 var(--panel-right-gutter, 12px) 0 var(--panel-indent);
  /* Carry the half-gap like a row (see .gradient-editor). */
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.image-fill-fit-row {
  display: flex;
  align-items: center;
  gap: 8px;
  align-self: stretch;
}
.image-fill-fit-row label {
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.image-fill-fit {
  flex: 1 1 0;
  min-width: 0;
  padding: 2px 4px;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}
.image-fill-select { margin: 0; }

/* Custom / Tile manual scale + offset controls. Scale rows reuse .scale-skew-* styles. */
.image-fill-xform {
  display: flex;
  flex-direction: column;
  gap: 5px;
  align-self: stretch;
}
.image-fill-offset-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.image-fill-offset-label {
  flex: 0 0 auto;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.image-fill-offset-axis {
  flex: 0 0 auto;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-muted-color, #888);
}
.image-fill-offset-in {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
  padding: 2px 4px;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  text-align: right;
}

/* Preview bar + draggable stop markers. */
.gradient-bar {
  display: flex;
  flex-direction: column;
  /* Separate the ramp from the marker strip via flex gap — a margin here gets
     zeroed by the panel's blanket margin reset, so the markers would ride up
     onto the ramp. */
  gap: 3px;
}

/* Preview bar: a checkerboard backdrop with the live gradient on top so
   stop transparency reads correctly. */
.gradient-preview {
  position: relative;
  height: 18px;
  overflow: hidden;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: #ffffff;
  background-image:
    linear-gradient(45deg, #c8c8c8 25%, transparent 25%, transparent 75%, #c8c8c8 75%),
    linear-gradient(45deg, #c8c8c8 25%, transparent 25%, transparent 75%, #c8c8c8 75%);
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
}

.gradient-preview-fill {
  position: absolute;
  inset: 0;
}

/* Strip below the preview bar holding the draggable stop markers. Height hugs
   the 12px marker so no dead space opens up before the first color row (the
   ramp↔marker gap lives on .gradient-bar). */
.gradient-marker-track {
  position: relative;
  height: 12px;
}

.gradient-marker {
  position: absolute;
  top: 0;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  box-sizing: border-box;
  border: 2px solid #ffffff;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
  cursor: ew-resize;
}

/* Indicator line spanning the full preview bar at each stop's location.
   Rendered inside .gradient-preview (which clips it) so it covers the
   whole bar height. */
.gradient-stop-indicator {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background-color: #ffffff;
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.55);
  pointer-events: none;
}

.gradient-stops {
  display: flex;
  flex-direction: column;
  /* Stack the stop rows on the one inter-row gap (was a one-off 4px). */
  gap: var(--details-row-gap);
}

.gradient-stop-row {
  display: flex;
  align-items: center;
  gap: var(--panel-checkbox-label-gap);
}

/* The hex box carries a right margin for the non-flex solid color line; in
   the flex stop row that margin stacks on top of the gap, so zero it here. */
.gradient-stop-row .color-text-input {
  margin: 0;
}

.gradient-stop-color {
  flex: none;
  width: 28px;
  height: 20px;
  padding: 0;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background: none;
  cursor: pointer;
}

.gradient-stop-alpha {
  /* flex-basis (not width) so `.details-scroll input { width: 100% }` can't
     stretch it across the row. */
  flex: 0 0 52px;
  box-sizing: border-box;
  padding: 2px 4px;
  border: 1px solid var(--editor-control-border-color);
  border-radius: var(--corner-radius-sm);
  background-color: var(--editor-input-bg, var(--editor-panel-background-color));
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}

.gradient-stop-range {
  flex: 1 1 auto;
  min-width: 0;
}

/* The hex field in a gradient stop row: pin its basis so it (like the alpha
   field) isn't stretched to 100% by `.details-scroll input`; the slider
   (flex 1 1) then takes the remaining width. */
.gradient-stop-row .color-text-input {
  flex: 0 0 64px;
  width: 64px;
}

.gradient-stop-pos {
  flex: none;
  width: 34px;
  text-align: right;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}

/* Same bare-glyph look/feel as the other delete (minus) icons via the
   .delete-color-icon class, at the standard small-icon size. */
.gradient-stop-remove {
  flex: none;
  height: var(--editor-small-icon-size);
}

.gradient-add-stop {
  align-self: flex-start;
  cursor: pointer;
}

.gradient-add-stop:hover {
  opacity: 1;
}

/* Numeric start/end endpoint controls (the panel twin of the on-canvas handles).
   Standard inter-row spacing: one --details-row-pad each side per row, plus one
   before the whole block so it's a full row gap from the add-stop button above. */
/* The Start / End rows sit as two children of the .gradient-editor flex column,
   which already puts one --details-row-gap between every block. So NO margin-top
   here (that stacked on the parent gap → extra space above Start) and NO per-row
   vertical padding (that stacked below End); the block's own `gap` spaces the two
   rows by the same single inter-row gap. */
.gradient-endpoints {
  display: flex;
  flex-direction: column;
  gap: var(--details-row-gap);
}
/* Proximity: the wide --panel-pair-gap separates the row's groups (the Start/End
   label and the two X | Y pairs), while each axis label hugs its own input with
   the tighter --panel-checkbox-label-gap below. Mirrors the .dim-row X/Y row. */
.gradient-endpoint-row {
  display: flex;
  align-items: center;
  gap: var(--panel-pair-gap);
}
.gradient-endpoint-label {
  flex: 0 0 40px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
}
/* One (axis label + input) pair. Each cell shares the row equally and grows,
   so the two fields fill the extra width — mirrors the shadow X/Y offset row. */
.gradient-endpoint-cell {
  display: inline-flex;
  align-items: center;
  flex: 1 1 0;
  min-width: 0;
}
.gradient-endpoint-axis {
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  margin-right: var(--panel-checkbox-label-gap);
  user-select: none;
}
/* Grow into the spare row width (flex-basis 0 + grow), beating
   `.details-scroll input { width: 100% }` via flex. */
.gradient-endpoint-input {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
  box-sizing: border-box;
  padding: 2px 4px;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}

/* The gradient endpoint handles are drawn directly on the canvas by the
   renderer (see render.ts drawGradientHandles) — no CSS overlay. */

/* ============================================================
   Color-picker eyedropper overlay & magnifier loupe
   ============================================================ */

/* Transparent layer shown while the color picker is in eyedropper
   mode. It covers only the canvas region (matching #canvas-div) so the
   toolbars and panels stay usable; sits below the toolbar dropdown
   menus (z-index 55–60) so those still open over it. */
.eyedropper-overlay {
  position: fixed;
  top: var(--top-toolbar-height);
  left: calc(var(--left-toolbar-width) + var(--tree-width));
  right: var(--details-width);
  bottom: 0;
  z-index: 50;
  background: transparent;
  cursor: crosshair;
}

/* The magnifier loupe — a zoomed view of the canvas pixels around the
   cursor. Positioned (in viewport coords) in a canvas corner; round or
   square per prefs. */
.eyedropper-loupe {
  position: fixed;
  box-sizing: content-box;
  border: 3px solid #ffffff;
  box-shadow:
    0 6px 20px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(0, 0, 0, 0.4);
  overflow: hidden;
  pointer-events: none;
  background: #7a7a82;
}

.eyedropper-loupe.round {
  border-radius: 50%;
}

.eyedropper-loupe.square {
  border-radius: 10px;
}

.eyedropper-loupe canvas {
  display: block;
}

/* ---- Components section (composition layer) ---- */
.templates-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--panel-control-gap);
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}

.templates-btn {
  font-size: var(--editor-control-font-size);
  padding: 3px 10px;
  border: 1px solid var(--editor-border-color, rgba(128, 128, 128, 0.4));
  border-radius: 4px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.templates-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.templates-instance-label {
  margin: 0 0 0 var(--panel-indent);
  font-size: var(--editor-control-font-size);
  opacity: 0.85;
}

.templates-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0 12px 0 var(--panel-indent);
}

.templates-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  column-gap: 8px;
  align-items: center;
}

.templates-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.templates-count {
  opacity: 0.6;
  font-size: var(--editor-control-font-size);
}

.templates-delete-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  cursor: pointer;
  user-select: none;
}
/* Highlight the delete (−) on hover so it reads as an interactive button, across every
   library section (colours / text styles / layouts). */
.templates-delete-icon:hover {
  opacity: 1;
}

/* Component-instance badge (tree rows + library) */
/* Component/instance marker — a hollow diamond drawn as a rotated square so
   it centers exactly (a ◇ text glyph sits off its optical center). */
.tree-instance-badge {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-right: 6px;
  border: 1.5px solid var(--accent-color, #7a5cff);
  transform: rotate(45deg);
  box-sizing: border-box;
  user-select: none;
}

/* In the tree, the diamond sits in a slot the same size as a type icon so
   every row's text lines up regardless of icon vs. diamond. */
.item-tree-item .tree-instance-slot {
  height: 16px;
  width: 16px;
  padding: 0 5px 0 0;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  user-select: none;
}
.item-tree-item .tree-instance-slot .tree-instance-badge {
  margin: 0;
}

/* The mid-purple is muddy against the near-black dark panels; lighten it
   so the marker keeps clear contrast. */
[data-theme="dark"] .tree-instance-badge {
  border-color: #b9a7ff;
}

/* A code-owned component (data node / UI control) uses the same diamond but in the
   code green (the data-binding green), not the template accent — lightened for dark. */
.tree-instance-badge.tree-component-badge {
  border-color: #15825a;
}
[data-theme="dark"] .tree-instance-badge.tree-component-badge {
  border-color: #4ec78e;
}
/* A non-data (UI) component: a FILLED purple diamond — the standard glyph for
   that component type (a template instance is the same purple, but outlined). */
.tree-instance-badge.tree-ui-component-badge {
  border: none;
  background-color: #7a5cff;
}
[data-theme="dark"] .tree-instance-badge.tree-ui-component-badge {
  background-color: #b9a7ff;
}

/* Components library — left panel section (between Pages and the tree) */
.templates-panel-div {
  padding: 8px 0;
}

.templates-panel-header {
  display: flex;
  align-items: center;
}

.templates-panel-heading {
  margin: 0;
  user-select: none;
  display: inline-block;
  vertical-align: middle;
  color: var(--header-2-color);
}

.templates-add-div {
  margin-left: auto;
  /* Match the Pages header's right-edge gap (`.page-header-row` padding-right)
     so the Templates "+" lines up horizontally with the Pages "+" — both sit in
     the same tree panel, so a different gap left them visibly misaligned. */
  margin-right: 10px;
  display: inline-flex;
  align-items: center;
}

.templates-add-icon {
  opacity: var(--editor-icon-muted-opacity);
  height: var(--editor-small-icon-size);
  cursor: pointer;
  user-select: none;
}

.templates-add-icon.disabled {
  opacity: 0.25;
  cursor: default;
}
/* Highlight the add (+) on hover so it reads as an interactive button — across every library
   section (components / colours / text styles / layouts). Skips the disabled state. */
.templates-add-icon:not(.disabled):hover {
  opacity: 1;
}

.templates-empty {
  margin: 0 0 0 var(--panel-indent);
  font-size: var(--editor-control-font-size);
  opacity: 0.7;
}

.templates-panel-ul {
  list-style: none;
  /* Right margin matches the section "+" gap (.templates-add-div, 10px) so the
     row "−" lines up under the "+" — and with every other assets section. */
  margin: 0 10px 0 var(--panel-indent);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.templates-panel-row {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  column-gap: 8px;
  align-items: center;
  /* Space the asset rows on the list / tree-view gap. */
  padding-top: var(--list-row-pad); padding-bottom: var(--list-row-pad);
}

/* Template rows read as clickable links — highlight the whole row on hover. */
.template-link-row {
  border-radius: var(--corner-radius-sm);
}
.template-link-row:hover {
  background-color: var(--editor-hover-bg, rgba(127, 127, 127, 0.15));
}

/* In the library grid the column-gap already spaces the badge from the name,
   so drop the badge's tree-row margin to tighten that gap. */
.templates-panel-row .tree-instance-badge {
  margin-right: 0;
}

/* Colour-token rows: swatch | name | alpha | delete — so the minus sits at the
   row's end like the other panels. The list's right gap matches the header's
   "+" gap (14px) so the row "−" lines up vertically with the section "+"; the
   name column (1fr) gives up the space. */
.color-tokens-ul {
  margin-right: 10px;
}
/* Colour-mode switcher row above the token list: [Mode] [select ▾] [name] [+] [−]. */
.color-mode-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px 6px calc(var(--panel-indent) - 3px);
  font-size: var(--editor-control-font-size);
}
.color-mode-label {
  flex: 0 0 auto;
  opacity: 0.7;
}
.color-mode-select {
  flex: 0 0 auto;
  min-width: 56px;
  max-width: 120px;
  box-sizing: border-box;
  padding: 2px 4px;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
}
.color-mode-name {
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
  padding: 2px 4px;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
}
.templates-panel-row.color-token-row {
  grid-template-columns: auto 1fr auto auto;
}
/* Opacity %. Matches the standard .alpha-input box (Fill/Stroke). */
.color-token-alpha {
  width: 44px;
  box-sizing: border-box;
  padding: 2px 4px;
  text-align: right;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
  vertical-align: middle;
}
/* Colour swatch. Matches the standard .color-div swatch (Fill/Stroke). */
.color-token-swatch {
  width: 28px;
  height: 20px;
  padding: 0;
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: none;
  cursor: pointer;
}
.color-token-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.color-token-swatch::-webkit-color-swatch { border: none; border-radius: 2px; }
.color-token-name {
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  min-width: 0;
  padding: 0;
}

/* ── Spacing/size token library rows ── */
.spacing-tokens-ul {
  margin-right: 10px;
}
/* Name | value | delete. Name and value are both flexible so a panel resize
   splits 55/45 between them (11fr : 9fr); the delete icon stays fixed. */
.templates-panel-row.spacing-token-row {
  grid-template-columns: 11fr 9fr auto;
}
.spacing-token-name {
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  min-width: 0;
  padding: 0;
}
/* Value box. Fills its flexible grid track (so it grows/shrinks with the panel),
   with a floor wide enough to keep a value plus its unit suffix (e.g. "0.5 in"). */
.spacing-token-value {
  width: 100%;
  min-width: 68px;
  box-sizing: border-box;
  padding: 2px 4px;
  text-align: right;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
  vertical-align: middle;
}

/* ── Spacing-token link control (design-panel numeric fields) ── */
/* A compact button that collapses to a link glyph; opens a portalled, viewport-
   clamped menu on click. Turns blue when bound, matching the other token UIs. */
/* ── Shared asset-link control (colour / text-style / spacing tokens) ──
   One button + portalled menu used by every token binding. See TokenLink.tsx. */
.token-link {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
}
/* Link-to-assets control: just the link glyph / token name — NO box (no border,
   no background fill). Follows the icon-button rule: the glyph is muted at rest
   and brightens on hover (opacity, so it lifts the 🔗 emoji and text alike). */
.token-link-btn {
  max-width: 84px;
  box-sizing: border-box;
  margin-left: 4px;
  padding: 1px 3px;
  text-align: center;
  color: var(--editor-muted-text-color);
  font-size: var(--editor-control-font-size);
  border: none;
  background: transparent;
  cursor: pointer;
  vertical-align: middle;
  line-height: 1.4;
  opacity: 0.72;
  transition: opacity 0.1s ease;
}
.token-link-btn .token-link-label {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Linked to a token: show its name in the accent colour. */
.token-link-btn.linked {
  color: var(--selection-color, #1097e2);
}
/* Hover brightens the glyph itself (foreground) — no background box. */
.token-link-btn:hover {
  opacity: 1;
}

/* A token-link sitting in a section header: standard horizontal spacing from
   the title, vertically centred (the header is already a centered flex row). */
.details-header > .token-link {
  margin-left: 6px;
}
.details-header > .token-link .token-link-btn {
  margin-left: 0;
}

/* Portalled menu (position:fixed set inline; clamped to the viewport in JS). */
.token-link-menu {
  position: fixed;
  z-index: 10000;
  min-width: 176px;
  max-height: 260px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--editor-panel-bg, var(--editor-input-bg, #fff));
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}
.token-link-menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 8px;
  border-radius: var(--corner-radius-sm);
  cursor: pointer;
  white-space: nowrap;
}
.token-link-menu-item:hover {
  background: var(--editor-hover-bg, rgba(127, 127, 127, 0.18));
}
.token-link-menu-item.active {
  color: var(--selection-color, #1097e2);
  font-weight: 600;
}
.token-link-menu-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.token-link-menu-meta {
  flex: 0 0 auto;
  color: var(--editor-muted-text-color);
}
/* Colour-token swatch shown as a menu row's trailing meta. */
.token-link-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid var(--editor-control-border-color, rgba(127, 127, 127, 0.5));
}
.token-link-menu-new,
.token-link-menu-unlink {
  margin-top: 0;
  border-top: var(--editor-control-border);
  border-radius: 0;
}
.token-link-menu-empty {
  padding: 4px 8px;
  color: var(--editor-muted-text-color);
}

/* ── Text styles library rows ── */
.text-styles-ul {
  margin-right: 10px;
}
.templates-panel-row.text-style-row {
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
}
/* "Ag" preview rendered in the style's own font; click applies to selected text. */
.text-style-preview {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 20px;
  padding: 0 5px;
  font-size: 13px;
  line-height: 1;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
  cursor: pointer;
  user-select: none;
  overflow: hidden;
}
.text-style-name {
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  min-width: 0;
  padding: 0;
}
/* Update-this-style-from-the-selected-text button (⟳). */
.text-style-update {
  background: none;
  border: none;
  color: var(--editor-text-color);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 2px;
  opacity: 0.7;
}
.text-style-update:hover {
  opacity: 1;
}

/* Layout presets ("Layouts" assets section): built-in one-click chips + saved-preset rows. */
.layout-preset-builtins {
  display: flex;
  flex-wrap: wrap;
  column-gap: 5px;
  row-gap: var(--list-row-gap);
  padding: var(--list-row-pad) var(--panel-right-gutter, 12px) var(--list-row-pad) var(--panel-indent);
}
.layout-preset-chip {
  padding: 3px 9px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  background: var(--button-bg);
  border: var(--editor-control-border);
  border-radius: 10px;
  cursor: pointer;
  white-space: nowrap;
}
.layout-preset-chip:hover {
  border-color: var(--editor-selected-blue);
}
/* The built-in preset buttons live in the right-panel Layout section, indented to level 1. */
.layout-presets-row {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 0 var(--panel-right-gutter, 12px) 0 var(--panel-indent);
}
/* The button matching the frame's current layout is highlighted. */
.layout-preset-chip.active {
  border-color: var(--editor-selected-blue);
  color: var(--editor-selected-blue);
  font-weight: 600;
}
/* Saved layout preset rows: name (1fr) | delete (auto) — the minus sits at the row end like
   the colour/text-style rows, and the list's right gap lines the "−" up with the others. */
.layout-presets-ul {
  margin-right: 10px;
}
.templates-panel-row.layout-preset-row {
  grid-template-columns: 1fr auto;
}
/* Normal-styled (bordered) rename box, filling its grid cell. */
.layout-preset-name {
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  background: var(--editor-input-bg, var(--button-bg));
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  padding: 2px 6px;
}
.layout-preset-apply {
  background: none;
  border: none;
  color: var(--editor-text-color);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 4px 0 0;
  opacity: 0.7;
}
.layout-preset-apply:hover {
  opacity: 1;
}
/* Mask-mode picker (alpha / luminance / clip) shown for a selected mask group.
   Height/font/border come from the shared .details-scroll select rule. */
.mask-mode-row {
  margin-left: var(--panel-indent);
}
.mask-mode-select {
  width: 110px;
}
.blend-mode-row {
  margin-left: var(--panel-indent);
}
.blend-mode-select {
  width: 110px;
}

/* Auto-layout (stacks) panel section. Control height/font/border come from the
   shared .details-scroll select rule; these just lay the rows out. */
.layout-div {
  /* The `.font-div` rows inside ALREADY carry the level-1 indent (margin-left:
     --panel-indent), so this wrapper must NOT add another (that made it level-2 / too deep).
     Only add the right gutter so the flexed controls stop short of the panel edge. */
  margin-right: var(--panel-right-gutter, 12px);
}
.layout-row {
  display: flex;
  align-items: center;
  gap: 5px;
  /* No extra row margin — the standard .font-div row (30px, --details-row-height) already
     spaces itself; an added margin made the section looser than every other panel section. */
}
.layout-row label {
  flex: 0 0 76px;               /* fixed label column so every select/input lines up + equal width */
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
/* The padding row's "Padding" label spans its own line, so it opts out of the fixed column. */
.layout-pad-row label {
  flex-basis: 100%;
}
.layout-select {
  flex: 1 1 0;
  min-width: 0;
}
/* Flex the padding/gap boxes so a row of four shares the width instead of overflowing. */
.layout-input {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
  padding: 2px 4px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  background: var(--editor-input-bg, transparent);
  text-align: right;
}

/* Padding row: 4 inputs (Top, Right, Bottom, Left). Put the label on its own line and let the
   inputs WRAP so each keeps enough width to show its value/formula instead of being squeezed
   onto one cramped line — 4-across when wide, 2×2 when the panel is narrow. */
.layout-pad-row {
  flex-wrap: wrap;
  height: auto;                 /* override .font-div's fixed height so wrapped inputs show */
  row-gap: 4px;
}
.layout-pad-row label {
  flex: 0 0 100%;               /* "Padding" on its own line; the 4 fields form a grid below */
  margin: 0;                    /* the row-gap spaces the label from the inputs — no extra */
  line-height: 1.3;
}
/* Header line = the "Padding" label + its token-link, spanning the full row width so the
   four padding inputs still wrap 4-across BELOW it (the link doesn't steal a field's slot). */
.layout-pad-header {
  flex: 0 0 100%;
  display: flex;
  align-items: center;
  gap: 6px;
}
.layout-pad-row .layout-pad-header label {
  flex: 0 1 auto;               /* not the full-width label rule — sits inline with the link */
}
/* Standard checkbox row (e.g. Wrap): box + label inline. */
.layout-checkbox {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
}
.layout-checkbox input {
  margin: 0;
}
/* Each padding field = a side icon (top/right/bottom/left) + its input. Real data width →
   4-across when wide, 2×2 when narrow. */
.layout-pad-field {
  display: flex;
  align-items: center;
  gap: 3px;
  flex: 1 1 0;
  min-width: 62px;
}
.layout-pad-field .layout-input {
  flex: 1 1 auto;
  min-width: 0;
}
.layout-pad-glyph {
  flex: 0 0 auto;
  color: var(--editor-muted-text-color);   /* the box + edge use currentColor — themes itself */
}

/* Control inspector (Design panel): one label + control per row, at the standard
   panel control font size, with the normal inline checkbox format for booleans. */
.control-prop-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  /* Right gutter keeps flex-filled selects/inputs off the panel's right edge,
     matching the standard panel rows. */
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
}
.control-prop-row > .control-prop-label {
  flex: 0 0 76px;               /* fixed label column so every control lines up */
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.control-prop-row > .layout-select,
.control-prop-row > .control-prop-input {
  flex: 1 1 0;
  min-width: 0;
}
.control-prop-input {
  min-width: 0;
  padding: 1px 4px;
  color: var(--editor-text-color);
  border: var(--editor-control-border);
  border-radius: var(--corner-radius-sm);
  outline-color: var(--editor-text-color);
  font-size: var(--editor-control-font-size);
  box-sizing: border-box;
}
/* Normal checkbox format: box then label, inline (matches .layout-checkbox). */
.control-prop-checkbox {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  margin-left: var(--panel-indent);
  padding-top: var(--details-row-pad); padding-bottom: var(--details-row-pad);
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
.control-prop-checkbox input {
  margin: 0;
}

/* Data tab (left panel, Data mode): a tree of data stores + their fields. */
.data-tree { padding: 4px 0; }
.data-tree-ul, .data-tree-fields { list-style: none; margin: 0; padding: 0; }
.data-tree-store {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: var(--list-row-pad) 10px var(--list-row-pad) 8px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  cursor: pointer;
}
.data-tree-store:hover { background: var(--tree-selection-bg, rgba(127, 127, 127, 0.12)); }
.data-tree-store.selected { background: var(--tree-selection-bg, rgba(127, 127, 127, 0.2)); }
.data-tree-triangle {
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  opacity: var(--editor-icon-muted-opacity, 0.7);
  cursor: pointer;
}
[data-theme="dark"] .data-tree-triangle { filter: invert(1); }
/* Filled diamond glyph in the data accent — the data-store marker. */
.data-tree-badge {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  transform: rotate(45deg);
  background-color: var(--data-accent);
}
/* Intent action nodes read as actions, not stores — a round badge in the Data
   accent, matching the intent node's canvas title bar. */
.data-tree-badge.intent {
  border-radius: 50%;
  transform: none;
  background-color: var(--data-accent);
}
.data-tree-store-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.data-tree-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: var(--list-row-pad) 10px var(--list-row-pad) 34px;      /* indented under the store */
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  cursor: pointer;
}
.data-tree-field:hover { background: var(--tree-selection-bg, rgba(127, 127, 127, 0.1)); }
.data-tree-field.selected {
  background: var(--tree-selection-bg, rgba(127, 127, 127, 0.2));
  box-shadow: inset 2px 0 0 var(--data-accent);
}
.data-tree-field-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.data-tree-field-type { flex: 0 0 auto; font-size: 11px; color: var(--editor-muted-text-color); }
.data-tree-empty {
  padding: 8px 12px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color);
  line-height: 1.4;
}
/* Data bindings (connections) list, below the stores. */
.data-tree-bindings { margin-top: 6px; border-top: 1px solid var(--editor-border-color); }
.data-tree-bindings-header {
  padding: 5px 10px 3px 10px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--data-accent);
}
.data-tree-binding {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: var(--list-row-pad) 10px var(--list-row-pad) 12px;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  cursor: pointer;
}
.data-tree-binding:hover { background: var(--tree-selection-bg, rgba(127, 127, 127, 0.1)); }
.data-tree-binding.selected {
  background: var(--tree-selection-bg, rgba(127, 127, 127, 0.2));
  box-shadow: inset 2px 0 0 var(--data-accent);
}
.data-tree-binding-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.data-tree-binding-arrow { flex: 0 0 auto; color: var(--data-accent); }

/* Diagrams tab (left panel): the flow diagrams TREE — a nested list mirroring the
   Data tree's look (SVG disclosure triangle, indentation, hover/selected states) with
   ＋ (add sub-diagram) / − (delete) icon buttons to the side, in the code accent. */
/* "Generate with AI" — describe a diagram in words, AI builds the flowchart.
   Sits at the top of the Diagrams list; collapsed to a single accent toggle. */
/* No left padding: the ✨ Generate-with-AI toggle is a section header, so its caret must
   line up with the sibling .details-header caret (which sits at the panel's content edge). */
.flow-ai-gen { padding: 4px 10px 8px 0; border-bottom: 1px solid var(--editor-border-color); margin-bottom: 6px; }
.flow-ai-toggle {
  /* Caret + label geometry matches .details-header (caret then title, no gap, no left
     padding) so the two section headers line up exactly. */
  display: flex; align-items: center; gap: 0; width: 100%;
  padding: 4px 0; border: none; background: transparent; cursor: pointer;
  font-size: var(--editor-control-font-size); font-weight: 700; color: var(--code-accent); text-align: left;
}
.flow-ai-caret { width: 14px; display: inline-block; }
.flow-ai-body { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.flow-ai-modes { display: inline-flex; border: 1px solid var(--editor-border-color); border-radius: var(--corner-radius-sm); overflow: hidden; width: fit-content; }
.flow-ai-mode {
  padding: 3px 10px; border: none; background: transparent; cursor: pointer;
  font-size: 12px; font-weight: 600; color: var(--editor-text-color);
}
.flow-ai-mode + .flow-ai-mode { border-left: 1px solid var(--editor-border-color); }
.flow-ai-mode.active { background: var(--code-accent-btn); color: var(--code-accent-fg); }
.flow-ai-input {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 48px;
  padding: 6px 8px; border: 1px solid var(--editor-control-border, var(--editor-border-color));
  border-radius: var(--corner-radius-sm); background: var(--editor-input-bg);
  color: var(--editor-text-color); font: inherit; font-size: 12.5px; line-height: 1.4;
}
.flow-ai-input:focus { outline: none; border-color: var(--code-accent); }
.flow-ai-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.flow-ai-run {
  display: inline-flex; align-items: center;
  padding: 4px 12px; border: 1px solid var(--code-accent); border-radius: var(--corner-radius-sm);
  background: var(--code-accent-btn); color: var(--code-accent-fg);
  font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.flow-ai-run:disabled { opacity: 0.5; cursor: default; }
/* While generating the button is disabled but stays fully opaque so its spinner
   reads clearly (matches the CodeDesigner / GenerateSection AI buttons). */
.flow-ai-run.working:disabled { opacity: 1; }
.flow-ai-status { font-size: 11.5px; color: var(--editor-muted-text-color); flex: 1 1 auto; min-width: 0; }

.flow-tree-ul { list-style: none; margin: 0; padding: 0; }
.flow-tree-li { margin: 0; }
.flow-tree-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: var(--list-row-pad) 6px var(--list-row-pad) 8px;   /* left padding overridden inline per depth */
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
  cursor: pointer;
}
.flow-tree-row:hover { background: color-mix(in srgb, var(--code-accent) 10%, transparent); }
.flow-tree-row.selected {
  background: color-mix(in srgb, var(--code-accent) 16%, transparent);
  box-shadow: inset 2px 0 0 var(--code-accent);
}
.flow-tree-triangle {
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  opacity: var(--editor-icon-muted-opacity, 0.7);
  cursor: pointer;
}
[data-theme="dark"] .flow-tree-triangle { filter: invert(1); }
/* Filled diamond in the code accent — the diagram marker (matches the data badge). */
.flow-tree-badge {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  transform: rotate(45deg);
  background-color: var(--code-accent);
}
.flow-tree-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flow-tree-name.placeholder { color: var(--editor-muted-text-color); font-style: italic; }
/* Kind glyph on a shape (outline) row — muted, fixed width so labels line up. */
.flow-tree-glyph { flex: 0 0 auto; width: 12px; text-align: center; color: var(--editor-muted-text-color); font-size: 11px; }
/* Flow Variables tab: a variable row (name input + type/entity selects + delete). */
.flow-var-row { display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }
.flow-var-name { flex: 1 1 auto; min-width: 40px; box-sizing: border-box; font-size: 12px; padding: 2px 5px; border: var(--editor-control-border); border-radius: var(--corner-radius-sm); }
.flow-var-type, .flow-var-ref { flex: 0 0 auto; max-width: 96px; font-size: 11px; }
.flow-var-add { border: none; background: none; cursor: pointer; color: var(--code-accent); font-size: 14px; line-height: 1; padding: 0; }
.flow-var-del { border: none; background: none; cursor: pointer; color: inherit; opacity: 0.55; font-size: 12px; padding: 0 2px; margin-left: auto; }
.flow-var-del:hover { opacity: 1; color: #c0442e; }
/* Generated-code preview for a flow — a compact read-only monospace block. */
.flow-code-pre {
  margin: 0;
  padding: 6px 8px;
  max-height: 260px;
  overflow: auto;
  font-family: var(--editor-mono-font-family, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11px;
  line-height: 1.45;
  white-space: pre;
  color: var(--editor-text-color);
  background: color-mix(in srgb, var(--code-accent) 7%, transparent);
  border: 1px solid var(--editor-border-color);
  border-radius: 5px;
}
/* The diagram-row kind marker (▭ process / ◇ decision) in the code accent. */
.flow-tree-diagram-glyph { color: var(--code-accent); font-size: 12px; }
/* Drag-drop drop-zone cues for diagram rows: an accent line before/after a sibling,
   a filled highlight when dropping INSIDE (nest as a sub-diagram). */
.flow-tree-row.drop-before { box-shadow: inset 0 2px 0 var(--code-accent); }
.flow-tree-row.drop-after { box-shadow: inset 0 -2px 0 var(--code-accent); }
.flow-tree-row.drop-inside { background: color-mix(in srgb, var(--code-accent) 22%, transparent); outline: 1px dashed var(--code-accent); outline-offset: -1px; }
.flow-tree-row .flow-rename { flex: 1 1 auto; min-width: 0; }
/* A clickable validation issue in the Checks section (one that points at a shape). */
.flow-check.clickable:hover { background: color-mix(in srgb, var(--code-accent) 10%, transparent); }
/* The ＋ / − actions on the Diagrams section header reuse the standard page-list
   +/- icons (page-add-div / page-delete-div + page-list-plus/minus-icon), so they
   get the app's standard icon size, hover highlight, order, and positioning for
   free (the .details-header > [class*="-add-div"]/[class*="-delete-div"] rule).
   The rightmost icon (the ＋) carries the tree panels' standard 10px right-edge
   gap the SAME way .templates-add-div does — a margin on the icon div, NOT
   padding-right on the header: .details-header is width:100% content-box, so
   header padding-right overflows past the visible edge and the icons still sit
   flush. The margin lives inside the flex content box, so it actually shows. */
.flow-diagrams .page-add-div { margin-right: 10px; }
/* Sequences header (now a .details-header like Flow Diagrams): give its add (＋)
   the same 10px right-edge gap so the two peer headers align. */
.seq-header-add { margin-right: 10px; }
/* Group the two ADD icons (＋Process, ＋Decision) as a pair, and set the Delete
   (−) apart from them — otherwise the delete reads as grouped with the first add.
   Tight gap within the add pair; a wider gap separates the delete; the last add
   keeps the 10px right-edge gap (rule above). */
.flow-diagrams .page-add-div:not(:last-child) { margin-right: 4px; }
.flow-diagrams .page-delete-div { margin-right: 11px; }

/* Empty-state message on the blank Diagrams canvas — theme-adaptive colors with
   real contrast (a deep green on the light canvas; the accent green reads fine on
   the dark canvas), and body copy in the standard text colour, not a faint grey. */
.diagrams-empty-title { color: #0e5f3f; }
.diagrams-empty-body { color: var(--editor-text-color); }
[data-theme="dark"] .diagrams-empty-title { color: var(--code-accent); }

/* Prototype tab (left panel): connections + triggers lists. */
.proto-tree { padding: 4px 0; }
.proto-tree-section { margin-bottom: 2px; }
.proto-tree-ul { list-style: none; margin: 0; padding: 0; }
.proto-tree-header {
  padding: 5px 10px 3px 10px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--editor-selected-blue);
}
.proto-tree-row {
  display: flex; align-items: center; gap: 5px;
  padding: var(--list-row-pad) 10px var(--list-row-pad) 12px;
  font-size: var(--editor-control-font-size); color: var(--editor-text-color); cursor: pointer;
}
.proto-tree-row:hover { background: var(--tree-selection-bg, rgba(127, 127, 127, 0.1)); }
.proto-tree-row.selected {
  background: var(--tree-selection-bg, rgba(127, 127, 127, 0.2));
  box-shadow: inset 2px 0 0 var(--editor-selected-blue);
}
.proto-tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* On a trigger row the name GROWS to fill the row, so the count badge lands in a
   fixed column just left of the eye (aligned across rows) instead of floating
   right after the name — its old margin-left:auto fought the eye's own for the
   free space, so the badge's spot depended on the name's length. */
.proto-tree-name-fill { flex: 1 1 auto; min-width: 0; }
.proto-tree-arrow { flex: 0 0 auto; color: var(--editor-selected-blue); }
.proto-tree-count {
  flex: 0 0 auto;
  /* A centred pill: inline-flex + fixed height so the number sits on the row's
     midline (not floating high) and single digits read as a neat circle. */
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 16px; box-sizing: border-box;
  font-size: 11px; line-height: 1; padding: 0 5px; border-radius: 8px;
  color: var(--editor-muted-text-color); background: var(--tree-selection-bg, rgba(127, 127, 127, 0.15));
}
.proto-tree-empty {
  padding: 8px 12px; font-size: var(--editor-control-font-size);
  color: var(--editor-muted-text-color); line-height: 1.4;
}

/* Customize → Theme → Data/Code accent-colour picker row. */
.accent-color-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.accent-color-row input[type="color"] {
  width: 44px; height: 30px; padding: 0; cursor: pointer; background: none;
  border: 1px solid var(--editor-control-border-color); border-radius: 6px;
}
.accent-color-row input[type="text"] {
  width: 150px; padding: 6px 8px; font-size: 13px; color: var(--editor-text-color);
  border: 1px solid var(--editor-control-border-color); border-radius: 6px;
  background: var(--editor-input-bg, #fff);
}
/* Read-only value (e.g. the store a button's connection points to). */
.control-prop-static {
  flex: 1 1 0;
  min-width: 0;
  font-size: var(--editor-control-font-size);
  color: var(--editor-text-color);
}
/* Guidance line (draw-a-connection prompt, row-verb note). */
.control-prop-hint {
  margin: 0 var(--panel-right-gutter) 0 var(--panel-indent);
  font-size: var(--editor-control-font-size);
  line-height: 1.4;
  color: var(--editor-muted-text-color);
}

/* Master name in the library is clickable to open the component for editing. */
.templates-name-edit {
  cursor: pointer;
}
.templates-name-edit:hover {
  text-decoration: underline;
}

/* On-canvas banner shown while editing a component master. Spans the canvas
   region (left/right set inline); sits just below the top toolbar. */
.template-edit-banner {
  position: fixed;
  top: var(--top-toolbar-height);
  z-index: 35;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 12px;
  background: var(--accent-color, #7a5cff);
  color: #ffffff;
  font-size: var(--editor-control-font-size);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

.template-edit-banner-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.template-edit-banner-actions {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

.template-edit-banner-btn {
  font-size: var(--editor-control-font-size);
  padding: 2px 12px;
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 4px;
  background: transparent;
  color: #ffffff;
  cursor: pointer;
}

.template-edit-banner-btn.done {
  background: #ffffff;
  color: var(--accent-color, #7a5cff);
  border-color: #ffffff;
  font-weight: 600;
}

/* Subtle bottom-center hint for in-place editing (pen / line). Spans the canvas
   region (left/right inline); the wrap is click-through so it never blocks the
   canvas. */
.edit-hint-wrap {
  position: fixed;
  bottom: calc(var(--status-bar-height, 0px) + 12px);
  z-index: 35;
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.edit-hint-pill {
  background: rgba(20, 20, 24, 0.85);
  color: #ffffff;
  font-size: var(--editor-control-font-size);
  padding: 4px 12px;
  border-radius: 14px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  user-select: none;
}

.edit-hint-key {
  display: inline-block;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 3px;
  padding: 0 5px;
  margin: 0 1px;
  font-size: 0.9em;
}

/* Master-edit panel: the component name row. */
.component-name-row {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 8px;
  align-items: center;
  margin: 0 12px 0 var(--panel-indent);
}
.component-name-label {
  font-size: var(--editor-control-font-size);
  opacity: 0.7;
}

.component-bind-heading {
  margin: 0 0 0 var(--panel-indent);
  font-size: var(--editor-control-font-size);
  opacity: 0.7;
}

/* Instance panel: a parameter name, its binding value, and (when overridden)
   a reset control. */
.cparam-bind-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  column-gap: 6px;
  align-items: center;
  margin: 0 12px 0 var(--panel-indent);
}
.cparam-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--editor-control-font-size);
}

/* Overridden parameter: accent name + a leading dot, with a reset button. */
.cparam-overridden {
  color: var(--accent-color, #7a5cff);
}
[data-theme="dark"] .cparam-overridden {
  color: #b9a7ff;
}
/* General override indicator for a design-panel control (instance differs
   from master). Clickable: reverts that property to the component default. */
.override-badge {
  display: inline-block;
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent-color, #7a5cff);
  vertical-align: middle;
  margin: 0 4px;
  flex: 0 0 auto;
  cursor: pointer;
}
[data-theme="dark"] .override-badge {
  background: #b9a7ff;
}
.override-badge:hover {
  outline: 2px solid color-mix(in srgb, var(--accent-color, #7a5cff) 40%, transparent);
}

/* Override-report dialog: which section properties differ from the template,
   with Reset / Cancel. Matches the app's modal house style. */
.override-backdrop {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 18, 24, 0.55);
  padding: 24px;
}
.override-modal {
  width: 100%;
  max-width: 480px;
  background: var(--editor-panel-background-color, #fff);
  color: var(--editor-text-color, #1a1a1f);
  border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.15));
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  padding: 22px 24px;
  box-sizing: border-box;
}
.override-title {
  margin: 0 0 4px;
  font-size: 1.1rem;
  font-weight: 700;
}
.override-subtitle {
  margin: 0 0 14px;
  font-size: 0.82rem;
  opacity: 0.7;
}
/* The report is an indented tree mirroring the item hierarchy: each component's
   name, its overridden properties, then its overridden descendants one level
   deeper. No dividers — indentation carries the structure. */
.override-tree {
  list-style: none;
  margin: 0;
  padding: 0;
}
.override-tree-root {
  margin: 0 0 18px;
  padding: 10px 0;
  max-height: 320px;
  overflow-y: auto;
  border-top: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.12));
  border-bottom: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.12));
}
/* Each nested level steps in; the root list itself is flush. */
.override-tree-node .override-tree {
  padding-left: 14px;
}
.override-tree-node {
  margin-top: 6px;
}
.override-tree-root > .override-tree-node:first-child {
  margin-top: 0;
}
.override-node-name {
  font-weight: 700;
  font-size: 0.85rem;
  margin-bottom: 2px;
}
.override-diff-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 0 2px 14px;
  font-size: 0.85rem;
}
.override-diff-label {
  font-weight: 500;
  min-width: 0;
  opacity: 0.85;
}
.override-diff-values {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  text-align: right;
  white-space: nowrap;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.override-diff-current {
  font-weight: 600;
}
.override-arrow {
  opacity: 0.5;
}
.override-diff-master {
  opacity: 0.6;
}
.override-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.override-cancel,
.override-reset {
  padding: 0.45rem 0.85rem;
  border-radius: 8px;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.18));
}
.override-cancel {
  background: transparent;
  color: inherit;
}
.override-reset {
  background: var(--accent-color, #7a5cff);
  border-color: transparent;
  color: #fff;
}
.override-cancel:hover { filter: brightness(0.97); }
.override-reset:hover { filter: brightness(1.06); }

/* Override dot on a design-panel dimension field (W/H/angle on an instance).
   Clickable: reverts that field to the component default. */
.vi-dim-override-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent-color, #7a5cff);
  vertical-align: middle;
  margin-right: 3px;
  flex: 0 0 auto;
  cursor: pointer;
}
.vi-dim-override-dot:hover {
  outline: 2px solid color-mix(in srgb, var(--accent-color, #7a5cff) 40%, transparent);
}
[data-theme="dark"] .vi-dim-override-dot {
  background: #b9a7ff;
}

.cparam-override-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 5px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
}
.cparam-reset {
  border: none;
  background: transparent;
  color: inherit;
  opacity: 0.7;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  padding: 0 4px;
}
.cparam-reset:hover {
  opacity: 1;
}

/* Tree rows: align the disclosure triangle, type icon, badge, and name on
   one centered line. */
.item-tree-row {
  display: flex;
  align-items: center;
  /* Vertical padding is set inline (paddingV in VisualItemTree / CodeFileTree)
     because it also compensates for the 1px hover border to avoid row jitter. */
}

/* Disclosure triangle — override the generic 6px `.item-tree-item img` size
   (which has higher specificity than a single class) so groups get a
   properly sized, clickable triangle. Use a FIXED width (not `auto`) so the
   non-square collapsed/expanded SVGs render at the same 12×12 box the design-
   panel section triangles use, instead of the expanded glyph spreading wider. */
.item-tree-item .tree-triangle-img {
  height: var(--panel-triangle-size);
  width: var(--panel-triangle-size);
  box-sizing: content-box;
  padding: 0 4px 0 0;
  cursor: pointer;
}

/* Per-item type icon (rectangle, text, group, …) in front of each row.
   Opacity matches the toolbar's .tool-icon (0.9) so the dark-mode invert
   reads with the same contrast; 16px so the icons with internal padding
   don't look undersized at tree scale. */
.item-tree-item .tree-type-icon {
  height: 16px;
  width: 16px;
  padding: 0 5px 0 0;
  flex: 0 0 auto;
  opacity: 0.9;
}

/* Text items use a crisp glyph instead of the tiny "T" in text.svg (which
   floats in a large viewBox). Sized to the icon column; inherits the themed
   text color, so it stays high-contrast in both light and dark. */
.item-tree-item .tree-type-glyph {
  width: 16px;
  padding-right: 5px;
  flex: 0 0 auto;
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
  text-align: center;
  opacity: 0.9;
  user-select: none;
}





/* ── UML Sequence diagrams (Sequences tab, Data mode) ─────────────────────── */
.seq-panel { padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }
/* The Generate-with-AI block already carries its own border + padding, so the panel's
   flex gap on top of its margin left too much air both ABOVE it (below the Sequences
   header) and below it (before the list). Drop the margin and keep only the small panel
   gap. */
.seq-panel .flow-ai-gen { margin-bottom: 0; }
.seq-empty { font-size: 12px; color: var(--editor-muted-text-color); padding: 2px; }
.seq-new-btn { align-self: flex-start; padding: 4px 10px; border: 1px solid var(--data-accent); color: var(--data-accent); background: transparent; border-radius: var(--corner-radius-sm); cursor: pointer; font-size: 12.5px; font-weight: 600; }
.seq-picker { display: flex; align-items: center; gap: 6px; }
.seq-picker select { flex: 1 1 auto; min-width: 0; }
.seq-name { width: 100%; box-sizing: border-box; font-size: 13.5px; font-weight: 600; padding: 4px 6px; border: var(--editor-control-border); border-radius: var(--corner-radius-sm); background: var(--editor-input-bg); color: var(--editor-text-color); }
.seq-canvas { overflow: auto; border: 1px solid var(--editor-border-color); border-radius: var(--corner-radius-sm); background: var(--editor-input-bg); max-height: 320px; padding: 4px; }
.seq-svg { display: block; max-width: none; }
.seq-section { display: flex; flex-direction: column; gap: 3px; }
.seq-section-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--code-accent); text-transform: uppercase; letter-spacing: .04em; }
/* Right-aligned action cluster in a section header — holds the delete (−) then add (＋)
   icon-buttons in that order, so the minus always sits LEFT of the plus. */
.seq-head-actions { margin-left: auto; display: flex; align-items: center; }
.seq-row { display: flex; align-items: center; gap: 4px; }
.seq-row select { flex: 0 0 auto; max-width: 92px; font-size: 11px; }
.seq-inline-name { flex: 1 1 auto; min-width: 40px; box-sizing: border-box; font-size: 12px; padding: 2px 5px; border: var(--editor-control-border); border-radius: var(--corner-radius-sm); background: var(--editor-input-bg); color: var(--editor-text-color); }
.seq-arrow { flex: 0 0 auto; color: var(--editor-muted-text-color); font-size: 12px; }
.seq-mini { flex: 0 0 auto; width: 18px; height: 18px; padding: 0; border: 1px solid var(--editor-border-color); background: transparent; border-radius: 4px; cursor: pointer; font-size: 10px; color: var(--editor-text-color); line-height: 1; }
.seq-mini:disabled { opacity: 0.35; cursor: default; }
.seq-hint { font-size: 11px; color: var(--editor-muted-text-color); }

/* Sequence inspector — the RIGHT-panel section (a standard .flow-node-section, so it
   needs its own padding + column layout since that class carries none). */
.seq-inspector { display: flex; flex-direction: column; gap: 8px; padding: 12px 12px 14px; }
/* Lifeline rows stay on ONE line (name + kind + −); cap the kind select so the row
   fits the narrow panel without wrapping. */
.seq-inspector .seq-row select { max-width: 84px; }

/* Messages are a compact master-detail: a one-line-per-message LIST (summary + drag
   handle + delete) and a detail editor below for the SELECTED message. */
.seq-msg-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.seq-msg-row { display: flex; align-items: center; gap: 6px; padding: 3px 6px 3px 10px; cursor: pointer; font-size: 12px; color: var(--editor-text-color); border-radius: 3px; }
.seq-msg-row:hover { background: color-mix(in srgb, var(--code-accent) 10%, transparent); }
.seq-msg-row.selected { background: color-mix(in srgb, var(--code-accent) 16%, transparent); box-shadow: inset 2px 0 0 var(--code-accent); }
.seq-msg-idx { flex: 0 0 auto; color: var(--editor-muted-text-color); font-variant-numeric: tabular-nums; }
.seq-msg-summary { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seq-ll-kind { color: var(--editor-muted-text-color); font-size: 11px; }
.seq-msg-detail { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; padding: 8px; border: 1px solid var(--editor-border-color); border-radius: var(--corner-radius-sm); background: color-mix(in srgb, var(--code-accent) 5%, transparent); }
.seq-detail-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.seq-detail-label { flex: 0 0 auto; font-size: 11px; color: var(--editor-muted-text-color); min-width: 28px; }
/* A second label in a detail row (e.g. "To" after From's control) starts a new
   field-group — give it extra left space so it doesn't read as part of the one before. */
.seq-detail-row .seq-detail-label ~ .seq-detail-label { margin-left: 12px; }
/* Detail-row selects fill to the panel's right edge (like the label/name inputs), so
   a lone From/To/Kind control hugs the right the same as everything else. */
.seq-detail-row select { flex: 1 1 60px; min-width: 0; }
.seq-detail-row .seq-inline-name { flex: 1 1 auto; }
/* …except a select that SHARES its row with a guard input (an alt operand's "at"
   picker) stays compact so it doesn't crowd the guard. */
.seq-detail-row .seq-op-select { flex: 0 1 auto; max-width: 96px; }
/* Line the row action icons up in one right-hand column: the shared .page-delete-div
   carries a 5px right margin that pushed the − left of the section-head ＋; zero it
   (and the add) inside the inspector so − and ＋ share the same right edge — even a
   lone icon. */
.seq-inspector .page-delete-div,
.seq-inspector .page-add-div { margin: 0; }
/* Drag-to-reorder lifeline rows. */
.seq-drag-row { cursor: default; }
.seq-drag-handle { flex: 0 0 auto; width: 12px; text-align: center; color: var(--editor-muted-text-color); cursor: grab; font-size: 12px; user-select: none; }
.seq-drag-row.drop-before { box-shadow: inset 0 2px 0 var(--code-accent); }
.seq-drag-row.drop-after { box-shadow: inset 0 -2px 0 var(--code-accent); }

/* ── Pen edit mode: unified Appearance master/detail list (reuses .shadow-tree) ── */
/* The − / + ride the standard header slot (order 2, pushed right by .details-header::after);
   an 8px right gutter keeps them off the panel edge (matching the pen sub-mode buttons).
   box-sizing: border-box is required — .details-header is width:100%, so a content-box
   padding-right would push 100%+8px wide (the padding hanging off-screen) instead of
   insetting the buttons. */
.pen-appearance .details-header {
  box-sizing: border-box;
  padding-right: 8px;
}
/* The ring rows line up with the "Rings" header title (one --panel-indent from the left):
   the shared .shadow-tree adds another level's worth on top, so pull the base back by the
   per-row level-0 pad (treeRowPad(0) = 10px) to cancel it. Deeper levels still nest. */
.pen-appearance-tree {
  margin-left: calc(var(--panel-indent) - 10px);
}
/* A ring / All-rings group heading — bold, standard selection when picked. */
.pen-appearance-group .shadow-tree-label { font-weight: 700; }
/* No separation line between the list and the detail editor; hide the reused
   section's own header/separator (the tree row is the header now). */
.pen-appearance-detail {
  margin-top: var(--details-row-pad);
}
.pen-appearance-detail .details-div-group {
  border: none;
}
.pen-appearance-detail .details-header {
  display: none;
}

