/* ── dist/main.css ── */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:"Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-serif:"Georgia", "Times New Roman", Times, serif;--font-mono:"JetBrains Mono", "Fira Code", "SF Mono", Monaco, "Inconsolata", "Roboto Mono", monospace;--color-neutral-200:oklch(92.2% 0 0);--color-neutral-800:oklch(26.9% 0 0);--color-white:#fff;--spacing:.25rem;--breakpoint-sm:40rem;--breakpoint-md:48rem;--breakpoint-lg:64rem;--breakpoint-xl:80rem;--breakpoint-2xl:96rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-lg:1.125rem;--text-xl:1.25rem;--text-2xl:1.5rem;--text-3xl:1.875rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-xs:2px;--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:24px;--shadow-xs:0 1px 2px 0 #0000000a;--shadow-sm:0 1px 3px 0 #0000000f;--shadow-md:0 4px 6px -1px #00000014, 0 2px 4px -2px #0000000f;--shadow-lg:0 10px 15px -3px #00000014, 0 4px 6px -4px #0000000a;--shadow-xl:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000000f;--shadow-2xl:0 25px 50px -12px #0003;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-primary:#6366f1;--color-secondary:#10b981;--color-accent:#8b5cf6;--color-success:#10b981;--color-success-dark:#059669;--color-warning:#f59e0b;--color-warning-dark:#d97706;--color-danger:#ef4444;--color-info:#3b82f6;--color-dark:#0f172a;--color-surface:var(--bg-primary);--font-size-xs:.75rem;--font-size-sm:.8125rem;--font-size-base:.875rem;--font-size-md:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--spacing-xs:.25rem;--spacing-sm:.5rem;--spacing-md:1rem;--spacing-lg:1.5rem;--spacing-xl:2rem;--spacing-2xl:3rem;--radius-full:9999px;--header-height:48px;--sidebar-width:240px;--footer-height:48px;--z-sticky:1100;--z-fixed:1150;--z-widget:1200;--z-sidebar-overlay:1440;--z-sidebar:1450;--z-stream-panel:1550;--z-floating-window:1650;--z-modal-backdrop:2500;--z-modal:2600;--z-dropdown:3200;--z-popover:3300;--z-tooltip:3400;--z-toast:3900;--z-loading:3950;--transition-fast:.15s cubic-bezier(.4, 0, .2, 1);--transition-base:.2s cubic-bezier(.4, 0, .2, 1);--transition-slow:.3s cubic-bezier(.4, 0, .2, 1);--btn-height-xs:28px;--btn-height-sm:36px;--btn-height-md:40px;--btn-height-lg:48px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{color-scheme:light;--bg-primary:#faf9f6;--bg-secondary:#f3f2ee;--bg-tertiary:#eceae4;--bg-elevated:#fff;--bg-hover:#eceae4;--bg-muted:#f3f2ee;--bg-overlay:#0006;--bg-code:#1e1e2e;--text-primary:#1a1a1a;--text-secondary:#5f5e5b;--text-muted:#78746e;--text-light:#a8a6a1;--text-inverse:#fff;--text-code:#e2e8f0;--border-color:#00000014;--border-strong:#00000026;--border-light:#0000000a;--accent-color:#c15f3c;--accent-hover:#a8502f;--accent-subtle:#f5e6df;--status-success:#2e7d5b;--status-success-bg:#e8f5ec;--status-warning:#b8860b;--status-warning-bg:#fef7e0;--status-danger:#c0392b;--status-danger-bg:#fdeceb;--status-info:#2b6cb0;--status-info-bg:#e6f0fa;--shadow-color:0 0 0;--primary:#4f46e5;--primary-dark:#4338ca;--primary-light:#818cf8;--primary-lighter:#a5b4fc;--primary-lightest:#e0e7ff;--secondary:#10b981;--secondary-dark:#059669;--accent:#7c3aed;--accent-light:#f3e8ff;--success:#10b981;--success-dark:#059669;--success-light:#34d399;--success-lighter:#6ee7b7;--success-lightest:#d1fae5;--warning:#f59e0b;--warning-dark:#d97706;--warning-light:#fbbf24;--warning-lighter:#fcd34d;--warning-lightest:#fef3c7;--danger:#ef4444;--danger-dark:#dc2626;--danger-light:#f87171;--danger-lighter:#fca5a5;--danger-lightest:#fee2e2;--info:#3b82f6;--info-dark:#2563eb;--info-light:#60a5fa;--info-lighter:#93c5fd;--info-lightest:#dbeafe;--dark:#0f172a;--gray-900:#111827;--gray-800:#1f2937;--gray-700:#374151;--gray-600:#4b5563;--gray-500:#6b7280;--gray-400:#9ca3af;--gray-300:#d1d5db;--gray-200:#e5e7eb;--gray-100:#f3f4f6;--gray-50:#f9fafb;--white:#fff;--bg-base:var(--bg-primary);--bg-card:var(--bg-elevated);--border:var(--border-color);--border-dark:var(--border-strong);--art-street:#e74c3c;--art-music:#3498db;--art-visual:#9b59b6;--art-design:#2ecc71;--art-event:#f39c12;--art-other:#95a5a6;--shadow-xs:0 1px 2px 0 #0000000d;--shadow-sm:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--shadow:0 1px 3px 0 #0000001a, 0 1px 2px 0 #0000000f;--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--shadow-lg:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--shadow-xl:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--shadow-2xl:0 25px 50px -12px #00000040;--shadow-inner:inset 0 2px 4px 0 #0000000d;--header-height:48px;--footer-height:48px;--sidebar-width:240px;--sidebar-left-width:240px;--sidebar-right-width:240px;--sidebar-collapsed:56px;--radius-xs:2px;--radius-sm:4px;--radius:6px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:24px;--radius-full:9999px;--spacing-xs:.25rem;--spacing-sm:.5rem;--spacing-md:1rem;--spacing-lg:1.5rem;--spacing-xl:2rem;--spacing-2xl:3rem;--spacing-3xl:4rem;--font-sans:"Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:"JetBrains Mono", "Fira Code", "SF Mono", Monaco, "Inconsolata", "Roboto Mono", monospace;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-size-xs:.75rem;--font-size-sm:.8125rem;--font-size-base:.875rem;--font-size-md:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--transition:all .2s cubic-bezier(.4, 0, .2, 1);--transition-fast:all .15s cubic-bezier(.4, 0, .2, 1);--transition-slow:all .3s cubic-bezier(.4, 0, .2, 1);--z-sticky:1100;--z-fixed:1150;--z-widget:1200;--z-sidebar-overlay:1440;--z-sidebar:1450;--z-stream-panel:1550;--z-floating-window:1650;--z-modal-backdrop:2500;--z-modal:2600;--z-dropdown:3200;--z-popover:3300;--z-tooltip:3400;--z-toast:3900;--z-loading:3950;--z-debug-panel:2800;--breakpoint-sm:640px;--breakpoint-md:768px;--breakpoint-lg:1024px;--breakpoint-xl:1280px;--breakpoint-2xl:1536px;--btn-height-xs:28px;--btn-height-sm:36px;--btn-height-md:44px;--btn-height-lg:52px;--btn-padding-xs:.375rem .75rem;--btn-padding-sm:.5rem 1rem;--btn-padding-md:.75rem 1.25rem;--btn-padding-lg:1rem 1.5rem;--btn-font-xs:.75rem;--btn-font-sm:.8125rem;--btn-font-md:.875rem;--btn-font-lg:1rem}:root[data-theme=dark]{color-scheme:dark;--bg-primary:#1a1a1a;--bg-secondary:#242422;--bg-tertiary:#2e2e2c;--bg-elevated:#333331;--bg-hover:#3a3a38;--bg-muted:#2e2e2c;--bg-overlay:#0009;--bg-code:#0f172a;--text-primary:#e8e6e1;--text-secondary:#a8a6a1;--text-muted:#6b6a66;--text-light:#4a4a47;--text-inverse:#1a1a1a;--text-code:#f1f5f9;--border-color:#ffffff14;--border-strong:#ffffff26;--accent-color:#da7756;--accent-hover:#e8906e;--accent-subtle:#3a2a22;--status-success:#34d399;--status-success-bg:#1a2e25;--status-warning:#fbbf24;--status-warning-bg:#2e2815;--status-danger:#f87171;--status-danger-bg:#2e1a1a;--status-info:#60a5fa;--status-info-bg:#1a2535;--shadow-color:0 0 0;--bg-base:var(--bg-primary);--bg-card:var(--bg-elevated);--border:var(--border-color);--border-dark:var(--border-strong);--border-light:#ffffff0a;--gray-50:#2e2e2c;--gray-100:#333331;--gray-200:#3a3a38;--gray-300:#4a4a47;--gray-400:#6b6a66;--gray-500:#9b9a97;--gray-600:#a8a6a1;--gray-700:#c4c3bf;--gray-800:#e0dfdb;--gray-900:#e8e6e1;--dark:#e8e6e1;--white:#1a1a1a;--shadow-xs:0 1px 2px 0 #00000026;--shadow-sm:0 1px 3px 0 #0003, 0 1px 2px -1px #00000026;--shadow:0 1px 3px 0 #0003, 0 1px 2px 0 #00000026;--shadow-md:0 4px 6px -1px #00000040, 0 2px 4px -2px #0003;--shadow-lg:0 10px 15px -3px #0000004d, 0 4px 6px -4px #0003;--shadow-xl:0 20px 25px -5px #00000059, 0 8px 10px -6px #00000040;--shadow-2xl:0 25px 50px -12px #00000080;--shadow-inner:inset 0 2px 4px 0 #00000026}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--bg-primary:#1a1a1a;--bg-secondary:#242422;--bg-tertiary:#2e2e2c;--bg-elevated:#333331;--bg-hover:#3a3a38;--bg-muted:#2e2e2c;--bg-overlay:#0009;--bg-code:#0f172a;--text-primary:#e8e6e1;--text-secondary:#a8a6a1;--text-muted:#6b6a66;--text-light:#4a4a47;--text-inverse:#1a1a1a;--text-code:#f1f5f9;--border-color:#ffffff14;--border-strong:#ffffff26;--border-light:#ffffff0a;--accent-color:#da7756;--accent-hover:#e8906e;--accent-subtle:#3a2a22;--status-success:#34d399;--status-success-bg:#1a2e25;--status-warning:#fbbf24;--status-warning-bg:#2e2815;--status-danger:#f87171;--status-danger-bg:#2e1a1a;--status-info:#60a5fa;--status-info-bg:#1a2535;--bg-base:#1a1a1a;--bg-card:#333331;--border:#ffffff14;--border-dark:#ffffff26;--gray-50:#2e2e2c;--gray-100:#333331;--gray-200:#3a3a38;--gray-300:#4a4a47;--gray-400:#6b6a66;--gray-500:#9b9a97;--gray-600:#a8a6a1;--gray-700:#c4c3bf;--gray-800:#e0dfdb;--gray-900:#e8e6e1;--dark:#e8e6e1;--white:#1a1a1a;--shadow-xs:0 1px 2px 0 #00000026;--shadow-sm:0 1px 3px 0 #0003, 0 1px 2px -1px #00000026;--shadow:0 1px 3px 0 #0003, 0 1px 2px 0 #00000026;--shadow-md:0 4px 6px -1px #00000040, 0 2px 4px -2px #0003;--shadow-lg:0 10px 15px -3px #0000004d, 0 4px 6px -4px #0003;--shadow-xl:0 20px 25px -5px #00000059, 0 8px 10px -6px #00000040;--shadow-2xl:0 25px 50px -12px #00000080;--shadow-inner:inset 0 2px 4px 0 #00000026}}@media(prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}html{font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;font-size:16px}body{background-color:var(--bg-primary);color:var(--text-primary);line-height:1.5}body,body *{transition:background-color .2s,border-color .2s,color .15s,box-shadow .2s}canvas,video,iframe,svg,img,.no-transition,.no-transition *,.leaflet-tile-pane *,.maplibregl-map *,[class*=chart],[class*=vis-],.gridstack-item-content{transition:none!important}h1,h2,h3,h4,h5,h6{color:var(--text-primary);letter-spacing:-.01em;font-weight:600;line-height:1.3}a{color:var(--primary);text-decoration:none;transition:color .15s}a:hover{color:var(--primary-dark)}:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:2px}[role=button]{cursor:pointer}[role=button]:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:var(--radius-sm,4px);box-shadow:0 0 0 4px var(--primary)}@supports (color:color-mix(in lab,red,red)){[role=button]:focus-visible{box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 15%,transparent)}}*{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}pre,code{font-family:var(--font-mono)}pre{background:var(--bg-code);color:var(--text-code);border-radius:var(--radius-md);padding:.75rem 1rem;font-size:.8125rem;line-height:1.6;overflow-x:auto}code{background:var(--bg-tertiary);color:var(--text-primary);border-radius:var(--radius-sm);padding:.125rem .375rem;font-size:.875em}pre code{color:inherit;font-size:inherit;background:0 0;border-radius:0;padding:0}input,select,textarea{color:var(--text-primary);background-color:var(--bg-elevated);border:1px solid var(--border-color);border-radius:var(--radius-md,8px);font-family:inherit;font-size:.875rem}select:not([class]),input:not([class]):not([type=hidden]):not([type=checkbox]):not([type=radio]){min-height:36px;padding:.5rem .75rem}textarea:not([class]){resize:vertical;min-height:80px;padding:.5rem .75rem}input::placeholder,textarea::placeholder{color:var(--text-muted)}input:focus,select:focus,textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px var(--primary)}@supports (color:color-mix(in lab,red,red)){input:focus,select:focus,textarea:focus{box-shadow:0 0 0 2px color-mix(in srgb,var(--primary) 15%,transparent)}}input[type=range],input[type=file],input[type=color],input[type=checkbox],input[type=radio]{background-color:initial;border-color:initial;border-radius:initial;box-shadow:initial;min-height:initial;padding:initial}::selection{background:var(--primary)}@supports (color:color-mix(in lab,red,red)){::selection{background:color-mix(in srgb,var(--primary) 25%,transparent)}}::selection{color:var(--text-primary)}}@layer components{.card-pro{background:var(--bg-elevated);border:1px solid var(--border-color);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);padding:1.25rem;transition:box-shadow .2s,border-color .2s}.card-pro:hover{box-shadow:var(--shadow-md);border-color:var(--border-strong)}.card-pro .card-pro-title{color:var(--text-primary);margin-bottom:.5rem;font-size:.875rem;font-weight:600}.card-pro .card-pro-subtitle{color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.75rem;font-size:.75rem}.btn-pro{border-radius:var(--radius-md);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;border:1px solid #0000;justify-content:center;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.8125rem;font-weight:500;line-height:1.5;transition:all .15s;display:inline-flex}.btn-pro:disabled{opacity:.5;cursor:not-allowed}.btn-pro-primary{background:var(--primary);color:var(--text-inverse)}.btn-pro-primary:hover:not(:disabled){background:var(--primary-dark);box-shadow:var(--shadow-sm)}.btn-pro-secondary{background:var(--bg-elevated);color:var(--text-primary);border-color:var(--border-color)}.btn-pro-secondary:hover:not(:disabled){background:var(--bg-hover);border-color:var(--border-strong)}.btn-pro-ghost{color:var(--text-secondary);background:0 0}.btn-pro-ghost:hover:not(:disabled){background:var(--bg-hover);color:var(--text-primary)}.btn-pro-danger{background:var(--danger);color:var(--text-inverse)}.btn-pro-danger:hover:not(:disabled){background:var(--danger-dark)}.input-pro{width:100%;min-height:var(--btn-height-md,44px);border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-elevated);color:var(--text-primary);padding:.625rem .875rem;font-size:.875rem;line-height:1.5;transition:border-color .15s,box-shadow .15s;display:block}.input-pro::placeholder{color:var(--text-muted)}.input-pro:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary)}@supports (color:color-mix(in lab,red,red)){.input-pro:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 15%,transparent)}}.input-pro:disabled,.input-pro[readonly]{opacity:.6;cursor:not-allowed;background:var(--bg-secondary)}textarea.input-pro{resize:vertical;min-height:100px}select.input-pro{cursor:pointer}.input-pro-label{color:var(--text-secondary);margin-bottom:.375rem;font-size:.8125rem;font-weight:500;display:block}.badge-pro{border-radius:var(--radius-full);text-transform:uppercase;letter-spacing:.04em;align-items:center;gap:.25rem;padding:.125rem .5rem;font-size:.75rem;font-weight:600;display:inline-flex}.badge-pro-success{background:var(--success)}@supports (color:color-mix(in lab,red,red)){.badge-pro-success{background:color-mix(in srgb,var(--success) 15%,var(--bg-primary))}}.badge-pro-success{color:var(--success)}.badge-pro-warning{background:var(--warning)}@supports (color:color-mix(in lab,red,red)){.badge-pro-warning{background:color-mix(in srgb,var(--warning) 15%,var(--bg-primary))}}.badge-pro-warning{color:var(--warning)}.badge-pro-danger{background:var(--danger)}@supports (color:color-mix(in lab,red,red)){.badge-pro-danger{background:color-mix(in srgb,var(--danger) 15%,var(--bg-primary))}}.badge-pro-danger{color:var(--danger)}.badge-pro-info{background:var(--info)}@supports (color:color-mix(in lab,red,red)){.badge-pro-info{background:color-mix(in srgb,var(--info) 15%,var(--bg-primary))}}.badge-pro-info{color:var(--info)}.badge-pro-neutral{background:var(--bg-tertiary);color:var(--text-secondary)}.divider{border:none;border-top:1px solid var(--border-color);margin:1rem 0}.empty-state-pro{color:var(--text-muted);text-align:center;flex-direction:column;justify-content:center;align-items:center;padding:3rem 1.5rem;display:flex}.empty-state-pro-icon{opacity:.5;margin-bottom:.75rem;font-size:2rem}.empty-state-pro-title{color:var(--text-secondary);margin-bottom:.25rem;font-size:.9375rem;font-weight:600}.empty-state-pro-description{max-width:280px;font-size:.8125rem}.table-pro{border-collapse:collapse;width:100%}.table-pro th{text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);border-bottom:1px solid var(--border-color);text-align:left;padding:.625rem .75rem;font-size:.75rem;font-weight:600}.table-pro td{color:var(--text-primary);border-bottom:1px solid var(--border-light);padding:.625rem .75rem;font-size:.8125rem}.table-pro tbody tr:hover{background:var(--bg-hover)}:root[data-theme=dark] .form-control,:root[data-theme=dark] .form-select{background-color:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-color)}:root[data-theme=dark] .form-control:focus,:root[data-theme=dark] .form-select:focus{background-color:var(--bg-secondary);color:var(--text-primary);border-color:var(--primary);box-shadow:0 0 0 3px var(--primary)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .form-control:focus,:root[data-theme=dark] .form-select:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 15%,transparent)}}:root[data-theme=dark] .form-control::placeholder{color:var(--text-muted)}:root[data-theme=dark] .form-label{color:var(--text-secondary)}:root[data-theme=dark] .form-text{color:var(--text-muted)}:root[data-theme=dark] .form-check-input{background-color:var(--bg-tertiary);border-color:var(--border-strong)}:root[data-theme=dark] .form-check-input:checked{background-color:var(--primary);border-color:var(--primary)}:root[data-theme=dark] .card{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .card-header{background-color:var(--bg-secondary);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .card-body{color:var(--text-primary)}:root[data-theme=dark] .card-footer{background-color:var(--bg-secondary);border-color:var(--border-color)}:root[data-theme=dark] .table{color:var(--text-primary);border-color:var(--border-color)}:root[data-theme=dark] .table>thead>tr>th{background-color:var(--bg-secondary);border-color:var(--border-color);color:var(--text-secondary)}:root[data-theme=dark] .table>tbody>tr>td{border-color:var(--border-color)}:root[data-theme=dark] .table-striped>tbody>tr:nth-of-type(odd){background-color:var(--bg-secondary);color:var(--text-primary)}:root[data-theme=dark] .table-hover>tbody>tr:hover{background-color:var(--bg-hover);color:var(--text-primary)}:root[data-theme=dark] .modal-content{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .modal-header,:root[data-theme=dark] .modal-footer{border-color:var(--border-color)}:root[data-theme=dark] .dropdown-menu{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .dropdown-item{color:var(--text-primary)}:root[data-theme=dark] .dropdown-item:hover,:root[data-theme=dark] .dropdown-item:focus{background-color:var(--bg-hover);color:var(--text-primary)}:root[data-theme=dark] .dropdown-divider,:root[data-theme=dark] .nav-tabs{border-color:var(--border-color)}:root[data-theme=dark] .nav-tabs .nav-link{color:var(--text-secondary)}:root[data-theme=dark] .nav-tabs .nav-link.active{background-color:var(--bg-elevated);border-color:var(--border-color) var(--border-color) var(--bg-elevated);color:var(--text-primary)}:root[data-theme=dark] .alert{color:var(--text-primary)}:root[data-theme=dark] .alert-info{background-color:var(--info)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-info{background-color:color-mix(in srgb,var(--info) 15%,var(--bg-primary))}}:root[data-theme=dark] .alert-info{border-color:var(--info)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-info{border-color:color-mix(in srgb,var(--info) 30%,transparent)}}:root[data-theme=dark] .alert-info{color:var(--info)}:root[data-theme=dark] .alert-warning{background-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-warning{background-color:color-mix(in srgb,var(--warning) 15%,var(--bg-primary))}}:root[data-theme=dark] .alert-warning{border-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-warning{border-color:color-mix(in srgb,var(--warning) 30%,transparent)}}:root[data-theme=dark] .alert-warning{color:var(--warning)}:root[data-theme=dark] .alert-danger{background-color:var(--danger)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-danger{background-color:color-mix(in srgb,var(--danger) 15%,var(--bg-primary))}}:root[data-theme=dark] .alert-danger{border-color:var(--danger)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-danger{border-color:color-mix(in srgb,var(--danger) 30%,transparent)}}:root[data-theme=dark] .alert-danger{color:var(--danger)}:root[data-theme=dark] .alert-success{background-color:var(--success)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-success{background-color:color-mix(in srgb,var(--success) 15%,var(--bg-primary))}}:root[data-theme=dark] .alert-success{border-color:var(--success)}@supports (color:color-mix(in lab,red,red)){:root[data-theme=dark] .alert-success{border-color:color-mix(in srgb,var(--success) 30%,transparent)}}:root[data-theme=dark] .alert-success{color:var(--success)}:root[data-theme=dark] .alert-light{background-color:var(--bg-secondary);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .list-group-item{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root[data-theme=dark] .badge.bg-light{background-color:var(--bg-tertiary)!important;color:var(--text-primary)!important}:root[data-theme=dark] .text-dark{color:var(--text-primary)!important}:root[data-theme=dark] .text-muted{color:var(--text-muted)!important}:root[data-theme=dark] .bg-light{background-color:var(--bg-secondary)!important}:root[data-theme=dark] .bg-white{background-color:var(--bg-elevated)!important}:root[data-theme=dark] .border,:root[data-theme=dark] .border-bottom,:root[data-theme=dark] .border-top{border-color:var(--border-color)!important}:root[data-theme=dark] .accordion-button{background-color:var(--bg-secondary);color:var(--text-primary)}:root[data-theme=dark] .accordion-body{background-color:var(--bg-elevated)}:root[data-theme=dark] .breadcrumb{background-color:#0000}:root[data-theme=dark] .breadcrumb-item+.breadcrumb-item:before,:root[data-theme=dark] .breadcrumb-item.active{color:var(--text-muted)}:root[data-theme=dark] .offcanvas{background-color:var(--bg-elevated);color:var(--text-primary)}:root[data-theme=dark] .btn-close{filter:invert()grayscale()brightness(200%)}:root[data-theme=dark] hr{border-color:var(--border-color);opacity:1}@media(prefers-color-scheme:dark){:root:not([data-theme=light]) .form-control,:root:not([data-theme=light]) .form-select{background-color:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-color)}:root:not([data-theme=light]) .form-control:focus,:root:not([data-theme=light]) .form-select:focus{background-color:var(--bg-secondary);color:var(--text-primary);border-color:var(--primary);box-shadow:0 0 0 3px var(--primary)}@supports (color:color-mix(in lab,red,red)){:root:not([data-theme=light]) .form-control:focus,:root:not([data-theme=light]) .form-select:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 15%,transparent)}}:root:not([data-theme=light]) .card{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root:not([data-theme=light]) .table{color:var(--text-primary);border-color:var(--border-color)}:root:not([data-theme=light]) .modal-content{background-color:var(--bg-elevated);border-color:var(--border-color);color:var(--text-primary)}:root:not([data-theme=light]) .dropdown-menu{background-color:var(--bg-elevated);border-color:var(--border-color)}:root:not([data-theme=light]) .dropdown-item{color:var(--text-primary)}:root:not([data-theme=light]) .dropdown-item:hover{background-color:var(--bg-hover)}:root:not([data-theme=light]) .alert-info{background-color:var(--info)}@supports (color:color-mix(in lab,red,red)){:root:not([data-theme=light]) .alert-info{background-color:color-mix(in srgb,var(--info) 15%,var(--bg-primary))}}:root:not([data-theme=light]) .alert-info{color:var(--info)}:root:not([data-theme=light]) .alert-warning{background-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){:root:not([data-theme=light]) .alert-warning{background-color:color-mix(in srgb,var(--warning) 15%,var(--bg-primary))}}:root:not([data-theme=light]) .alert-warning{color:var(--warning)}:root:not([data-theme=light]) .alert-danger{background-color:var(--danger)}@supports (color:color-mix(in lab,red,red)){:root:not([data-theme=light]) .alert-danger{background-color:color-mix(in srgb,var(--danger) 15%,var(--bg-primary))}}:root:not([data-theme=light]) .alert-danger{color:var(--danger)}:root:not([data-theme=light]) .alert-success{background-color:var(--success)}@supports (color:color-mix(in lab,red,red)){:root:not([data-theme=light]) .alert-success{background-color:color-mix(in srgb,var(--success) 15%,var(--bg-primary))}}:root:not([data-theme=light]) .alert-success{color:var(--success)}:root:not([data-theme=light]) .btn-close{filter:invert()grayscale()brightness(200%)}:root:not([data-theme=light]) hr{border-color:var(--border-color);opacity:1}}.skeleton{background:linear-gradient(90deg,var(--bg-tertiary) 25%,var(--bg-hover) 50%,var(--bg-tertiary) 75%);border-radius:var(--radius-sm);background-size:200% 100%;animation:1.5s ease-in-out infinite skeleton-pulse}@keyframes skeleton-pulse{0%{background-position:200% 0}to{background-position:-200% 0}}}@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.visible\!{visibility:visible!important}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.\!start{inset-inline-start:var(--spacing)!important}.start{inset-inline-start:var(--spacing)}.start\!{inset-inline-start:var(--spacing)!important}.start-100{inset-inline-start:calc(var(--spacing) * 100)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-1{top:calc(var(--spacing) * 1)}.top-3{top:calc(var(--spacing) * 3)}.top-5{top:calc(var(--spacing) * 5)}.top-6{top:calc(var(--spacing) * 6)}.top-10{top:calc(var(--spacing) * 10)}.top-20{top:calc(var(--spacing) * 20)}.top-25{top:calc(var(--spacing) * 25)}.top-1000{top:calc(var(--spacing) * 1000)}.isolate{isolation:isolate}.col-4{grid-column:4}.col-6{grid-column:6}.col-12{grid-column:12}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.m-2{margin:calc(var(--spacing) * 2)}.m-3{margin:calc(var(--spacing) * 3)}.my-3{margin-block:calc(var(--spacing) * 3)}.ms-1{margin-inline-start:calc(var(--spacing) * 1)}.ms-2{margin-inline-start:calc(var(--spacing) * 2)}.ms-4{margin-inline-start:calc(var(--spacing) * 4)}.ms-auto{margin-inline-start:auto}.me-1{margin-inline-end:calc(var(--spacing) * 1)}.me-2{margin-inline-end:calc(var(--spacing) * 2)}.me-3{margin-inline-end:calc(var(--spacing) * 3)}.me-auto{margin-inline-end:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-lg{margin-top:var(--spacing-lg)}.mt-md{margin-top:var(--spacing-md)}.mt-sm{margin-top:var(--spacing-sm)}.mt-xs{margin-top:var(--spacing-xs)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-0{margin-bottom:calc(var(--spacing) * 0)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-lg{margin-bottom:var(--spacing-lg)}.mb-md{margin-bottom:var(--spacing-md)}.mb-sm{margin-bottom:var(--spacing-sm)}.ml-2{margin-left:calc(var(--spacing) * 2)}.content-grid{grid-template-columns:minmax(0,960px);justify-content:center;padding-inline:1rem;display:grid}.\!hidden{display:none!important}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.grid\!{display:grid!important}.hidden{display:none}.hidden\!{display:none!important}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.inline-table{display:inline-table}.list-item{display:list-item}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-column{display:table-column}.table-column-group{display:table-column-group}.table-footer-group{display:table-footer-group}.table-header-group{display:table-header-group}.table-row{display:table-row}.table-row-group{display:table-row-group}.h-100{height:calc(var(--spacing) * 100)}.h-full{height:100%}.w-100{width:calc(var(--spacing) * 100)}.w-auto{width:auto}.flex-shrink,.shrink{flex-shrink:1}.flex-grow,.flex-grow-1,.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.resize{resize:both}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-dark{border-color:var(--color-dark)}.border-info{border-color:var(--color-info)}.border-primary{border-color:var(--color-primary)}.border-secondary{border-color:var(--color-secondary)}.border-success{border-color:var(--color-success)}.border-warning{border-color:var(--color-warning)}.bg-accent{background-color:var(--color-accent)}.bg-danger{background-color:var(--color-danger)}.bg-dark{background-color:var(--color-dark)}.bg-info{background-color:var(--color-info)}.bg-neutral-200{background-color:var(--color-neutral-200)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.bg-success{background-color:var(--color-success)}.bg-warning{background-color:var(--color-warning)}.bg-white{background-color:var(--color-white)}.p-0{padding:calc(var(--spacing) * 0)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.ps-3{padding-inline-start:calc(var(--spacing) * 3)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-end{text-align:end}.text-justify{text-align:justify}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-nowrap{text-wrap:nowrap}.text-wrap{text-wrap:wrap}.break-all{word-break:break-all}.text-danger{color:var(--color-danger)}.text-dark{color:var(--color-dark)}.text-info{color:var(--color-info)}.text-primary{color:var(--color-primary)}.text-secondary{color:var(--color-secondary)}.text-success{color:var(--color-success)}.text-warning{color:var(--color-warning)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.overline{text-decoration-line:overline}.overline\!{text-decoration-line:overline!important}.underline{text-decoration-line:underline}.underline\!{text-decoration-line:underline!important}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow\!{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)!important}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.sepia{--tw-sepia:sepia(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter\!{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-all{-webkit-user-select:all;user-select:all}.\[h\:7\]{h:7}.\[notify\:error\]{notify:error}.\[notify\:info\]{notify:info}.\[notify\:success\]{notify:success}.\[p\:42\]{p:42}.\[program\:citydialogue\]{program:citydialogue}.\[timeout\:180\]{timeout:180}.block-full{block-size:100%}.before\:transform:before{content:var(--tw-content);transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}@media(prefers-color-scheme:dark){.dark\:bg-neutral-800{background-color:var(--color-neutral-800)}}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes spin{to{transform:rotate(360deg)}}
/* ── css/vendor/MarkerCluster.css ── */
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
	-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
	-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
	-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
	transition: transform 0.3s ease-out, opacity 0.3s ease-in;
}

.leaflet-cluster-spider-leg {
	/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
	-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
	-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
	-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
	transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
}
/* ── css/vendor/MarkerCluster.Default.css ── */
.marker-cluster-small {
	background-color: rgba(181, 226, 140, 0.6);
	}
.marker-cluster-small div {
	background-color: rgba(110, 204, 57, 0.6);
	}

.marker-cluster-medium {
	background-color: rgba(241, 211, 87, 0.6);
	}
.marker-cluster-medium div {
	background-color: rgba(240, 194, 12, 0.6);
	}

.marker-cluster-large {
	background-color: rgba(253, 156, 115, 0.6);
	}
.marker-cluster-large div {
	background-color: rgba(241, 128, 23, 0.6);
	}

	/* IE 6-8 fallback colors */
.leaflet-oldie .marker-cluster-small {
	background-color: rgb(181, 226, 140);
	}
.leaflet-oldie .marker-cluster-small div {
	background-color: rgb(110, 204, 57);
	}

.leaflet-oldie .marker-cluster-medium {
	background-color: rgb(241, 211, 87);
	}
.leaflet-oldie .marker-cluster-medium div {
	background-color: rgb(240, 194, 12);
	}

.leaflet-oldie .marker-cluster-large {
	background-color: rgb(253, 156, 115);
	}
.leaflet-oldie .marker-cluster-large div {
	background-color: rgb(241, 128, 23);
}

.marker-cluster {
	background-clip: padding-box;
	border-radius: 20px;
	}
.marker-cluster div {
	width: 30px;
	height: 30px;
	margin-left: 5px;
	margin-top: 5px;

	text-align: center;
	border-radius: 15px;
	font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
	}
.marker-cluster span {
	line-height: 30px;
	}
/* ── css/variables.css ── */
/**
 * Shared Design Tokens (Global CSS Variables)
 * Single source of truth for palette, spacing, typography and stacking.
 *
 * IMPORTANT:
 * - Keep this file loaded BEFORE any other app styles.
 * - Do not redefine these variables in `main.css` / `dashboard-base.css`.
 * - Dashboard-specific files may override tokens (rare, intentional).
 */

:root {
  /* ======================================================================
     Primary palette (canonical)
     ====================================================================== */
  --primary: #4f46e5; /* §7.2: indigo-600 — WCAG AA; было #6366f1 (3.75:1, провал) */
  --primary-dark: #4338ca;
  --primary-light: #818cf8;
  --primary-lighter: #a5b4fc;
  --primary-lightest: #e0e7ff;

  /* Secondary / accent */
  --secondary: #10b981;
  --secondary-dark: #059669;
  --accent: #7c3aed; /* §7.2: violet-600 — WCAG AA; было #8b5cf6 (4.23:1, провал) */
  --accent-light: #f3e8ff;

  /* Status colors */
  --success: #10b981;
  --success-dark: #059669;
  --success-light: #34d399;
  --success-lighter: #6ee7b7;
  --success-lightest: #d1fae5;

  --warning: #f59e0b;
  --warning-dark: #d97706;
  --warning-light: #fbbf24;
  --warning-lighter: #fcd34d;
  --warning-lightest: #fef3c7;

  --danger: #ef4444;
  --danger-dark: #dc2626;
  --danger-light: #f87171;
  --danger-lighter: #fca5a5;
  --danger-lightest: #fee2e2;

  --info: #3b82f6;
  --info-dark: #2563eb;
  --info-light: #60a5fa;
  --info-lighter: #93c5fd;
  --info-lightest: #dbeafe;

  /* ======================================================================
     Grays
     ====================================================================== */
  --dark: #0f172a;
  --gray-900: #111827;
  --gray-800: #1f2937;
  --gray-700: #374151;
  --gray-600: #4b5563;
  --gray-500: #6b7280;
  --gray-400: #9ca3af;
  --gray-300: #d1d5db;
  --gray-200: #e5e7eb;
  --gray-100: #f3f4f6;
  --gray-50: #f9fafb;
  --white: #ffffff;

  /* ======================================================================
     Art type colors (used by cultural map)
     ====================================================================== */
  --art-street: #e74c3c;
  --art-music: #3498db;
  --art-visual: #9b59b6;
  --art-design: #2ecc71;
  --art-event: #f39c12;
  --art-other: #95a5a6;

  /* ======================================================================
     Backgrounds
     ====================================================================== */
  --bg-primary: #ffffff;
  --bg-secondary: #f9fafb;
  --bg-tertiary: #f3f4f6;
  --bg-hover: #f3f4f6;
  --bg-muted: #f3f4f6;
  --bg-base: #ffffff;
  --bg-card: #ffffff;
  --bg-overlay: rgba(0, 0, 0, 0.5);

  /* Text colors */
  --text-primary: #111827;
  --text-secondary: #4b5563;
  --text-muted: #5e6472; /* §7.2: WCAG AA даже на тонированных фонах (5.5:1 на #f6f6fe); было #6b7280 (4.49:1 на тинте, провал) */
  --text-light: #d1d5db;

  /* Borders */
  --border: #e5e7eb;
  --border-light: #f3f4f6;
  --border-dark: #d1d5db;

  /* ======================================================================
     Shadows
     ====================================================================== */
  --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px 0 rgb(0 0 0 / 0.06);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
  --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
  --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);

  /* ======================================================================
     Layout sizes
     ====================================================================== */
  /* ТЗ §6.2 (DS-03 2026-07-16): высота хедера — из ds-токена (56px desktop),
     было 64px. Единый источник: --ds-header-h/-mobile ниже. */
  --header-height: var(--ds-header-h, 56px);
  --footer-height: 50px;
  --sidebar-width: 320px;
  --sidebar-left-width: var(--sidebar-width);
  --sidebar-right-width: var(--sidebar-width);
  --sidebar-collapsed: 64px;

  /* Border radius */
  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-2xl: 24px;
  --radius-full: 9999px;

  /* Spacing scale */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  --spacing-2xl: 3rem;
  --spacing-3xl: 4rem;

  /* Typography */
  --font-sans: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "SF Mono", Monaco, "Inconsolata", "Fira Code", "Fira Mono", "Roboto Mono", monospace;

  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --font-size-xs: 0.75rem;
  --font-size-sm: 0.8125rem;
  --font-size-base: 0.875rem;
  --font-size-md: 1rem;
  --font-size-lg: 1.125rem;
  --font-size-xl: 1.25rem;

  /* Transitions */
  --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  /* ======================================================================
     Z-index scale (canonical)
     NOTE: values are intentionally spaced to avoid collisions across dashboards.
     Target ranges:
       - Base:            1-999
       - Widgets:         1000-1499
       - Stream panel:    1500-1599
       - Floating windows:1600-1699
       - Modals:          2000-2999
       - Tooltips/dropdowns: 3000-3999
     ====================================================================== */
  --z-sticky: 1100;
  --z-fixed: 1150;
  --z-widget: 1200;
  /* Sidebars (Citizen mobile overlay panels, etc.) */
  --z-sidebar-overlay: 1440;
  --z-sidebar: 1450;
  --z-stream-panel: 1550;
  --z-floating-window: 1650;

  --z-modal-backdrop: 2500;
  --z-modal: 2600;

  --z-dropdown: 3200;
  --z-popover: 3300;
  --z-tooltip: 3400;

  --z-toast: 3900;
  --z-loading: 3950;
  --z-debug-panel: 2800;

  /* Breakpoints (for consistency; JS may read these if needed) */
  --breakpoint-sm: 640px;
  --breakpoint-md: 768px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1280px;
  --breakpoint-2xl: 1536px;

  /* ======================================================================
     Buttons (canonical sizing tokens)
     ====================================================================== */
  --btn-height-xs: 28px;
  --btn-height-sm: 36px;
  --btn-height-md: 44px;
  --btn-height-lg: 52px;

  --btn-padding-xs: 0.375rem 0.75rem;
  --btn-padding-sm: 0.5rem 1rem;
  --btn-padding-md: 0.75rem 1.25rem;
  --btn-padding-lg: 1rem 1.5rem;

  --btn-font-xs: 0.75rem;
  --btn-font-sm: 0.8125rem;
  --btn-font-md: 0.875rem;
  --btn-font-lg: 1rem;

  /* ======================================================================
     Unified Dashboard Shell tokens (--ds-*)
     Источник истины: docs/dashboard_ui_audit_and_tz_2026-07-16.md §6.2.
     Единственное место объявления. AppShell / 3 компоновки
     (overview | workspace | console) обязаны использовать ТОЛЬКО их;
     legacy-токены выше (--header-height, --sidebar-width) остаются для
     немигрированных экранов и удаляются по мере миграции MIG-01..03.
     ====================================================================== */

  /* Каркас */
  --ds-nav-rail-w: 56px;        /* постоянный рельс навигации */
  --ds-nav-overlay-w: 272px;    /* раскрытая навигация — всегда overlay */
  --ds-header-h: 56px;
  --ds-header-h-mobile: 48px;   /* <768px */
  --ds-panel-left-w: 288px;     /* левая панель workspace/console */
  --ds-panel-right-w: 360px;    /* правая контекстная панель / inspector */
  --ds-inspector-max-w: 420px;
  --ds-content-max: 1440px;     /* центр overview-компоновки */
  --ds-reading-max: 800px;      /* нарратив/чтение */

  /* Отступы (шкала 1..7) */
  --ds-space-1: 4px;
  --ds-space-2: 8px;
  --ds-space-3: 12px;
  --ds-space-4: 16px;
  --ds-space-5: 24px;
  --ds-space-6: 32px;
  --ds-space-7: 48px;

  /* Скругления */
  --ds-radius-control: 6px;
  --ds-radius-card: 10px;
  --ds-radius-modal: 12px;

  /* Высоты контролов: 36/40 desktop, ≥44 touch (ТЗ §6.4) */
  --ds-control-sm: 36px;
  --ds-control-md: 40px;
  --ds-control-touch: 44px;

  /* Типографика (ТЗ §6.5): size/line-height/weight.
     Функциональный текст ≥12px; 9–11px запрещён (кроме vendor-атрибуции карт). */
  --ds-font-page-title: 600 24px/32px var(--font-sans);
  --ds-font-section: 600 20px/28px var(--font-sans);
  --ds-font-card-title: 600 16px/24px var(--font-sans);
  --ds-font-ui: 400 14px/20px var(--font-sans);
  --ds-font-reading: 400 16px/25px var(--font-sans);
  --ds-font-caption: 500 12px/16px var(--font-sans);
  --ds-font-kpi: 600 28px/32px var(--font-sans);
  --ds-font-kpi-lg: 600 40px/44px var(--font-sans);

  /* ======================================================================
     Семантические цвета (UX/UI-ТЗ 2026-07-20, §7.2).
     Бренд разведён с семантикой: brand (тёмно-зелёный) — акцент роли;
     info/success/warning/danger — СТАТУС, не бренд. Смысл не кодируется
     ТОЛЬКО цветом (дублировать иконкой/текстом — §7.9 a11y).
     Единственное место объявления; роль может переопределить --ds-brand.
     ====================================================================== */
  --ds-brand:        #173F35;   /* primary тёмно-зелёный — акцент/бренд */
  --ds-brand-hover:  #0f2d26;
  --ds-brand-weak:   #dfeae6;   /* лёгкий зелёный тинт (hover/selected) */
  --ds-surface:      #FAF8F3;   /* тёплый нейтральный фон */
  --ds-surface-raised: #ffffff;
  --ds-surface-hover: #f2f4f7;  /* ховер строк/пунктов общих компонентов */
  --ds-text:         #172033;
  --ds-text-muted:   #667085;
  --ds-border:       #D0D5DD;
  --ds-info:         #2563EB;
  --ds-success:      #16835D;
  --ds-warning:      #B26A00;
  --ds-danger:       #C43D3D;
  /* Мягкие фоны статусов (для чипов/баннеров; текст — соответствующий цвет). */
  --ds-info-bg:      #eaf1fe;
  --ds-success-bg:   #e6f4ee;
  --ds-warning-bg:   #fbf1e3;
  --ds-danger-bg:    #fbeaea;
  --ds-brand-bg:     #e9f0ed;
  /* Контрастный foreground для сплошных семантических фонов. Не заменять
     на #fff: dark-тема осветляет brand/status и требует тёмный текст. */
  --ds-on-brand:      #ffffff;
  --ds-on-info:       #ffffff;
  --ds-on-success:    #ffffff;
  --ds-on-warning:    #172033;
  --ds-on-danger:     #ffffff;
}

/* Роль-тёмная тема ИИ-мэра и т.п. переопределяет --ds-brand локально;
   базовые статус-цвета остаются одинаковыми во всех ролях (§7.2). */



/* ======================================================================
   Тёмная тема для LEGACY-токенов (ТЗ Часть 7 §5).
   ----------------------------------------------------------------------
   ПРОБЛЕМА (доказано Chromium 2026-07-21): app.css переопределяет эти же
   поверхностные/текстовые/бордер-токены под :root[data-theme="dark"], НО внутри
   `@layer base`. Этот variables.css — БЕЗ слоя (unlayered). По правилам
   каскадных слоёв CSS unlayered ВСЕГДА побеждает layered, поэтому светлые
   значения отсюда перебивали тёмные из app.css → страницы на прямых
   legacy-токенах (login/register/admin) в тёмной теме оставались «половинчато
   тёмными» (тёмная карточка + тёмный текст = нечитабельно).
   РЕШЕНИЕ: даём unlayered dark-переопределения ЗДЕСЬ же. Значения зеркалят
   app.css :root[data-theme="dark"] (строки ~358-441) для консистентности.
   Дашборды используют Editorial-токены (--paper/--ink) и этим блоком не
   затрагиваются в поведении (легаси-токены на них и так должны быть тёмными).
   ====================================================================== */
:root[data-theme="dark"] {
  /* Поверхности */
  --bg-primary: #1A1A1A;
  --bg-secondary: #242422;
  --bg-tertiary: #2E2E2C;
  --bg-hover: #2E2E2C;
  --bg-muted: #2E2E2C;
  --bg-base: #1A1A1A;
  --bg-card: #242422;
  --bg-elevated: #333331;
  --bg-overlay: rgba(0, 0, 0, 0.6);

  /* Текст */
  --text-primary: #E8E6E1;
  --text-secondary: #A8A6A1;
  --text-muted: #9D9A93;  /* §7.2 dark: было #6B6A66 (2.3–3.2:1 на тёмных фонах — нечитаемо); стало ≥4.5:1 на #1a1a1a/#242422/#333331 */
  --text-light: #8A877F;  /* §7.2 dark: было #4A4A47 (невидимо); стало 4.85:1 на базовом фоне */

  /* Линии */
  --border: rgba(255, 255, 255, 0.12);
  --border-light: rgba(255, 255, 255, 0.06);
  --border-dark: rgba(255, 255, 255, 0.18);

  /* Тени — насыщеннее под тёмный фон */
  --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.4);
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.5), 0 1px 2px -1px rgb(0 0 0 / 0.5);
  --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.5), 0 1px 2px 0 rgb(0 0 0 / 0.4);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.5), 0 2px 4px -2px rgb(0 0 0 / 0.5);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.55), 0 4px 6px -4px rgb(0 0 0 / 0.5);
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.6), 0 8px 10px -6px rgb(0 0 0 / 0.55);
  --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.7);
  --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.4);

  /* ====================================================================
     Тёмная тема для СЕМАНТИЧЕСКИХ --ds-* токенов (UX-аудит 2026-07-29).
     --------------------------------------------------------------------
     ПРОБЛЕМА (доказано чтением кода): --ds-* объявлялись ТОЛЬКО в светлом
     :root, тёмных переопределений не было нигде. На них построены ВСЕ 14
     общих компонентов (StatusChip, ContextBar, RoleSwitcher, JobCenter,
     ArtifactCard, RegistryTable, AsyncView, EvidenceDrawer, AIConsent,
     ConfirmDestructive, OverviewTemplate, MapFallback, LineageChain,
     RoleOverview) → в тёмной теме шапка тёмная, а переключатель роли,
     контекст-полоса и центр задач оставались белыми плашками.
     РЕШЕНИЕ: unlayered dark-значения здесь же (тот же приём и та же
     причина, что у legacy-блока выше — unlayered побеждает @layer base).
     Контраст проверен скриптом WCAG: текст ≥ 4.5:1, границы/акценты ≥ 3:1
     на соответствующих поверхностях.
     ==================================================================== */
  /* Бренд: тёмно-зелёный #173F35 на тёмном фоне нечитаем — осветляем. */
  --ds-brand:        #5FBF9B;
  --ds-brand-hover:  #7BD0B1;
  --ds-brand-weak:   #1E3B33;   /* тинт для hover/selected на тёмном */
  --ds-surface:      #1A1A1A;
  --ds-surface-raised: #242422;
  --ds-surface-hover: #2E2E2C;
  --ds-text:         #E8E6E1;
  --ds-text-muted:   #A8A6A1;
  --ds-border:       rgba(255, 255, 255, 0.14);
  /* Статусы: светлее светлотемных, чтобы держать 4.5:1 на #1A1A1A/#242422 */
  --ds-info:         #7FB0FF;
  --ds-success:      #57C79C;
  --ds-warning:      #E3A860;
  --ds-danger:       #F28B8B;
  /* Мягкие фоны статусов — тёмные тинты (текст берёт цвет статуса выше). */
  --ds-info-bg:      #16233D;
  --ds-success-bg:   #12332A;
  --ds-warning-bg:   #33270F;
  --ds-danger-bg:    #3A1E1E;
  --ds-brand-bg:     #16302A;
  /* Светлые dark-theme акценты требуют тёмный foreground (WCAG AA). */
  --ds-on-brand:      #172033;
  --ds-on-info:       #172033;
  --ds-on-success:    #172033;
  --ds-on-warning:    #172033;
  --ds-on-danger:     #172033;
}

/* ═══════════════════════════════════════════════════════════════════════
   ВИДИМЫЙ ФОКУС — unlayered (UX-аудит С-9)
   ═══════════════════════════════════════════════════════════════════════

   Замер на 2026-07-29: 71 правило `outline: none|0` против 43 `:focus-visible`.
   Глобальное кольцо объявлено в app.css внутри `@layer base`, а ролевые
   стили (moderator_dashboard.css, citizen_dashboard.css и др.) идут БЕЗ
   слоя — по правилам каскадных слоёв unlayered ВСЕГДА побеждает layered,
   независимо от специфичности. Итог: кольцо гасилось почти везде, и
   пользователь клавиатуры терял позицию на экране.

   Та же ловушка уже описана выше для тёмной темы — лечим тем же приёмом:
   объявляем кольцо ЗДЕСЬ (unlayered) и последним по порядку.

   `!important` здесь осознан: это a11y-восстановление поверх правил,
   которые гасят фокус целенаправленно. Форсируем ТОЛЬКО outline — если
   компонент рисует своё кольцо через box-shadow, оно остаётся на месте.
   Компоненту, у которого есть СОБСТВЕННЫЙ видимый индикатор фокуса и
   двойное кольцо мешает, — класс `.focus-ring-custom` (opt-out ниже).

   Мышь не затрагиваем: `:focus-visible` срабатывает на клавиатуре и
   ассистивных технологиях, при клике мышью кольца не будет. */

:focus-visible {
  outline: 2px solid var(--ds-brand, var(--primary, #173F35)) !important;
  outline-offset: 2px !important;
}

/* Тёмная тема: бренд-зелёный на тёмном фоне читается хуже — берём светлый
   вариант токена (он уже проверен на контраст в dark-блоке выше). */
:root[data-theme="dark"] :focus-visible {
  outline-color: var(--ds-brand-hover, #7BD0B1) !important;
}

/* Opt-out для компонентов с собственным видимым индикатором фокуса.
   ВАЖНО: применять, только если индикатор ДЕЙСТВИТЕЛЬНО виден (кольцо,
   заливка, сдвиг) — иначе это возврат к невидимому фокусу. */
.focus-ring-custom:focus-visible {
  outline: 2px solid var(--ds-brand, var(--primary)) !important;
  outline-offset: 2px;
}
/* ── css/_palette_refresh_2026.css ── */
/**
 * static/css/_palette_refresh_2026.css
 *
 * Обновление палитры — май 2026. Приглушённые оттенки поверх существующих
 * переменных в variables.css. Сохраняет ПОЛНУЮ совместимость:
 *   • Все классы и компоненты продолжают работать.
 *   • Только переопределяет hex-значения наиболее заметных переменных.
 *   • Цвета подобраны для меньшего "шума" в UI и лучшей читаемости.
 *
 * Подключается ПОСЛЕ variables.css в _base_dashboard.html — поэтому
 * любые компоненты, ссылающиеся на переменные ниже, получают новые
 * значения автоматически.
 *
 * Для отката — закомментировать `<link>` в _base_dashboard.html.
 *
 * Палитра вдохновлена Editorial Calm (см. design-system/tokens/colors.css):
 * приглушённая зелень "охранной грамоты" + тёплые neutral'ы.
 */

:root {
    /* ────────────────────── Primary ──────────────────────
     * Был: indigo #6366f1 (яркий, "сине-фиолетовый ибп")
     * Стал: deep-green #1F3D2B (Editorial Calm accent — "охранная грамота",
     *       чуть менее saturated, лучше для длительного просмотра)
     */
    --primary:         #1F3D2B;
    --primary-dark:    #163021;
    --primary-light:   #355A40;
    --primary-lighter: #6B8B72;
    --primary-lightest:#E8EEEA;

    /* ────────────────────── Accent ──────────────────────
     * Был: violet #8b5cf6
     * Стал: muted teal — спокойнее, лучше совместим с deep-green primary
     */
    --accent:       #4A7C7C;
    --accent-light: #DCE9E9;

    /* ────────────────────── Status colors — slightly muted ──────────────────────
     * Tailwind-яркие saturate'ы → editorial-приглушённые.
     * Tints стали теплее (бумажный оттенок).
     */
    --success:         #2E5E3E;
    --success-dark:    #1F4029;
    --success-light:   #5A8770;
    --success-lightest:#EAF1EC;

    --warning:         #8C5A1A;
    --warning-dark:    #6B4513;
    --warning-light:   #B68440;
    --warning-lightest:#F5EBDA;

    --danger:          #8B2A1F;
    --danger-dark:     #6B1F17;
    --danger-light:    #B65040;
    --danger-lightest: #F4E3DF;

    --info:            #2C5282;
    --info-dark:       #1E3A5F;
    --info-light:      #4A7DB0;
    --info-lightest:   #DCE6F0;

    /* ────────────────────── Surfaces (тёплые neutral'ы) ──────────────────────
     * Был: чистый #ffffff и #f9fafb (холодные).
     * Стал: лёгкий бумажный оттенок (#FBFAF7) — мягче для глаз при долгой работе.
     * НЕ влияет на контраст с текстом — AA сохранён.
     */
    --bg-primary:    #FBFAF7;   /* было: #ffffff (alias --white) */
    --bg-secondary:  #F4F1EA;   /* было: #f9fafb */
    --bg-tertiary:   #ECE7DA;   /* было: #f3f4f6 */
    --bg-elevated:   #FFFFFF;   /* для cards, поверх paper-фона */

    /* Border line: чуть тёплее серого */
    --border:        #D9D3C5;   /* было: #e5e7eb */
    --border-light:  #E6E1D4;   /* было: #f3f4f6 */
    --border-strong: #B8B0A0;

    /* ────────────────────── Text colors (Editorial ink) ──────────────────────
     * Чуть мягче чем чисто-чёрный — лучше для длительного чтения.
     */
    --text-primary:   #1A1A1A;  /* было: #0f172a (slate-900) */
    --text-secondary: #3D3D3D;  /* было: #374151 (gray-700) */
    --text-muted:     #5A5A55;  /* §7.2: WCAG AA на тонированных фонах (5.8:1); было #6B6B66 (4.46:1 на тинте, провал) */
    --text-disabled:  #9B978C;  /* было: #9ca3af (gray-400) */
    --text-inverse:   #FBFAF7;  /* для текста на тёмном фоне */

    /* ────────────────────── Shadows (мягче) ──────────────────────
     * Editorial Calm избегает резких теней. Используем тёплые tints.
     */
    --shadow-sm:  0 1px 2px rgba(26, 26, 26, 0.05);
    --shadow-md:  0 2px 8px rgba(26, 26, 26, 0.06), 0 1px 3px rgba(26, 26, 26, 0.04);
    --shadow-lg:  0 8px 24px rgba(26, 26, 26, 0.08), 0 2px 6px rgba(26, 26, 26, 0.04);
    --shadow-xl:  0 16px 40px rgba(26, 26, 26, 0.10);

    /* Focus ring — приглушённая зелень вместо ярко-синего */
    --focus-ring: 0 0 0 3px rgba(31, 61, 43, 0.20);
}

/* ============================================================
 * Dashboard themes — мягкие фоны для тематических ролей.
 * Не меняем кардинально, только приглушаем существующие.
 * (Каждый dashboard-themes.css добавляет свой акцент поверх.)
 * ============================================================ */

body[data-dashboard-theme] {
    background: var(--bg-primary);
    color: var(--text-secondary);
}

/* ============================================================
 * Smooth transitions для elements которые меняют цвет
 * (button hover, link hover, status changes).
 * Раньше резкие color-jumps делали интерфейс "дёрганным".
 * ============================================================ */

a, button, .btn, [role="button"], [data-toggleable] {
    transition:
        color 150ms ease,
        background-color 150ms ease,
        border-color 150ms ease,
        box-shadow 150ms ease,
        opacity 150ms ease;
}

/* ============================================================
 * Утилитарный класс для скрытия элементов (вместо style="display:none")
 * Используется в HTML где раньше был inline `style="display:none;"`.
 * ============================================================ */

.hidden,
[hidden] {
    display: none !important;
}

/* ============================================================
 * Reduced motion для пользователей с настройкой OS.
 * Editorial Calm избегает агрессивных анимаций.
 * ============================================================ */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
/* ── css/design-system/tokens/colors.css ── */
/*
 * design-system/tokens/colors.css
 * Editorial Calm — палитра.
 * См. ТЗ редизайна v1.0 раздел 3.1.
 *
 * Активируется через: <body data-theme="editorial"> ... </body>
 * чтобы не конфликтовать с существующей Tailwind-палитрой проекта.
 */

[data-theme="editorial"] {
  /* Поверхности */
  --paper:       #FBFAF7;
  --paper-2:     #F4F1EA;
  --paper-3:     #ECE7DA;
  --paper-edge:  #FFFFFF;

  /* Чернила */
  --ink:    #1A1A1A;   /* заголовки, max-contrast */
  --ink-2:  #3D3D3D;   /* основной body-текст */
  --ink-3:  #5A5A55;   /* §7.2: подписи — WCAG AA даже на тонированных фонах (5.8:1); было #6B6B66 (4.46:1 на тинте, провал) */
  --ink-4:  #9B978C;   /* деактивированный, decorative-only — НЕ AA */

  /* Линейки */
  --rule:        #D9D3C5;
  --rule-2:      #E6E1D4;
  --rule-strong: #1A1A1A;

  /* Акцент — приглушённая зелень "охранной грамоты" */
  --accent:      #1F3D2B;
  --accent-ink:  #FBFAF7;
  --accent-tint: #E8EEEA;

  /* Семантика */
  --good:      #2E5E3E;
  --good-tint: #EAF1EC;
  --warn:      #8C5A1A;
  --warn-tint: #F5EBDA;
  --bad:       #8B2A1F;
  --bad-tint:  #F4E3DF;

  /* Подложки для слоёв карты */
  --map-base:   #EEE9DC;
  --map-water:  #DDE4DD;
  --map-stroke: #C9C2B0;

  /* Поверхность по умолчанию */
  background: var(--paper);
  color: var(--ink-2);
}

/*
 * Тёмный вариант Editorial-палитры (ТЗ Часть 7 §5).
 * Дашборды несут <body data-theme="editorial"> и используют --paper/--ink/--rule
 * НАПРЯМУЮ. app.css :root[data-theme="dark"] переопределяет только legacy
 * --bg-… и --text-… (НЕ писать здесь звёздочку сразу перед слэшем — это
 * закрывает CSS-комментарий и роняет следующее правило, Anti-pattern #2),
 * поэтому без этого блока тёмная тема не доходила до Editorial-компонентов
 * (визуальная проверка Chromium 2026-07-21: фон дашборда оставался
 * «бумажным» #FBFAF7 под data-theme="dark"). Селектор
 * :root[data-theme="dark"] [data-theme="editorial"] (специфичность 0,3,0)
 * перекрывает светлый [data-theme="editorial"] (0,1,0). Значения зеркалят
 * тёмные поверхности/текст из app.css для консистентности.
 */
:root[data-theme="dark"] [data-theme="editorial"] {
  /* Поверхности */
  --paper:       #1A1A1A;
  --paper-2:     #242422;
  --paper-3:     #2E2E2C;
  --paper-edge:  #333331;

  /* Чернила (инверсия) */
  --ink:    #E8E6E1;
  --ink-2:  #C9C6C0;
  --ink-3:  #A8A6A1;
  --ink-4:  #6B6A66;

  /* Линейки */
  --rule:        rgba(255, 255, 255, 0.12);
  --rule-2:      rgba(255, 255, 255, 0.06);
  --rule-strong: #E8E6E1;

  /* Акцент — осветлённая «охранная» зелень для контраста на тёмном */
  --accent:      #6FA382;
  --accent-ink:  #14211A;
  --accent-tint: #24352B;

  /* Семантика (осветлённая под тёмный фон) */
  --good:      #5FB37A;
  --good-tint: #1E2E23;
  --warn:      #D9A25A;
  --warn-tint: #33291A;
  --bad:       #E08A7D;
  --bad-tint:  #33211E;

  /* Подложки карты */
  --map-base:   #242422;
  --map-water:  #1E2A24;
  --map-stroke: #3A3A38;

  background: var(--paper);
  color: var(--ink-2);
}
/* ── css/design-system/tokens/legacy-aliases.css ── */
/*
 * design-system/tokens/legacy-aliases.css
 * Editorial Calm — алиасы LEGACY-переменных на палитру (ТЗ §6.1,
 * docs/dashboard_ui_audit_and_tz_2026-07-16.md; активация — решение
 * user 2026-07-16 по пакету до/после Аналитик/Продюсер/Горожанин).
 *
 * Весь существующий CSS продолжает ссылаться на --bg-… / --text-… / --border /
 * --primary — здесь они перенаправляются на Editorial-палитру из colors.css.
 * (Не писать в комментариях "--bg-*" со слэшем сразу после звёздочки —
 * это закрывает комментарий и убивает следующее правило целиком.)
 * Набор алиасов = РОВНО тот, что был в утверждённом эксперименте; расширение
 * (например --info-семейство) — отдельными шагами под VR.
 *
 * Гейт html:not([data-theme="dark"]) — на дашбордах html жёстко "light"
 * (тёмная тема отключена), но если dark когда-нибудь вернётся, Editorial
 * не должен перекрасить его в «бумагу».
 */

html:not([data-theme="dark"]) body[data-theme="editorial"] {
    /* Поверхности */
    --bg-primary: var(--paper-edge);
    --bg-secondary: var(--paper);
    --bg-tertiary: var(--paper-2);
    --bg-hover: var(--paper-2);
    --bg-elevated: var(--paper-edge);

    /* Линии */
    --border: var(--rule);
    --border-light: var(--rule-2);

    /* Текст */
    --text-primary: var(--ink);
    --text-secondary: var(--ink-2);
    --text-muted: var(--ink-3);

    /* Акцент и семантика */
    --primary: var(--accent);
    --primary-dark: #16301F;
    --primary-light: var(--accent-tint);
    --success: var(--good);
    --warning: var(--warn);
    --danger: var(--bad);
}
/* ── css/design-system/tokens/typography.css ── */
/*
 * design-system/tokens/typography.css
 * Editorial Calm — типографика. ТЗ раздел 3.2.
 *
 * 1 шкала, 7 ступеней, 2 шрифтовых семейства (sans + serif) + mono.
 * Шрифты подключаются через <link> в base-template (Google Fonts):
 *   Inter (400, 500, 600, 700) — sans
 *   Source Serif 4 (600) — serif
 *   JetBrains Mono (500) — mono
 */

[data-theme="editorial"] {
  --font-sans:  'Inter', 'Helvetica Neue', system-ui, sans-serif;
  --font-serif: 'Source Serif 4', 'Charter', 'Georgia', serif;
  --font-mono:  'JetBrains Mono', 'SF Mono', Menlo, monospace;

  /* Шкала размеров основных текстов: pair size/lh */
  --t-display-size: 56px; --t-display-lh: 1.05;  /* serif 600 */
  --t-title-size:   36px; --t-title-lh:   1.15;  /* serif 600 */
  --t-section-size: 24px; --t-section-lh: 1.30;  /* sans  600 */
  --t-body-lg-size: 18px; --t-body-lg-lh: 1.55;  /* sans  400 */
  --t-body-size:    16px; --t-body-lh:    1.55;  /* sans  400 */
  --t-caption-size: 13px; --t-caption-lh: 1.40;  /* sans  500 */
  --t-mono-size:    13px; --t-mono-lh:    1.40;  /* mono  500 */

  /* Шкала для KPI и микро-заголовков */
  --t-kpi-xl-size:  44px;
  --t-kpi-size:     28px;
  --t-eyebrow-size: 11px;

  /* Глобальные шрифтовые feature-settings: tnum для всех чисел,
     ss01 — стилистический сет (если есть в шрифте). */
  font-family: var(--font-sans);
  font-feature-settings: "tnum", "ss01";
  font-size: var(--t-body-size);
  line-height: var(--t-body-lh);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ─── Шкала текстовых утилит ───────────────────────────────────────── */

[data-theme="editorial"] .t-display {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: var(--t-display-size);
  line-height: var(--t-display-lh);
  color: var(--ink);
  text-wrap: balance;
}

[data-theme="editorial"] .t-title {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: var(--t-title-size);
  line-height: var(--t-title-lh);
  color: var(--ink);
  text-wrap: balance;
}

[data-theme="editorial"] .t-section {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--t-section-size);
  line-height: var(--t-section-lh);
  color: var(--ink);
  text-wrap: balance;
}

[data-theme="editorial"] .t-body-lg {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--t-body-lg-size);
  line-height: var(--t-body-lg-lh);
  color: var(--ink-2);
  text-wrap: pretty;
}

[data-theme="editorial"] .t-body {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--t-body-size);
  line-height: var(--t-body-lh);
  color: var(--ink-2);
}

[data-theme="editorial"] .t-caption {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--t-caption-size);
  line-height: var(--t-caption-lh);
  color: var(--ink-3);
}

[data-theme="editorial"] .t-mono {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--t-mono-size);
  line-height: var(--t-mono-lh);
  color: var(--ink-2);
}

/* KPI и eyebrow */
[data-theme="editorial"] .t-kpi-xl {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--t-kpi-xl-size);
  line-height: 1.0;
  color: var(--ink);
  font-feature-settings: "tnum";
}

[data-theme="editorial"] .t-kpi {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--t-kpi-size);
  line-height: 1.0;
  color: var(--ink);
  font-feature-settings: "tnum";
}

[data-theme="editorial"] .t-eyebrow {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--t-eyebrow-size);
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* ── css/design-system/tokens/spacing.css ── */
/*
 * design-system/tokens/spacing.css
 * Editorial Calm — 8-px ритм. ТЗ раздел 3.3.
 */

[data-theme="editorial"] {
  --s-1:  4px;
  --s-2:  8px;
  --s-3:  12px;
  --s-4:  16px;
  --s-5:  24px;
  --s-6:  32px;
  --s-7:  48px;
  --s-8:  64px;
  --s-9:  96px;
  --s-10: 128px;

  /* Семантические отступы — desktop-lg по умолчанию */
  --page-px:     96px;
  --page-py:     64px;
  --gutter:      32px;
  --stack:       24px;
  --stack-tight: 16px;
  --stack-loose: 48px;

  /* Радиусы — Editorial Calm не любит сильно скруглённое */
  --r-0:    0;
  --r-1:    2px;     /* пилюли */
  --r-2:    4px;     /* кнопки, инпуты */
  --r-3:    8px;     /* крупные карточки — редко */
  --r-pill: 999px;

  /* Тени — минимально */
  --shadow-0:     none;
  --shadow-1:     0 1px 0 rgba(26, 26, 26, 0.04);
  --shadow-2:     0 1px 3px rgba(26, 26, 26, 0.06), 0 1px 2px rgba(26, 26, 26, 0.04);
  --shadow-focus: 0 0 0 3px rgba(31, 61, 43, 0.25);

  /* Z-index слои.
     ВНИМАНИЕ: имена --z-sticky / --z-modal / --z-toast уже принадлежат общей
     шкале приложения (app.css, variables.css): 1100 / 2600 / 3900. Этот блок
     объявлен на [data-theme="editorial"], который висит на <body> ВСЕХ
     дашбордов и подключается ПОЗЖЕ — при равной специфичности он побеждал и
     подменял три чужих токена своими 10 / 1000 / 2000.
     Последствия были системные, а не косметические:
       • модалка получала 1000 при своей подложке --z-modal-backdrop 2500 —
         то есть уезжала ПОД собственный оверлей. Карточка отчёта Горожанина
         на весь экран выглядела мутной (её размывал backdrop-filter подложки)
         и не принимала клики: elementFromPoint в центре экрана возвращал
         оверлей (замерено на проде 18.08);
       • тост 2000 оказывался ниже выпадашки 3200 и попапа 3300;
       • sticky 10 вместо 1100.
     Свои имена дизайн-системы (--z-base, --z-overlay) не пересекаются с общей
     шкалой и остаются. Чужие — не переопределяем: шкала слоёв в проекте одна.
     Гейт: tests/test_design_token_layer_collisions.py */
  --z-base:    0;
  --z-overlay: 100;
}

/* Адаптивные отступы — десктоп / планшет / мобайл */
@media (max-width: 1439px) {
  [data-theme="editorial"] {
    --page-px: 64px;
    --page-py: 56px;
    --gutter:  24px;
  }
}
@media (max-width: 1023px) {
  [data-theme="editorial"] {
    --page-px: 32px;
    --page-py: 40px;
    --gutter:  24px;
  }
}
@media (max-width: 767px) {
  [data-theme="editorial"] {
    --page-px: 20px;
    --page-py: 32px;
    --gutter:  16px;
  }
}

/* ─── Сетка ─────────────────────────────────────────────────────────── */

[data-theme="editorial"] .ed-page {
  max-width: 1440px;
  margin: 0 auto;
  padding-inline: var(--page-px);
  padding-block:  var(--page-py);
}

[data-theme="editorial"] .ed-grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
}

/* Семантические утилиты вертикального ритма */
[data-theme="editorial"] .ed-stack       { display: flex; flex-direction: column; gap: var(--stack); }
[data-theme="editorial"] .ed-stack-tight { display: flex; flex-direction: column; gap: var(--stack-tight); }
[data-theme="editorial"] .ed-stack-loose { display: flex; flex-direction: column; gap: var(--stack-loose); }
/* ── css/design-system/tokens/motion.css ── */
/*
 * design-system/tokens/motion.css
 * Editorial Calm — движение. ТЗ раздел 3.7.
 *
 * Любая анимация дольше 300ms запрещена.
 * Никаких easing-кривых вне --ease.
 */

[data-theme="editorial"] {
  --motion-fast: 120ms;
  --motion-base: 180ms;
  --motion-slow: 280ms;
  --ease:        cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* Глобальный safety-net для пользователей с reduced-motion */
@media (prefers-reduced-motion: reduce) {
  [data-theme="editorial"],
  [data-theme="editorial"] *,
  [data-theme="editorial"] *::before,
  [data-theme="editorial"] *::after {
    animation-duration:   0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration:  0.01ms !important;
    scroll-behavior:      auto !important;
  }
}
/* ── css/design-system/components/button.css ── */
/*
 * design-system/components/button.css
 * Editorial Calm — Button. ТЗ раздел 4.1.
 *
 * Варианты:  primary, secondary, ghost, danger
 * Размеры:   sm (32px), md (40px по умолчанию), lg (48px)
 * Состояния: default, hover, active, focus, disabled, loading
 *
 * Использование:
 *   <button class="ed-btn ed-btn--primary">Открыть город</button>
 *   <button class="ed-btn ed-btn--secondary ed-btn--lg">Подробнее</button>
 *   <button class="ed-btn ed-btn--ghost ed-btn--sm">Отменить</button>
 *   <button class="ed-btn ed-btn--danger" disabled>Удалить</button>
 *   <button class="ed-btn ed-btn--primary" data-loading>Запускаю…</button>
 *
 * ЗАПРЕЩЕНО: эмодзи в кнопках. Только Lucide-иконки 16/20/24px,
 * stroke-width: 1.5 (см. ТЗ приложение A).
 */

[data-theme="editorial"] .ed-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  height: 40px;
  padding-inline: var(--s-4);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.01em;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  user-select: none;
  transition: background-color var(--motion-fast) var(--ease),
              border-color var(--motion-fast) var(--ease),
              color var(--motion-fast) var(--ease);
}

/* Размеры */
[data-theme="editorial"] .ed-btn--sm { height: 32px; padding-inline: var(--s-3); font-size: 13px; }
[data-theme="editorial"] .ed-btn--md { height: 40px; padding-inline: var(--s-4); font-size: 14px; }
[data-theme="editorial"] .ed-btn--lg { height: 48px; padding-inline: var(--s-5); font-size: 15px; }

/* Иконки внутри (Lucide, никаких эмодзи) */
[data-theme="editorial"] .ed-btn svg {
  width: 16px;
  height: 16px;
  stroke-width: 1.5;
  flex-shrink: 0;
}
[data-theme="editorial"] .ed-btn--lg svg { width: 20px; height: 20px; }

/* ─── PRIMARY ──────────────────────────────────────────────────────── */
[data-theme="editorial"] .ed-btn--primary {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
[data-theme="editorial"] .ed-btn--primary:hover:not(:disabled) {
  background: #000;        /* затемнение на ~4% */
  border-color: #000;
}
[data-theme="editorial"] .ed-btn--primary:active:not(:disabled) {
  background: #000;
  transform: translateY(0.5px);
}

/* ─── SECONDARY ────────────────────────────────────────────────────── */
[data-theme="editorial"] .ed-btn--secondary {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}
[data-theme="editorial"] .ed-btn--secondary:hover:not(:disabled) {
  background: var(--paper-2);
}
[data-theme="editorial"] .ed-btn--secondary:active:not(:disabled) {
  background: var(--paper-3);
}

/* ─── GHOST ────────────────────────────────────────────────────────── */
[data-theme="editorial"] .ed-btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: transparent;
}
[data-theme="editorial"] .ed-btn--ghost:hover:not(:disabled) {
  background: var(--paper-2);
}

/* ─── DANGER ───────────────────────────────────────────────────────── */
[data-theme="editorial"] .ed-btn--danger {
  background: var(--bad);
  color: var(--white);
  border-color: var(--bad);
}
[data-theme="editorial"] .ed-btn--danger:hover:not(:disabled) {
  background: #6E1F17;     /* ~4% темнее */
  border-color: #6E1F17;
}

/* ─── ОБЩИЕ СОСТОЯНИЯ ──────────────────────────────────────────────── */
[data-theme="editorial"] .ed-btn:focus-visible {
   box-shadow: var(--shadow-focus);
}
[data-theme="editorial"] .ed-btn:disabled,
[data-theme="editorial"] .ed-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;     /* ТЗ: именно прозрачность, не серый текст */
}

/* Loading: спиннер слева, текст остаётся.
   Применяется через атрибут [data-loading] для совместимости с
   реактивным state (без перерисовки HTML). */
[data-theme="editorial"] .ed-btn[data-loading]::before {
  content: "";
  width: 14px;
  height: 14px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: ed-btn-spin 700ms linear infinite;
}
[data-theme="editorial"] .ed-btn[data-loading] { pointer-events: none; }

@keyframes ed-btn-spin {
  to { transform: rotate(360deg); }
}
/* ── css/design-system/components/pill.css ── */
/*
 * design-system/components/pill.css
 * Editorial Calm — StatusPill. ТЗ раздел 4.3.
 *
 * Использование:
 *   <span class="ed-pill ed-pill--good">актив</span>
 *   <span class="ed-pill ed-pill--warn">пауза</span>
 *   <span class="ed-pill ed-pill--bad">сбой</span>
 *   <span class="ed-pill ed-pill--neutral">черновик</span>
 *
 * Спека: height 24, padding 0 10, font 12/500, letter-spacing 0.02em,
 * radius --r-1, фон *-tint, текст семантический, рамка цвет-25%.
 */

[data-theme="editorial"] .ed-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  padding: 0 10px;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1;
  border-radius: var(--r-1);
  border-width: 1px;
  border-style: solid;
  white-space: nowrap;
  vertical-align: middle;
}

/* Семантические варианты */
[data-theme="editorial"] .ed-pill--good {
  background: var(--good-tint);
  color: var(--good);
  border-color: rgba(46, 94, 62, 0.25);   /* --good @ 25% */
}
[data-theme="editorial"] .ed-pill--warn {
  background: var(--warn-tint);
  color: var(--warn);
  border-color: rgba(140, 90, 26, 0.25);
}
[data-theme="editorial"] .ed-pill--bad {
  background: var(--bad-tint);
  color: var(--bad);
  border-color: rgba(139, 42, 31, 0.25);
}
[data-theme="editorial"] .ed-pill--neutral {
  background: var(--paper-2);
  color: var(--ink-3);
  border-color: var(--rule);
}

/* Точка-индикатор — отдельный примитив, можно использовать самостоятельно
   или внутри пилюли: <span class="ed-dot ed-dot--good"></span> */
[data-theme="editorial"] .ed-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
}
[data-theme="editorial"] .ed-dot--good { color: var(--good); }
[data-theme="editorial"] .ed-dot--warn { color: var(--warn); }
[data-theme="editorial"] .ed-dot--bad  { color: var(--bad); }
/* ── css/design-system/components/empty.css ── */
/*
 * design-system/components/empty.css
 * Editorial Calm — EmptyState. ТЗ раздел 4.6.
 *
 * 1 заголовок + 1 описание + опционально 1 действие.
 * НИКАКИХ иллюстраций. Тонкая пунктирная рамка.
 *
 * Использование:
 *   <div class="ed-empty">
 *     <div class="ed-empty__title">Исследования ещё не запущены</div>
 *     <div class="ed-empty__body">Когда появится первое — здесь будет
 *       список с прогрессом и логами.</div>
 *     <button class="ed-btn ed-btn--primary">Создать исследование</button>
 *   </div>
 */

[data-theme="editorial"] .ed-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-6);
  border: 1px dashed var(--rule);
  border-radius: var(--r-2);
  background: var(--paper);
}

[data-theme="editorial"] .ed-empty__title {
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
  text-wrap: balance;
}

[data-theme="editorial"] .ed-empty__body {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-3);
  text-wrap: pretty;
  max-width: 60ch;
}

/* Центрированный вариант — для больших EmptyState на всю секцию. */
[data-theme="editorial"] .ed-empty--center {
  align-items: center;
  text-align: center;
}
[data-theme="editorial"] .ed-empty--center .ed-empty__body {
  max-width: 50ch;
}
/* ── css/design-system/components/skeleton.css ── */
/*
 * design-system/components/skeleton.css
 * Editorial Calm — Skeleton. ТЗ раздел 4.7.
 *
 * Skeleton РЕЗЕРВИРУЕТ место для финального компонента → нулевой CLS.
 * При prefers-reduced-motion — без shimmer-анимации, статичная плашка.
 *
 * Использование:
 *   <div class="ed-skel ed-skel--text" style="width: 70%"></div>
 *   <div class="ed-skel ed-skel--text" style="width: 90%"></div>
 *   <div class="ed-skel ed-skel--block" style="height: 200px"></div>
 *   <div class="ed-skel ed-skel--circle" style="width:40px;height:40px"></div>
 *
 * ВАЖНО (ТЗ 4.2 + 6.1): не используем "—" как индикатор "грузится".
 * "—" — это empty-state. Loading — это skeleton.
 */

[data-theme="editorial"] .ed-skel {
  display: block;
  background: var(--paper-3);
  border-radius: var(--r-2);
  background-image: linear-gradient(
    90deg,
    var(--paper-3) 0%,
    var(--paper-2) 50%,
    var(--paper-3) 100%
  );
  background-size: 200% 100%;
  animation: ed-skel-shimmer 1500ms ease-in-out infinite;
}

[data-theme="editorial"] .ed-skel--text {
  height: 14px;
  width: 100%;
  margin: 4px 0;
}

[data-theme="editorial"] .ed-skel--block {
  width: 100%;
  height: 100px;
}

[data-theme="editorial"] .ed-skel--circle {
  border-radius: 50%;
}

@keyframes ed-skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Reduced-motion: статичная плашка без анимации */
@media (prefers-reduced-motion: reduce) {
  [data-theme="editorial"] .ed-skel {
    animation: none;
    background-image: none;
    background: var(--paper-3);
  }
}
/* ── css/design-system/components/stat.css ── */
/*
 * design-system/components/stat.css
 * Editorial Calm — Stat (KPI). ТЗ 4.2.
 *
 * 4 канонических состояния:
 *   data    — число + лейбл + опциональная дельта
 *   loading — skeleton-полоска вместо числа, лейбл остаётся
 *   empty   — "—" + микрокопия "Данные ожидаются"
 *   error   — иконка + кнопка "Попробовать снова"
 *
 * Использование:
 *   <div class="ed-stat">
 *     <div class="ed-stat__value">12 408</div>
 *     <div class="ed-stat__label">фактов в БЗ</div>
 *     <div class="ed-stat__delta ed-stat__delta--up">+ 12% за неделю</div>
 *   </div>
 *
 * Loading:
 *   <div class="ed-stat" data-state="loading">
 *     <div class="ed-skel ed-skel--text" style="width: 60%; height: 32px;"></div>
 *     <div class="ed-stat__label">фактов в БЗ</div>
 *   </div>
 *
 * Empty:
 *   <div class="ed-stat" data-state="empty">
 *     <div class="ed-stat__value">—</div>
 *     <div class="ed-stat__label">фактов в БЗ</div>
 *     <div class="ed-stat__hint">Данные ожидаются</div>
 *   </div>
 *
 * Error:
 *   <div class="ed-stat" data-state="error">
 *     <div class="ed-stat__error">
 *       <svg>...</svg>
 *       <span>Не удалось загрузить</span>
 *       <button class="ed-btn ed-btn--ghost ed-btn--sm">Попробовать снова</button>
 *     </div>
 *     <div class="ed-stat__label">фактов в БЗ</div>
 *   </div>
 *
 * ЗАПРЕЩЕНО (ТЗ 4.2):
 *  • Использовать "—" как loading-индикатор. Это empty-state.
 *  • Лейбл ПЕРВЫМ, число вторым. Лейбл ВСЕГДА снизу.
 *  • Дельта без знака. Всегда "+ 12%" или "− 4%".
 */

[data-theme="editorial"] .ed-stat {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-4) 0;
}

[data-theme="editorial"] .ed-stat__value {
  font-family: var(--font-sans);
  font-size: var(--t-kpi-size);
  font-weight: 600;
  line-height: 1;
  color: var(--ink);
  font-feature-settings: "tnum";
}

[data-theme="editorial"] .ed-stat__label {
  font-family: var(--font-sans);
  font-size: var(--t-caption-size);
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink-3);
}

[data-theme="editorial"] .ed-stat__delta {
  font-family: var(--font-mono);
  font-size: var(--t-mono-size);
  font-weight: 500;
  margin-top: var(--s-1);
  color: var(--ink-3);
}
[data-theme="editorial"] .ed-stat__delta--up   { color: var(--good); }
[data-theme="editorial"] .ed-stat__delta--down { color: var(--bad);  }
[data-theme="editorial"] .ed-stat__delta--flat { color: var(--ink-3); }

/* Empty-state hint под лейблом */
[data-theme="editorial"] .ed-stat__hint {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--ink-4);  /* допустимо — это decorative-hint */
  margin-top: var(--s-1);
}

/* Error — компактный inline-блок с иконкой и кнопкой повтора */
[data-theme="editorial"] .ed-stat__error {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-sans);
  font-size: var(--t-caption-size);
  color: var(--bad);
}
[data-theme="editorial"] .ed-stat__error svg {
  width: 16px;
  height: 16px;
  stroke-width: 1.5;
  flex-shrink: 0;
}

/* XL-вариант — для главного KPI на странице (ТЗ 3.2 --t-kpi-xl) */
[data-theme="editorial"] .ed-stat--xl .ed-stat__value {
  font-size: var(--t-kpi-xl-size);
}

/* Inline-вариант: число и лейбл в одну строку, через тонкий разделитель */
[data-theme="editorial"] .ed-stat--inline {
  flex-direction: row;
  align-items: baseline;
  gap: var(--s-3);
  padding: 0;
}
[data-theme="editorial"] .ed-stat--inline .ed-stat__label::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 12px;
  background: var(--rule);
  margin-right: var(--s-3);
  vertical-align: middle;
}
/* ── css/design-system/components/city-card.css ── */
/*
 * design-system/components/city-card.css
 * Editorial Calm — CityCard. ТЗ 4.4.
 *
 * Кликабельна вся карточка (через <a>-обёртку).
 * НЕ используем тени — рамка + hover на ink.
 *
 * Использование:
 *   <a class="ed-city-card" href="/cities/kaluga">
 *     <div class="ed-city-card__name">Калуга</div>
 *     <div class="ed-city-card__meta">12 408 фактов · 9 исследований</div>
 *     <div class="ed-city-card__pulse">
 *       <span class="ed-dot ed-dot--good"></span>
 *       <span>обновлено сегодня</span>
 *     </div>
 *   </a>
 *
 * Loading:
 *   <div class="ed-city-card" data-state="loading">
 *     <div class="ed-skel ed-skel--text" style="width: 50%; height: 22px;"></div>
 *     <div class="ed-skel ed-skel--text" style="width: 70%;"></div>
 *     <div class="ed-skel ed-skel--text" style="width: 40%;"></div>
 *   </div>
 */

[data-theme="editorial"] .ed-city-card {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-5);
  background: var(--paper-edge);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--motion-fast) var(--ease),
              background-color var(--motion-fast) var(--ease);
}

[data-theme="editorial"] a.ed-city-card:hover,
[data-theme="editorial"] a.ed-city-card:focus-visible {
  border-color: var(--ink);
}
[data-theme="editorial"] a.ed-city-card:focus-visible {
   box-shadow: var(--shadow-focus);
}

/* Имя города — title-like, sans 600 */
[data-theme="editorial"] .ed-city-card__name {
  font-family: var(--font-sans);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}

/* Мета — счётчики, через middle-dot */
[data-theme="editorial"] .ed-city-card__meta {
  font-family: var(--font-sans);
  font-size: var(--t-caption-size);
  font-weight: 500;
  color: var(--ink-3);
  font-feature-settings: "tnum";
}

/* Pulse-индикатор внизу */
[data-theme="editorial"] .ed-city-card__pulse {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--ink-3);
  margin-top: var(--s-2);
}

/* Empty-вариант — для городов без данных */
[data-theme="editorial"] .ed-city-card[data-state="empty"] .ed-city-card__name {
  color: var(--ink-3);
}
/* ── css/design-system/components/role-switcher.css ── */
/*
 * design-system/components/role-switcher.css
 * Editorial Calm — RoleSwitcher. ТЗ 4.5.
 *
 * Сегмент-контрол для переключения активной роли в контексте города.
 * До 6 ролей помещаются в одну линию, остальные — в overflow-меню «ещё».
 *
 * Использование:
 *   <div class="ed-role-switcher" role="tablist" aria-label="Роль">
 *     <button class="ed-role-switcher__item is-active" role="tab" aria-selected="true">Аналитик</button>
 *     <button class="ed-role-switcher__item" role="tab">Урбанист</button>
 *     <button class="ed-role-switcher__item is-locked" role="tab" disabled aria-disabled="true">
 *       Стратег
 *       <span class="ed-pill ed-pill--neutral">PRO</span>
 *     </button>
 *     <button class="ed-role-switcher__more">Ещё 5</button>
 *   </div>
 */

[data-theme="editorial"] .ed-role-switcher {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding: 0;
}

[data-theme="editorial"] .ed-role-switcher__item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: 32px;
  padding-inline: var(--s-3);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: var(--ink-3);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--motion-fast) var(--ease),
              color var(--motion-fast) var(--ease),
              background-color var(--motion-fast) var(--ease);
}

[data-theme="editorial"] .ed-role-switcher__item:hover:not(:disabled) {
  border-color: var(--ink);
  color: var(--ink);
}

[data-theme="editorial"] .ed-role-switcher__item:focus-visible {
   box-shadow: var(--shadow-focus);
}

/* Активная — рамка ink, текст ink */
[data-theme="editorial"] .ed-role-switcher__item.is-active,
[data-theme="editorial"] .ed-role-switcher__item[aria-selected="true"] {
  border-color: var(--ink);
  color: var(--ink);
  background: var(--paper-edge);
}

/* Locked (PRO без подписки) — disabled но кликабельна для показа PRO-флоу.
   Используем cursor: pointer и не блокируем клик через CSS. */
[data-theme="editorial"] .ed-role-switcher__item.is-locked,
[data-theme="editorial"] .ed-role-switcher__item:disabled,
[data-theme="editorial"] .ed-role-switcher__item[aria-disabled="true"] {
  opacity: 0.6;
  cursor: pointer;  /* Не not-allowed — мы хотим клик на PRO-флоу */
}

[data-theme="editorial"] .ed-role-switcher__more {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding-inline: var(--s-3);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-3);
  background: transparent;
  border: 1px dashed var(--rule);
  border-radius: var(--r-2);
  cursor: pointer;
}
[data-theme="editorial"] .ed-role-switcher__more:hover {
  border-color: var(--ink);
  color: var(--ink);
}
/* ── css/design-system/components/toast.css ── */
/*
 * design-system/components/toast.css
 * Editorial Calm — Toast. ТЗ 4.8.
 *
 * Появляется в правом нижнем углу, position: fixed, z-index --z-toast.
 * Auto-close 5s для good/warn. НЕ закрывается для bad — пользователь
 * должен прочитать ошибку.
 *
 * JS-помощник: static/js/design-system/toast.js
 *   ToastManager.show({ kind: 'good', title: '...', body: '...' });
 */

[data-theme="editorial"] .ed-toast-container {
  position: fixed;
  bottom: var(--s-5);
  right: var(--s-5);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  z-index: var(--z-toast);
  pointer-events: none;  /* контейнер не перехватывает клики */
}

[data-theme="editorial"] .ed-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  min-width: 280px;
  max-width: 400px;
  padding: var(--s-3) var(--s-4);
  background: var(--paper-edge);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  pointer-events: auto;
  transform: translateY(8px);
  opacity: 0;
  animation: ed-toast-in var(--motion-base) var(--ease) forwards;
}

[data-theme="editorial"] .ed-toast.is-leaving {
  animation: ed-toast-out var(--motion-base) var(--ease) forwards;
}

[data-theme="editorial"] .ed-toast__icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  margin-top: 1px;  /* выравнивание с baseline заголовка */
}
[data-theme="editorial"] .ed-toast__icon svg {
  width: 20px;
  height: 20px;
  stroke-width: 1.5;
}

[data-theme="editorial"] .ed-toast--good .ed-toast__icon { color: var(--good); }
[data-theme="editorial"] .ed-toast--warn .ed-toast__icon { color: var(--warn); }
[data-theme="editorial"] .ed-toast--bad  .ed-toast__icon { color: var(--bad);  }

[data-theme="editorial"] .ed-toast__body {
  flex: 1;
  min-width: 0;
}

[data-theme="editorial"] .ed-toast__title {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

[data-theme="editorial"] .ed-toast__text {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-3);
  margin-top: 2px;
}

[data-theme="editorial"] .ed-toast__close {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--ink-3);
  border-radius: var(--r-2);
}
[data-theme="editorial"] .ed-toast__close:hover { color: var(--ink); background: var(--paper-2); }
[data-theme="editorial"] .ed-toast__close:focus-visible { outline: 0; box-shadow: var(--shadow-focus); }

@keyframes ed-toast-in {
  to { transform: translateY(0); opacity: 1; }
}
@keyframes ed-toast-out {
  to { transform: translateY(8px); opacity: 0; }
}
/* ── css/design-system/components/global-search.css ── */
/*
 * design-system/components/global-search.css
 * Editorial Calm — GlobalSearch (Cmd-K). ТЗ 4.9.
 *
 * Триггер — кнопка в AppHeader. Активация по клику / ⌘K / Ctrl+K.
 * Открывается модальный оверлей с инпутом и сгруппированными результатами.
 *
 * Группы (ТЗ 4.9):
 *   • Города
 *   • Активные исследования
 *   • Разделы (Пульс, Тарифы, Профиль)
 *   • История последних 5 запросов
 */

/* ─── Trigger в хедере ─────────────────────────────────────────────── */
[data-theme="editorial"] .ed-search-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  height: 36px;
  padding: 0 var(--s-3);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  color: var(--ink-3);
  font-family: var(--font-sans);
  font-size: 13px;
  cursor: pointer;
  min-width: 220px;
  transition: border-color var(--motion-fast) var(--ease);
}
[data-theme="editorial"] .ed-search-trigger:hover { border-color: var(--ink); }
[data-theme="editorial"] .ed-search-trigger:focus-visible { outline: 0; box-shadow: var(--shadow-focus); }
[data-theme="editorial"] .ed-search-trigger > span { flex: 1; text-align: left; }

[data-theme="editorial"] .ed-kbd {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  background: var(--paper-edge);
  border: 1px solid var(--rule);
  border-radius: var(--r-1);
}

/* ─── Overlay + dialog ─────────────────────────────────────────────── */
[data-theme="editorial"] .ed-search-overlay {
  position: fixed;
  inset: 0;
  background: rgba(26, 26, 26, 0.4);
  z-index: var(--z-modal);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}

[data-theme="editorial"] .ed-search-dialog {
  width: min(640px, 92%);
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--paper-edge);
  border: 1px solid var(--rule);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}

[data-theme="editorial"] .ed-search-input-wrap {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4);
  border-bottom: 1px solid var(--rule);
}
[data-theme="editorial"] .ed-search-input-wrap svg {
  width: 20px; height: 20px; stroke-width: 1.5; color: var(--ink-3); flex-shrink: 0;
}
[data-theme="editorial"] .ed-search-input {
  flex: 1;
  border: 0;
   background: transparent;
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--ink);
}
[data-theme="editorial"] .ed-search-input::placeholder { color: var(--ink-3); }
[data-theme="editorial"] .ed-search-input:focus-visible { box-shadow: var(--shadow-focus); }

[data-theme="editorial"] .ed-search-results {
  overflow-y: auto;
  flex: 1;
}

/* Группа результатов */
[data-theme="editorial"] .ed-search-group {
  border-bottom: 1px solid var(--rule-2);
}
[data-theme="editorial"] .ed-search-group:last-child { border-bottom: 0; }

[data-theme="editorial"] .ed-search-group__title {
  padding: var(--s-3) var(--s-4) var(--s-1);
  font-family: var(--font-sans);
  font-size: var(--t-eyebrow-size);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

[data-theme="editorial"] .ed-search-item {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  cursor: pointer;
  border: 0;
  width: 100%;
  background: transparent;
  text-align: left;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink-2);
  text-decoration: none;
  transition: background-color var(--motion-fast) var(--ease);
}
[data-theme="editorial"] .ed-search-item:hover,
[data-theme="editorial"] .ed-search-item.is-selected {
  background: var(--paper-2);
  color: var(--ink);
}
[data-theme="editorial"] .ed-search-item__title {
  flex: 1;
  font-weight: 500;
}
[data-theme="editorial"] .ed-search-item__meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-3);
}

[data-theme="editorial"] .ed-search-empty {
  padding: var(--s-6) var(--s-4);
  text-align: center;
  color: var(--ink-3);
  font-size: 14px;
}

/* Footer-подсказка по горячим клавишам */
[data-theme="editorial"] .ed-search-footer {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-2) var(--s-4);
  border-top: 1px solid var(--rule-2);
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--ink-3);
}
[data-theme="editorial"] .ed-search-footer .ed-kbd {
  margin-right: var(--s-2);
}
/* ── css/design-system/components/app-header.css ── */
/*
 * design-system/components/app-header.css
 * Editorial Calm — AppHeader. ТЗ 4.10.
 *
 * Единый хедер на всех экранах кроме главной (на главной — упрощённый
 * вариант без хлебных крошек).
 *
 * Структура:
 *   [logo] · [breadcrumbs] · [search] · [pulse · profile]
 *   sticky top:0, z-index --z-sticky, height 64px,
 *   border-bottom 1px solid --rule
 *
 * Использование (через partial templates/components/_app_header.html):
 *   {% include "components/_app_header.html" with city=city, role=role %}
 */

[data-theme="editorial"] .ed-app-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--s-5);
  height: 64px;
  padding: 0 var(--s-6);
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

/* Логотип-вордмарк слева */
[data-theme="editorial"] .ed-app-header__logo {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 18px;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
[data-theme="editorial"] .ed-app-header__logo:focus-visible {
   box-shadow: var(--shadow-focus);
  border-radius: var(--r-2);
}

/* Хлебные крошки в центре-слева */
[data-theme="editorial"] .ed-app-header__crumbs {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink-3);
  flex: 0 1 auto;
  min-width: 0;
}
[data-theme="editorial"] .ed-app-header__crumbs a {
  color: var(--ink-3);
  text-decoration: none;
}
[data-theme="editorial"] .ed-app-header__crumbs a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
[data-theme="editorial"] .ed-app-header__crumbs strong {
  font-weight: 500;
  color: var(--ink);
}
[data-theme="editorial"] .ed-app-header__crumbs__sep {
  opacity: 0.4;
  user-select: none;
}

/* Spacer для распределения */
[data-theme="editorial"] .ed-app-header__spacer { flex: 1; }

/* Правая зона: поиск + меню */
[data-theme="editorial"] .ed-app-header__right {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

[data-theme="editorial"] .ed-app-header__menu-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: 36px;
  padding: 0 var(--s-3);
  background: transparent;
  border: 0;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--ink-3);
  cursor: pointer;
  text-decoration: none;
  border-radius: var(--r-2);
  transition: color var(--motion-fast) var(--ease),
              background-color var(--motion-fast) var(--ease);
}
[data-theme="editorial"] .ed-app-header__menu-item:hover { color: var(--ink); background: var(--paper-2); }
[data-theme="editorial"] .ed-app-header__menu-item:focus-visible { outline: 0; box-shadow: var(--shadow-focus); }
[data-theme="editorial"] .ed-app-header__menu-item svg {
  width: 16px; height: 16px; stroke-width: 1.5;
}

/* Адаптация — на узких экранах прячем breadcrumbs */
@media (max-width: 767px) {
  [data-theme="editorial"] .ed-app-header { padding: 0 var(--s-4); gap: var(--s-3); }
  [data-theme="editorial"] .ed-app-header__crumbs { display: none; }
  [data-theme="editorial"] .ed-search-trigger { min-width: 0; }
  [data-theme="editorial"] .ed-search-trigger > span { display: none; }
}
/* ── css/design-system/components/tabs.css ── */
/*
 * design-system/components/tabs.css
 * Editorial Calm — Tabs. ТЗ 4.11.
 *
 * Унифицируют структуру всех дашбордов. ≤ 5 вкладок верхнего уровня.
 * Активная вкладка — нижняя линия 2px ink с -1px margin (overlay рамки).
 *
 * Использование:
 *   <div class="ed-tabs" role="tablist" aria-label="Разделы города">
 *     <button class="ed-tab is-active" role="tab" aria-selected="true">Обзор</button>
 *     <button class="ed-tab" role="tab" aria-selected="false">Исследования</button>
 *     <button class="ed-tab" role="tab">Новости</button>
 *     <button class="ed-tab" role="tab">База знаний</button>
 *   </div>
 */

.ed-tabs {
  display: flex;
  gap: var(--s-5, 24px);
  height: 44px;
  border-bottom: 1px solid var(--rule, var(--border, #D9D3C5));
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* §12 «длинные названия»: внутри flex-контейнера (шапка/тулбар) группа
     вкладок сжимается и скроллится сама, а не распирает родителя. */
  min-width: 0;
  flex-shrink: 1;
}

.ed-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 var(--s-1, 4px);
  /* §12 стресс-сценарий «длинные названия»: вкладка с длинным лейблом не
     должна распирать тулбар за viewport — clamp + ellipsis. */
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: -1px;  /* перекрываем border-bottom родителя */
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-3, var(--text-muted, #6b7280));
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--motion-fast, .15s) var(--ease, ease),
              border-color var(--motion-fast, .15s) var(--ease, ease);
}

.ed-tab:hover { color: var(--ink, var(--text-primary, #1F2937)); }

.ed-tab:focus-visible {
   box-shadow: var(--shadow-focus, 0 0 0 2px var(--primary, #1F3D2B));
  border-radius: var(--r-2, 6px);
}

.ed-tab.is-active,
.ed-tab.active,
.ed-tab[aria-selected="true"] {
  color: var(--ink, var(--text-primary, #1F2937));
  border-bottom-color: var(--ink, var(--text-primary, #1F2937));
}

/* Бэйджик-счётчик внутри таба */
.ed-tab__count {
  margin-left: var(--s-2, 8px);
  padding: 0 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3, var(--text-muted, #6b7280));
  background: var(--paper-2, var(--bg-secondary, #F5F4F0));
  border-radius: var(--r-1, 4px);
  font-feature-settings: "tnum";
}
.ed-tab.is-active .ed-tab__count,
.ed-tab.active .ed-tab__count {
  color: var(--ink, var(--text-primary, #1F2937));
  background: var(--paper-3, var(--bg-tertiary, #ECEAE4));
}

/* Компактный вариант для под-табов и плотных тулбаров (§6.7):
   <div class="ed-tabs ed-tabs--sm" role="tablist"> */
.ed-tabs.ed-tabs--sm { height: 36px; gap: var(--s-4, 16px); }
.ed-tabs--sm .ed-tab { height: 36px; font-size: 13px; }
/* ── css/design-system/components/pulse.css ── */
/*
 * design-system/components/pulse.css
 * Editorial Calm — Pulse. ТЗ 4.12.
 *
 * Минималистичный индикатор статуса системы. Заменяет всё текущее
 * "💓 Пульс Системы" в одну строку.
 *
 * Состояния:
 *   good — все системы в норме
 *   warn — частичная деградация (с указанием подсистемы)
 *   bad  — сбой (со ссылкой на /system/pulse)
 *
 * Использование:
 *   <div class="ed-pulse ed-pulse--good">
 *     <span class="ed-dot ed-dot--good"></span>
 *     <span>Все системы в норме · обновлено 2 мин назад</span>
 *   </div>
 */

[data-theme="editorial"] .ed-pulse {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  transition: border-color var(--motion-fast) var(--ease),
              background-color var(--motion-fast) var(--ease);
}
[data-theme="editorial"] a.ed-pulse:hover { border-color: var(--ink); }
[data-theme="editorial"] a.ed-pulse:focus-visible { outline: 0; box-shadow: var(--shadow-focus); }

[data-theme="editorial"] .ed-pulse--good { background: transparent; }
[data-theme="editorial"] .ed-pulse--warn { background: var(--warn-tint); border-color: rgba(140, 90, 26, 0.25); color: var(--warn); }
[data-theme="editorial"] .ed-pulse--bad  { background: var(--bad-tint);  border-color: rgba(139, 42, 31, 0.25); color: var(--bad);  }

[data-theme="editorial"] .ed-pulse--warn .ed-dot,
[data-theme="editorial"] .ed-pulse--bad .ed-dot {
  /* анимация мягкого пульса для тревожных состояний */
  animation: ed-pulse-blink 2000ms ease-in-out infinite;
}

@keyframes ed-pulse-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

@media (prefers-reduced-motion: reduce) {
  [data-theme="editorial"] .ed-pulse .ed-dot {
    animation: none;
  }
}
/* ── css/design-system/components/map.css ── */
/*
 * design-system/components/map.css
 * Editorial Calm — Map. ТЗ §6.5.
 *
 * Тайлы — монохромные на тёплой бумажной подложке (--map-base).
 * Точки городов — кружки 6-20px, диаметр по плотности данных.
 * Hover на точке — мини-превью CityCard.
 *
 * Зависимость: MapLibre GL JS подключается через CDN.
 */

[data-theme="editorial"] .ed-map {
  position: relative;
  width: 100%;
  min-height: 480px;
  background: var(--map-base);
  border: 1px solid var(--rule);
}

[data-theme="editorial"] .ed-map__container {
  width: 100%;
  height: 100%;
  min-height: 480px;
}

/* Mini-preview popup (CityCard adapt for hover) */
[data-theme="editorial"] .ed-map-popup {
  font-family: var(--font-sans);
  pointer-events: none;
}
[data-theme="editorial"] .ed-map-popup .maplibregl-popup-content {
  padding: var(--s-3) var(--s-4);
  background: var(--paper-edge);
  border: 1px solid var(--ink);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  font-family: var(--font-sans);
  min-width: 200px;
}
[data-theme="editorial"] .ed-map-popup .maplibregl-popup-tip { display: none; }

[data-theme="editorial"] .ed-map-popup__name {
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
  margin-bottom: 4px;
}
[data-theme="editorial"] .ed-map-popup__meta {
  font-size: 12px;
  color: var(--ink-3);
  font-feature-settings: "tnum";
}

/* MapLibre overrides — приглушаем default UI под Editorial */
[data-theme="editorial"] .maplibregl-ctrl-group {
  background: var(--paper-edge);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  box-shadow: none;
}
[data-theme="editorial"] .maplibregl-ctrl-group button {
  background: var(--paper-edge);
  border: 0;
}
[data-theme="editorial"] .maplibregl-ctrl-group button:hover {
  background: var(--paper-2);
}
[data-theme="editorial"] .maplibregl-ctrl-attrib {
  background: rgba(251, 250, 247, 0.85);
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--ink-3);
}

/* Loading-state */
[data-theme="editorial"] .ed-map[data-state="loading"]::after {
  content: "Загружаем карту…";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--map-base);
  color: var(--ink-3);
  font-family: var(--font-sans);
  font-size: 14px;
  z-index: 1;
}

/* Error-state */
[data-theme="editorial"] .ed-map[data-state="error"] .ed-map__container { display: none; }
[data-theme="editorial"] .ed-map[data-state="error"]::after {
  content: "Не удалось загрузить тайлы. Попробовать снова?";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--bad);
  font-family: var(--font-sans);
  font-size: 14px;
  padding: var(--s-5);
  text-align: center;
}
/* ── css/dashboard-base.css ── */
/**
 * Dashboard Base Styles - Unified Design System
 * Version 4.1 - Added Cultural Map Components
 * FIXED: Font imports, modal styles, backdrop-filter fallbacks
 */

/* ========================================================================
   Design tokens moved to static/css/variables.css
   ======================================================================== */

/* Stream Recorder styles were moved to static/css/stream-panel.css and are lazy-loaded
   by static/js/stream/streamToggle.js (to avoid global z-index collisions). */

/* ========================================================================
   RESET & BASE
   ======================================================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    font-size: 16px;
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
}

body {
    font-family: var(--font-sans);
    font-size: 0.875rem;
    font-weight: 400;
    line-height: 1.6;
    color: var(--text-primary);
    background: var(--bg-base);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

body[data-dashboard-theme] {
    /* One-screen dashboards: keep footer visible and make inner panes scroll */
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* body stays flex-column; nav-sidebar is position:fixed, shell uses margin-left */

body[data-dashboard-theme] .dashboard-header {
    flex-shrink: 0;
}

/* Desktop: lock body height so footer never "falls down" */
@media (min-width: 901px) {
    html,
    body[data-dashboard-theme] {
        height: 100%;
    }

    body[data-dashboard-theme] {
        height: 100vh;
        overflow: hidden;
    }
}

/* ========================================================================
   NAV SIDEBAR — persistent vertical navigation
   ======================================================================== */

:root {
    --nav-sidebar-width: 240px;
    --nav-sidebar-collapsed-width: 56px;
}

.nav-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--nav-sidebar-width);
    background: var(--bg-primary);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    z-index: 200;
    transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: hidden;
}

.nav-sidebar.collapsed {
    width: var(--nav-sidebar-collapsed-width);
}

/* Brand / Logo area */
.nav-sidebar-brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px;
    height: 48px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.nav-sidebar-logo {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
    color: var(--text-primary);
    min-width: 0;
    overflow: hidden;
}

.nav-sidebar-logo-icon {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    color: var(--primary);
}

.nav-sidebar-brand-text {
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    white-space: nowrap;
    opacity: 1;
    transition: opacity 0.2s;
}

.nav-sidebar.collapsed .nav-sidebar-brand-text {
    opacity: 0;
    width: 0;
    overflow: hidden;
}

/* Toggle button */
.nav-sidebar-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    background: var(--bg-tertiary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--text-muted);
    flex-shrink: 0;
    transition: background 0.15s, color 0.15s;
}

.nav-sidebar-toggle:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.nav-sidebar .toggle-icon-expand { display: none; }
.nav-sidebar .toggle-icon-collapse { display: block; }
.nav-sidebar.collapsed .toggle-icon-expand { display: block; }
.nav-sidebar.collapsed .toggle-icon-collapse { display: none; }

/* Menu area */
.nav-sidebar-menu {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 0;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.nav-sidebar-menu::-webkit-scrollbar {
    width: 4px;
}

.nav-sidebar-menu::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: var(--radius-xs);
}

/* Section labels */
.nav-sidebar-section {
    padding: 4px 0;
}

.nav-sidebar-section-label {
    display: block;
    padding: 6px 16px 4px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    transition: opacity 0.2s;
}

.nav-sidebar.collapsed .nav-sidebar-section-label {
    opacity: 0;
    height: 0;
    padding: 0;
    overflow: hidden;
}

/* Nav items */
.nav-sidebar-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    margin: 1px 8px;
    border-radius: var(--radius);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    cursor: pointer;
    border: none;
    background: none;
    width: calc(100% - 16px);
    text-align: left;
    transition: background 0.15s, color 0.15s;
}

.nav-sidebar-item:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.nav-sidebar-item.active {
    background: var(--primary);
    color: var(--white);
}

.nav-sidebar-item.active:hover {
    background: var(--primary-dark, var(--primary));
    color: var(--white);
}

.nav-sidebar-item.disabled {
    opacity: 0.4;
    pointer-events: none;
    cursor: not-allowed;
}

.nav-sidebar-item-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 1;
}

.nav-sidebar-item-icon svg {
    width: 20px;
    height: 20px;
}

.nav-sidebar-item-text {
    opacity: 1;
    transition: opacity 0.2s;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nav-sidebar.collapsed .nav-sidebar-item-text {
    opacity: 0;
    width: 0;
    overflow: hidden;
}

.nav-sidebar.collapsed .nav-sidebar-item {
    justify-content: center;
    padding: 8px;
    margin: 1px 6px;
    gap: 0;
}

/* Bottom section */
.nav-sidebar-bottom {
    border-top: 1px solid var(--border);
    padding: 8px 0;
    flex-shrink: 0;
}

/* ========================================================================
   DASHBOARD SHELL — offset by nav sidebar
   ======================================================================== */

.dashboard-shell {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    min-width: 0;
    margin-left: var(--nav-sidebar-width);
    transition: margin-left 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    height: 100vh;
    overflow: hidden;
}

html.nav-sidebar-is-collapsed .dashboard-shell {
    margin-left: var(--nav-sidebar-collapsed-width);
}

/* ========================================================================
   NAV SIDEBAR BACKDROP & MOBILE TOGGLE
   ======================================================================== */

.nav-sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 199;
    opacity: 0;
    transition: opacity 0.25s;
}

.nav-sidebar-backdrop.visible {
    display: block;
    opacity: 1;
}

.nav-sidebar-mobile-toggle {
    display: none;
    position: fixed;
    top: 10px;
    left: 10px;
    z-index: 201;
    width: 40px;
    height: 40px;
    border: none;
    background: var(--bg-primary);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    color: var(--text-primary);
}

@media (max-width: 768px) {
    .nav-sidebar {
        transform: translateX(-100%);
        transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        width: var(--nav-sidebar-width);
    }

    .nav-sidebar.mobile-open {
        transform: translateX(0);
    }

    .dashboard-shell {
        margin-left: 0;
    }

    html.nav-sidebar-is-collapsed .dashboard-shell {
        margin-left: 0;
    }

    .nav-sidebar-mobile-toggle {
        display: flex;
    }
}

@media print {
    .nav-sidebar,
    .nav-sidebar-backdrop,
    .nav-sidebar-mobile-toggle {
        display: none !important;
    }

    .dashboard-shell {
        margin-left: 0 !important;
    }
}

/* ========================================================================
   DASHBOARD HEADER (unified) — Phase 2: compact after nav-link cleanup
   ======================================================================== */

body[data-dashboard-theme] .dashboard-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    padding: 0 var(--spacing-lg);
    height: var(--header-height, 48px);
    background: var(--bg-primary);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 50;
    flex-shrink: 0;
}

body[data-dashboard-theme] .dashboard-header .header-left {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    min-width: 0;
}

body[data-dashboard-theme] .dashboard-header .header-left h1 {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* F-07 (аудит v2.2): без пола ширины flex ужимал заголовок до «Г…».
       Многоточие допустимо, односимвольный обрубок — нет. */
    min-width: 10ch;
}

body[data-dashboard-theme] .dashboard-header .city-name,
body[data-dashboard-theme] .dashboard-header .survey-name {
    font-size: 0.8125rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 40vw;
}

/* Пилот ContextBar (UX-P0-01): слот полосы контекста выносится на СВОЮ строку
   под заголовком (flex-wrap + order + flex-basis), чтобы не сжимать h1 — иначе
   даже короткий role-title («Аналитика») сам обрезается в одном ряду. Сам бар
   несёт свою ellipsis-логику для длинных значений. */
body[data-dashboard-theme] .dashboard-header .header-left:has(.dashboard-contextbar) {
    flex-wrap: wrap;
    row-gap: 4px;
}
body[data-dashboard-theme] .dashboard-header .dashboard-contextbar {
    order: 99;
    flex-basis: 100%;
    min-width: 0;
}

body[data-dashboard-theme] .dashboard-header .header-right {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.375rem;
    flex-wrap: nowrap;
}

/* Hide header-right when empty (all nav links removed) */
body[data-dashboard-theme] .dashboard-header .header-right:empty {
    display: none;
}

/* Header center stats (moderator, etc.) — compact */
body[data-dashboard-theme] .dashboard-header .header-center {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
}

body[data-dashboard-theme] .dashboard-header .stats-container {
    display: flex;
    gap: var(--spacing-md);
}

body[data-dashboard-theme] .dashboard-header .stat-item {
    text-align: center;
    line-height: 1.2;
}

body[data-dashboard-theme] .dashboard-header .stat-value {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-primary);
}

body[data-dashboard-theme] .dashboard-header .stat-label {
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

body[data-dashboard-theme] .llm-balance-widget {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    background: var(--bg-tertiary);
    border-radius: var(--radius-full);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--text-secondary);
    /* Тесный топбар ломал чип в 3 строки — держим одной строкой */
    white-space: nowrap;
    flex-shrink: 0;
}

body[data-dashboard-theme] .llm-balance-widget .details-link {
    color: var(--primary);
    text-decoration: none;
}

@media (max-width: 640px) {
    body[data-dashboard-theme] .dashboard-header {
        padding: 0 var(--spacing-md);
        /* ТЗ §6.2/§12: mobile-хедер не ниже 48px (было fallback 40px) */
        height: var(--ds-header-h-mobile, 48px);
    }
    body[data-dashboard-theme] .dashboard-header .header-left h1 {
        font-size: 0.875rem;
    }
    body[data-dashboard-theme] .dashboard-header .city-name,
    body[data-dashboard-theme] .dashboard-header .survey-name {
        display: none;
    }
    body[data-dashboard-theme] .dashboard-header .header-center {
        display: none;
    }
    body[data-dashboard-theme] .user-info-panel .user-details {
        display: none;
    }
}

body[data-dashboard-theme] .dashboard-main {
    /* Allow main layout to shrink so footer stays visible and inner panes can scroll */
    flex: 1 1 auto;
    width: 100%;
    display: flex;
    flex-direction: row;
    min-height: 0;
    overflow: hidden;
    background: var(--bg-secondary);
    /* Subtle inner shadow to separate from header */
    box-shadow: inset 0 1px 0 var(--border);
}

/* Layout wrappers used by role dashboards inside shell.
   Each needs flex:1 + min-height:0 so the 3-column content fills the shell. */
.dashboard-shell .dashboard-layout,
.dashboard-shell .developer-dashboard-root,
.dashboard-shell .econ-wrap,
.dashboard-shell > .page-container {
    flex: 1 1 auto;
    display: flex;
    flex-direction: row;
    min-height: 0;
    overflow: hidden;
    width: 100%;
}

/* KPI/status bars between header and main — don't let them shrink */
.dashboard-shell .strategy-kpi-grid,
.dashboard-shell .status-bar,
.dashboard-shell .view-mode-bar {
    flex-shrink: 0;
}

/* Main container (methodologist etc.) — fill shell like dashboard-main */
.dashboard-shell .main-container {
    flex: 1 1 auto;
    display: flex;
    flex-direction: row;
    min-height: 0;
    overflow: hidden;
    width: 100%;
}

/* Header actions — compact button group */
body[data-dashboard-theme] .header-actions {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

/* User info panel in header — keep compact.
   Header is 60px: the chip must stay a single meta-line and never overflow
   vertically (floating-windows.css gives it fat paddings + 36px avatar —
   override here; these rules win by specificity). */
body[data-dashboard-theme] .user-info-panel {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 4px 10px;
    flex-shrink: 0;
}

body[data-dashboard-theme] .user-info-panel .user-avatar {
    font-size: 1rem;
    line-height: 1;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
}

body[data-dashboard-theme] .user-info-panel .user-details {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

body[data-dashboard-theme] .user-info-panel .user-name {
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

body[data-dashboard-theme] .user-info-panel .user-meta {
    display: flex;
    gap: 0.5rem;
    font-size: 0.75rem;
    color: var(--text-muted);
    white-space: nowrap;
}

body[data-dashboard-theme] .dashboard-content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* Critical for nested flex layouts: enables .content-wrapper/.view-pane scroll instead of clipping */
    min-height: 0;
    overflow: auto;
    padding: var(--spacing-md);
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

body[data-dashboard-theme] .dashboard-content::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

body[data-dashboard-theme] .dashboard-content::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 3px;
}

body[data-dashboard-theme] .dashboard-content::-webkit-scrollbar-track {
    background: transparent;
}

body[data-dashboard-theme] .dashboard-sidebar-left,
body[data-dashboard-theme] .dashboard-sidebar-right {
    background: var(--bg-primary);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    flex-shrink: 0;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

body[data-dashboard-theme] .dashboard-sidebar-left::-webkit-scrollbar,
body[data-dashboard-theme] .dashboard-sidebar-right::-webkit-scrollbar {
    width: 4px;
}

body[data-dashboard-theme] .dashboard-sidebar-left::-webkit-scrollbar-thumb,
body[data-dashboard-theme] .dashboard-sidebar-right::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: var(--radius-xs);
}

body[data-dashboard-theme] .dashboard-sidebar-left {
    width: var(--sidebar-left-width);
    border-left: none;
    border-right: 1px solid var(--border);
}

body[data-dashboard-theme] .dashboard-sidebar-right {
    width: var(--sidebar-right-width);
    border-right: none;
    border-left: 1px solid var(--border);
}

/* ── Шторки боковых панелей (UX 2026-07-03 «больше места для работы»).
   Классы ставит static/js/shared/sidebar-collapse.js; аддитивно для всех
   дашбордов на общем каркасе. Плавное схлопывание в 0 + ручки ‹ › на краях. ── */
body[data-dashboard-theme] .dashboard-sidebar-left,
body[data-dashboard-theme] .dashboard-sidebar-right {
    transition: width 0.25s ease;
}
body[data-dashboard-theme].sb-left-collapsed .dashboard-sidebar-left,
body[data-dashboard-theme].sb-right-collapsed .dashboard-sidebar-right {
    width: 0 !important;
    min-width: 0 !important;
    border: none !important;
    overflow: hidden !important;
    padding: 0 !important;
}
body[data-dashboard-theme] .dashboard-main.sb-collapse-host {
    position: relative;
}
body[data-dashboard-theme] .sb-collapse-handle {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 60;
    width: 16px;
    height: 64px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-primary);
    color: var(--text-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    opacity: 0.55;
    transition: opacity 0.15s, background 0.15s;
    box-shadow: 0 1px 4px color-mix(in srgb, var(--dark) 15%, transparent);
}
body[data-dashboard-theme] .sb-collapse-handle:hover {
    opacity: 1;
    background: var(--bg-secondary);
    color: var(--text-primary);
}
body[data-dashboard-theme] .sb-handle-left  { left: 0;  border-top-left-radius: 0; border-bottom-left-radius: 0; }
body[data-dashboard-theme] .sb-handle-right { right: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; }
body[data-dashboard-theme] .sb-handle-chev { font-size: 14px; font-weight: 700; line-height: 1; transition: transform 0.25s; }
body[data-dashboard-theme] .sb-handle-collapsed .sb-handle-chev { transform: rotate(180deg); }

body[data-dashboard-theme] .sidebar-section {
    padding: var(--spacing-md);
    border-bottom: 1px solid var(--border);
}

body[data-dashboard-theme] .sidebar-section:last-child {
    border-bottom: none;
}

body[data-dashboard-theme] .sidebar-title {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: var(--spacing-sm);
}

/* Central panel containers — fill available space, scroll when needed */
body[data-dashboard-theme] .dashboard-main > main,
body[data-dashboard-theme] .dashboard-main .dashboard-center,
body[data-dashboard-theme] .dashboard-main .center-panel {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    overflow-x: hidden;
    position: relative;
}

@media (max-width: 1200px) {
    body[data-dashboard-theme] .dashboard-main {
        flex-direction: column;
    }
    body[data-dashboard-theme] .dashboard-sidebar-left,
    body[data-dashboard-theme] .dashboard-sidebar-right {
        width: 100%;
        max-height: 30vh;
        border: none;
    }
    body[data-dashboard-theme] .dashboard-sidebar-left { border-bottom: 1px solid var(--border); }
    body[data-dashboard-theme] .dashboard-sidebar-right { border-top: 1px solid var(--border); }
}

@media (max-width: 768px) {
    body[data-dashboard-theme] .dashboard-sidebar-left,
    body[data-dashboard-theme] .dashboard-sidebar-right {
        position: fixed;
        left: -100%;
        height: 100vh;
        z-index: var(--z-fixed);
        transition: left 0.3s;
        box-shadow: var(--shadow-lg);
        max-height: 100vh;
    }
    body[data-dashboard-theme] .dashboard-sidebar-right {
        left: auto;
        right: -100%;
        transition: right 0.3s;
    }
    body[data-dashboard-theme] .dashboard-sidebar-left.open { left: 0; }
    body[data-dashboard-theme] .dashboard-sidebar-right.open { right: 0; }
}

/* ========================================================================
   COLLAPSIBLE SIDE PANELS — системный стандарт (shared/collapsible-panels.js)
   Кнопки-переключатели в .dashboard-header сворачивают левую/правую
   .dashboard-sidebar-* (или [data-collapsible-panel]) колонку — центр
   растёт через flex:1. Стандарт для всех 3-колоночных дашбордов.
   ======================================================================== */
.panel-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-primary, var(--white));
    color: var(--text-secondary, var(--gray-500));
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.panel-toggle:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.panel-toggle.is-collapsed {
    /* Свёрнуто — подсветить, чтобы было видно «панель спрятана». */
    background: var(--accent-light, var(--bg-secondary));
    border-color: var(--accent, var(--border));
    color: var(--accent, var(--text-primary));
}
.panel-toggle svg { display: block; transition: transform 0.2s ease; }
.panel-toggle-left { margin-right: 0.5rem; }
.panel-toggle-right { margin-left: 0.5rem; }
/* Направление шеврона: ‹ = «свернуть», › = «развернуть».
   Базовый SVG указывает ‹ (влево). */
.panel-toggle-right svg            { transform: rotate(180deg); } /* › свернуть вправо */
.panel-toggle-left.is-collapsed svg  { transform: rotate(180deg); } /* › развернуть */
.panel-toggle-right.is-collapsed svg { transform: rotate(0deg); }  /* ‹ развернуть */

/* Опциональный якорь для центральной колонки: если центр не имеет
   flex-grow в своём CSS, пометь его data-collapsible-center — тогда при
   сворачивании боковой панели освободившееся место заберёт именно он. */
body[data-dashboard-theme] [data-collapsible-center] {
    flex: 1 1 auto;
    min-width: 0;
}

/* Страховка последней инстанции (P0-DEV-01, аудит 23.08). Если после
   «показать панель» она всё равно оказалась ЗА пределами окна — раскладка
   решила иначе, чем мы думали, — panel-visibility.js вешает этот класс.
   Панель становится шторкой у правого края ВНУТРИ окна: пользователь
   добирается до вкладок и легенд, даже когда чужое правило увело колонку
   за viewport. Лучше шторка, чем недостижимая панель. */
body[data-dashboard-theme] .dashboard-sidebar-right.panel-forced-drawer,
body[data-dashboard-theme] [data-collapsible-panel="right"].panel-forced-drawer {
    position: fixed !important;
    top: var(--ds-header-h, 56px);
    right: 0 !important;
    left: auto !important;
    height: calc(100vh - var(--ds-header-h, 56px));
    width: min(var(--sidebar-right-width, 360px), 92vw) !important;
    transform: none !important;
    z-index: var(--z-fixed, 1030);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
}
body[data-dashboard-theme] .dashboard-sidebar-left.panel-forced-drawer,
body[data-dashboard-theme] [data-collapsible-panel="left"].panel-forced-drawer {
    position: fixed !important;
    top: var(--ds-header-h, 56px);
    left: 0 !important;
    right: auto !important;
    height: calc(100vh - var(--ds-header-h, 56px));
    width: min(var(--sidebar-left-width, 320px), 92vw) !important;
    transform: none !important;
    z-index: var(--z-fixed, 1030);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
}

/* Свёртка применяется только на широких экранах — ниже работает
   адаптивная раскладка (стек / drawer), там переключатели не нужны. */
@media (min-width: 1201px) {
    body[data-dashboard-theme] .dashboard-sidebar-left.is-collapsed,
    body[data-dashboard-theme] .dashboard-sidebar-right.is-collapsed,
    body[data-dashboard-theme] [data-collapsible-panel].is-collapsed {
        display: none !important;
    }
}
@media (max-width: 1200px) {
    .panel-toggle { display: none; }
}

/* ========================================================================
   CONTEXT PANEL — slide-over panel (V2 Design System)
   Replaces permanent right sidebar for dashboards that need on-demand info.
   Usage: add .context-panel to a right-side element, toggle .is-open via JS.
   ======================================================================== */

.context-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 400px;
    max-width: 90vw;
    background: var(--bg-elevated, var(--white));
    border-left: 1px solid var(--border);
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);
    z-index: var(--z-fixed, 100);
    transform: translateX(100%);
    transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.context-panel.is-open {
    transform: translateX(0);
}

.context-panel__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.context-panel__title {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-primary);
}

.context-panel__close {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md, 8px);
    color: var(--text-muted);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.context-panel__close:hover {
    background: color-mix(in srgb, var(--danger) 12%, var(--bg-primary));
    color: var(--danger);
}

.context-panel__body {
    flex: 1 1 0;
    overflow-y: auto;
    padding: 16px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

/* Backdrop overlay when panel is open */
.context-panel-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.2);
    z-index: calc(var(--z-fixed, 100) - 1);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}

.context-panel-backdrop.is-visible {
    opacity: 1;
    pointer-events: auto;
}

[data-theme="dark"] .context-panel {
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.35);
}

/* Ensure font inheritance for all elements */
button, input, select, textarea, optgroup {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
}

/* ========================================================================
   TYPOGRAPHY
   ======================================================================== */

/* §6.5: пол 12px для относительных вложений. small/code внутри уже мелкого
   родителя (0.75rem-хинты) композитно уезжали до 10.5–11.2px — max() держит
   относительный размер, но не даёт упасть ниже читаемого минимума.
   Vendor-атрибуция карт — единственное допущенное исключение (ТЗ §6.5). */
small { font-size: max(12px, 0.83em); }
code, kbd, samp { font-size: max(12px, 0.875em); }

h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-weight: 600;
    line-height: 1.2;
    color: var(--text-primary);
}

h1 { font-size: 2.25rem; }
h2 { font-size: 1.875rem; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }
h5 { font-size: 1.125rem; }
h6 { font-size: 1rem; }

p {
    margin: 0 0 1rem;
    line-height: 1.6;
}

a {
    color: var(--primary);
    text-decoration: none;
    transition: var(--transition-fast);
}

a:hover {
    color: var(--primary-dark);
}

/* ========================================================================
   LAYOUT COMPONENTS
   ======================================================================== */

.page-container {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Header */
.app-header {
    position: sticky;
    top: 0;
    height: var(--header-height);
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    padding: 0 var(--spacing-lg);
}

/* Fallback for browsers without backdrop-filter support */
@supports not (backdrop-filter: blur(20px)) {
    .app-header {
        background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    }
}

.app-logo {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--gray-900);
    letter-spacing: -0.02em;
}

.header-nav {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    margin-left: auto;
    margin-right: auto;
}

/* ========================================================================
   KNOWLEDGE OVERLAY COMPONENT
   ======================================================================== */

.kb-overlay {
    position: absolute;
    top: clamp(12px, 2vw, 32px);
    right: clamp(12px, 3vw, 40px);
    width: clamp(240px, 24vw, 340px);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 1rem;
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    pointer-events: auto;
}

.kb-overlay.is-hidden {
    display: none;
}

.kb-overlay__close {
    align-self: flex-end;
    border: none;
    background: none;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    margin: -0.5rem -0.5rem -0.5rem 0;
}

.kb-overlay__close:hover {
    color: var(--text-primary);
    background: var(--bg-tertiary);
}

.kb-overlay__header {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    align-items: flex-start;
}

.kb-overlay__eyebrow {
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0 0 0.2rem;
}

.kb-overlay__title {
    font-size: 0.95rem;
    margin: 0;
    color: var(--text-primary);
}

.kb-overlay__btn {
    border: 1px solid var(--border);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border-radius: var(--radius-sm);
    padding: 0.35rem 0.6rem;
    font-size: 0.78rem;
    cursor: pointer;
    transition: all 0.2s ease;
}

.kb-overlay__btn:hover {
    border-color: var(--primary);
    color: var(--primary);
}

.kb-overlay__stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.4rem;
}

.kb-overlay__stat {
    padding: 0.5rem;
    border-radius: var(--radius);
    background: var(--bg-tertiary);
}

.kb-overlay__stat-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: 0.05em;
}

.kb-overlay__stat-value {
    display: block;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--text-primary);
}

.kb-overlay__section {
    border-top: 1px solid var(--border-light);
    padding-top: 0.6rem;
}

.kb-overlay__section h4 {
    margin: 0 0 0.4rem;
    font-size: 0.82rem;
    color: var(--text-secondary);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.kb-overlay__fact {
    padding: 0.35rem 0;
    border-bottom: 1px dashed var(--border-light);
}

.kb-overlay__fact:last-child {
    border-bottom: none;
}

.kb-overlay__fact-title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 0.2rem;
}

.kb-overlay__fact-meta {
    font-size: 0.75rem;
    color: var(--text-muted);
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
}

.kb-overlay__fact button {
    border: none;
    background: none;
    color: var(--primary);
    font-size: 0.78rem;
    padding: 0;
    cursor: pointer;
}

.kb-overlay__principle {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin-bottom: 0.45rem;
    display: flex;
    gap: 0.4rem;
}

.kb-overlay__principle span {
    color: var(--primary);
    font-weight: 600;
}

.kb-overlay__footnote {
    font-size: 0.75rem;
    color: var(--text-muted);
    display: flex;
    justify-content: space-between;
    gap: 0.4rem;
    align-items: center;
}

.kb-overlay__loading {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    align-items: center;
    justify-content: center;
    min-height: 140px;
    color: var(--text-secondary);
    text-align: center;
}

@media (max-width: 1200px) {
    .kb-overlay {
        display: none;
    }
}

.header-user-section {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
}

.user-info {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

#current-user-name {
    font-weight: 500;
    color: var(--text-primary);
}

/* Footer */
.app-footer {
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-top: 1px solid var(--border);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
    padding: var(--spacing-md) var(--spacing-lg);
    margin-top: auto;
}

@supports not (backdrop-filter: blur(20px)) {
    .app-footer {
        background: var(--bg-elevated);
    }
}

.footer-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-md);
}

/* Buttons moved to static/css/components/buttons.css */

/* ========================================================================
   FORMS
   ======================================================================== */

.form-group {
    margin-bottom: var(--spacing-md);
}

.form-label {
    display: block;
    margin-bottom: var(--spacing-xs);
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
}

.input,
.form-input,
.search-input {
    width: 100%;
    padding: 10px 14px;
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 400;
    line-height: 1.5;
    color: var(--gray-900);
    background: var(--bg-elevated);
    border: 1px solid var(--gray-300);
    border-radius: var(--radius-md);
    transition: var(--transition-fast);
 }

.input:focus,
.form-input:focus,
.search-input:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-success) 10%, transparent);
}

.input:disabled {
    background: var(--gray-50);
    color: var(--text-muted);
    cursor: not-allowed;
}

textarea.input,
textarea.form-input {
    resize: vertical;
    min-height: 100px;
}

select.input {
    cursor: pointer;
}

/* Form helper / error / actions / row — shared by templates/components/_macros.html
   form macros (form_field, text_input, textarea, select_field, …). Используют
   только design tokens, без hardcoded цветов.

   .form-hint — legacy-alias .form-helper'а; canonical-source консолидирован
   из task_setter_layout.css + grant_wizard.css в эту общую точку (P13).
   Scoped-overrides (.dashboard-sidebar-right .form-hint в developer,
   #mission-constructor-modal .form-hint в data_engineer) сохраняются как
   контекстные. */
.form-helper,
.form-hint {
    margin-top: var(--spacing-xs);
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.45;
}
.form-error {
    margin-top: var(--spacing-xs);
    font-size: 12px;
    color: var(--danger);
    line-height: 1.45;
}
.form-group.has-error .form-input,
.form-group.has-error .input,
.form-group.has-error select,
.form-group.has-error textarea {
    border-color: var(--danger);
}
.form-group.has-error .form-input:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-danger) 10%, transparent);
}
.form-required {
    color: var(--danger);
    margin-left: 2px;
}

/* Inline row layout for fields side-by-side. Wraps gracefully on narrow viewports. */
.form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--spacing-md);
}

/* Actions row — submit + cancel button alignment.
   Default: right-aligned (form convention). Pass align='space-between' / 'left'
   for alternative layouts. */
.form-actions {
    display: flex;
    gap: var(--spacing-sm);
    justify-content: flex-end;
    margin-top: var(--spacing-lg);
    flex-wrap: wrap;
}
.form-actions--left { justify-content: flex-start; }
.form-actions--space-between { justify-content: space-between; }
.form-actions--center { justify-content: center; }

/* Checkbox / radio — inline label + native input. */
.form-checkbox,
.form-radio {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-sm);
    cursor: pointer;
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-primary);
}
.form-checkbox input,
.form-radio input {
    margin-top: 2px;
    flex-shrink: 0;
    cursor: pointer;
}
.form-checkbox-text,
.form-radio-text {
    flex: 1;
}

/* ========================================================================
   CARDS
   ======================================================================== */

.card {
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
    transition: var(--transition);
}

.card:hover {
    box-shadow: var(--shadow-lg);
}

.card-header {
    padding: var(--spacing-md);
    background: var(--gray-50);
    border-bottom: 1px solid var(--border);
    font-weight: 600;
    color: var(--gray-900);
}

.card-body {
    padding: var(--spacing-md);
}

.card-footer {
    padding: var(--spacing-md);
    background: var(--gray-50);
    border-top: 1px solid var(--border);
}

/* ========================================================================
   CULTURAL MAP COMPONENTS
   ======================================================================== */

/* Masonry Grid Layout */
.masonry-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
    margin-top: 20px;
}

/* Art Card */
.art-card {
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    padding: 20px;
    box-shadow: var(--shadow);
    transition: var(--transition);
    break-inside: avoid;
    position: relative;
    overflow: hidden;
}

.art-card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--primary) 0%, var(--primary-light) 100%);
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.art-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
}

.art-card:hover::before {
    opacity: 1;
}

/* Art Card Type Badge */
.art-card-type {
    display: inline-block;
    padding: 4px 12px;
    border-radius: var(--radius-full);
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 12px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Art Type Specific Colors */
.art-card[data-type="street-art"] .art-card-type {
    background: color-mix(in srgb, var(--art-street) 15%, transparent);
    color: var(--art-street);
}

.art-card[data-type="music"] .art-card-type {
    background: color-mix(in srgb, var(--art-music) 15%, transparent);
    color: var(--art-music);
}

.art-card[data-type="visual-art"] .art-card-type {
    background: color-mix(in srgb, var(--art-visual) 15%, transparent);
    color: var(--art-visual);
}

.art-card[data-type="design"] .art-card-type {
    background: color-mix(in srgb, var(--art-design) 15%, transparent);
    color: var(--art-design);
}

.art-card[data-type="event"] .art-card-type {
    background: color-mix(in srgb, var(--art-event) 15%, transparent);
    color: var(--art-event);
}

.art-card[data-type="other"] .art-card-type {
    background: color-mix(in srgb, var(--art-other) 15%, transparent);
    color: var(--art-other);
}

/* Art Card Content */
.art-card-title {
    margin: 12px 0;
    font-size: 18px;
    font-weight: 600;
    color: var(--gray-900);
    line-height: 1.4;
}

.art-card-author {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--gray-600);
    font-size: 14px;
    margin-bottom: 12px;
}

.art-card-author svg {
    width: 14px;
    height: 14px;
    opacity: 0.6;
}

.art-card-description {
    color: var(--text-secondary);
    font-size: 14px;
    line-height: 1.6;
    margin: 12px 0;
}

.art-card-location,
.art-card-date {
    font-size: 13px;
    color: var(--gray-500);
    margin: 8px 0;
    display: flex;
    align-items: center;
    gap: 6px;
}

.art-card-location::before {
    content: '📍';
}

.art-card-date::before {
    content: '📅';
}

.art-card-actions {
    display: flex;
    gap: 8px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border-light);
}

.art-card-actions .btn {
    flex: 1;
    font-size: 13px;
    padding: 8px 12px;
}

/* Filter Buttons */
.filter-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 20px 0;
    padding: 16px;
    background: var(--bg-secondary);
    border-radius: var(--radius-md);
}

.filter-btn {
    padding: 8px 16px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    border-radius: var(--radius-full);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition-fast);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.filter-btn:hover {
    border-color: var(--primary);
    background: var(--primary-lightest);
    transform: translateY(-1px);
}

.filter-btn.active {
    background: var(--primary);
    color: var(--text-inverse);
    border-color: var(--primary);
    box-shadow: var(--shadow-sm);
}

.filter-btn .filter-count {
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    padding: 2px 6px;
    border-radius: var(--radius-full);
    font-size: 12px;
    font-weight: 600;
    margin-left: 4px;
}

.filter-btn.active .filter-count {
    background: color-mix(in srgb, var(--bg-primary) 30%, transparent);
}

/* Art Statistics */
#art-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin: 20px 0;
}

#art-stats .stat-card {
    background: var(--bg-elevated);
    padding: 20px;
    border-radius: var(--radius-lg);
    text-align: center;
    box-shadow: var(--shadow);
    border: 1px solid var(--border-light);
    transition: var(--transition);
}

#art-stats .stat-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

#art-stats .stat-value {
    font-size: 32px;
    font-weight: 700;
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    margin-bottom: 4px;
}

#art-stats .stat-label {
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
}

/* Cultural Map Tab */
#tab-cultural-map {
    padding: var(--spacing-lg);
}

#tab-cultural-map .content-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--spacing-lg);
}

#tab-cultural-map .content-header h2 {
    font-size: 24px;
    font-weight: 700;
    color: var(--gray-900);
}

/* ========================================================================
   TABLES
   ======================================================================== */

.table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

.table thead {
    background: var(--gray-50);
}

.table th {
    padding: var(--spacing-sm) var(--spacing-md);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--gray-600);
    text-align: left;
    border-bottom: 2px solid var(--border);
}

.table td {
    padding: var(--spacing-md);
    border-bottom: 1px solid var(--border-light);
    color: var(--text-primary);
}

.table tbody tr {
    transition: var(--transition-fast);
}

.table tbody tr:hover {
    background: var(--gray-50);
}

.table tbody tr:last-child td {
    border-bottom: none;
}

/* Modals moved to static/css/components/modals.css */

/* ========================================================================
   DASHBOARD LAYOUT - FLEX CONTAINERS
   ======================================================================== */

body.dashboard-layout {
    min-height: 100vh;
    margin: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: var(--font-sans);
}

body.dashboard-layout > .dashboard-header {
    flex-shrink: 0;
}

body.dashboard-layout > .main-container {
    flex: 1;
    display: flex;
    min-height: 0;
    min-width: 0;
}

body.dashboard-layout .sidebar {
    flex-shrink: 0;
    min-height: 0;
    overflow-y: auto;
}

body.dashboard-layout .main-content {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

body.dashboard-layout .view-container,
body.dashboard-layout .view-panel {
    flex: 1;
    min-height: 0;
}

body.dashboard-layout .view-panel {
    display: none;
    overflow: auto;
}

body.dashboard-layout .view-panel.active {
    display: flex;
    flex-direction: column;
}

body.dashboard-layout footer,
body.dashboard-layout .dashboard-footer {
    flex-shrink: 0;
    margin-top: auto;
}

/* ========================================================================
   LOADING & STATES
   NOTE: loading overlay/spinner styles moved to static/css/components/loading.css
   ======================================================================== */

/* Empty State */
.empty-state {
    text-align: center;
    padding: var(--spacing-2xl);
    color: var(--text-muted);
}

.empty-state-icon {
    font-size: 48px;
    margin-bottom: var(--spacing-md);
    opacity: 0.3;
}

.empty-state-title {
    font-size: 18px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--spacing-sm);
    font-family: var(--font-sans);
}

.empty-state-text {
    color: var(--text-secondary);
    font-size: 14px;
    font-family: var(--font-sans);
}

/* ========================================================================
   NOTIFICATIONS - FIXED
   ======================================================================== */

.notification {
    box-shadow: var(--shadow-md);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--spacing-md);
    font-family: var(--font-sans);
}

.notification * {
    font-family: var(--font-sans);
}

.notification.success {
    border-left: 3px solid var(--success);
}

.notification.error {
    border-left: 3px solid var(--danger);
}

.notification.warning {
    border-left: 3px solid var(--warning);
}

.notification.info {
    border-left: 3px solid var(--info);
}

/* ========================================================================
   BADGES
   ======================================================================== */

.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    font-size: 12px;
    font-weight: 600;
    border-radius: var(--radius-full);
    line-height: 1.5;
    font-family: var(--font-sans);
}

.badge-primary {
    background: var(--primary);
    color: var(--text-inverse);
}

.badge-success {
    background: var(--success);
    color: var(--text-inverse);
}

.badge-warning {
    background: var(--warning);
    color: var(--text-inverse);
}

.badge-danger {
    background: var(--danger);
    color: var(--text-inverse);
}

.badge-info {
    background: var(--info);
    color: var(--text-inverse);
}

/* ========================================================================
   SIDEBAR
   ======================================================================== */

.sidebar {
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    border-right: 1px solid var(--border);
    overflow-y: auto;
}

@supports (backdrop-filter: blur(20px)) {
    .sidebar {
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
    }
}

.sidebar-section {
    padding: var(--spacing-md);
    border-bottom: 1px solid var(--border);
}

.sidebar-title {
    /* ЕДИНЫЙ канон (ТЗ §6.5 caption / §12, DS-03 2026-07-16): маленький
       капс-ярлык секции — стиль большинства ролей (patron/visionary/
       historian/analyst/citizen). Ролевые дубли удалены; допустимая
       ролевая дельта — ОДНА строка с комментарием (напр. justify-content
       у Аналитика для кнопки-тогглера в заголовке). */
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin: 0 0 var(--spacing-sm) 0;
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    font-family: var(--font-sans);
}

/* ========================================================================
   KPI COMPONENTS
   ======================================================================== */

.kpi-container {
    display: flex;
    gap: var(--spacing-md);
    align-items: center;
}

.kpi-card {
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    padding: var(--spacing-md);
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    box-shadow: var(--shadow);
    transition: var(--transition);
    cursor: pointer;
}

.kpi-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.kpi-value {
    font-size: 24px;
    font-weight: 700;
    color: var(--primary);
    line-height: 1;
    font-family: var(--font-sans);
}

.kpi-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--gray-500);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-family: var(--font-sans);
}

/* Stats Row for Cultural Map */
.stats-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--spacing-md);
    margin-bottom: var(--spacing-lg);
}

.stat-card {
    background: var(--bg-elevated);
    padding: var(--spacing-md);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border-light);
}

.stat-value {
    font-size: 28px;
    font-weight: 700;
    color: var(--primary);
    margin-bottom: 4px;
}

.stat-label {
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* ========================================================================
   PROGRESS
   ======================================================================== */

.progress {
    height: 8px;
    background: var(--gray-200);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.progress-bar {
    height: 100%;
    background: linear-gradient(90deg, var(--primary) 0%, var(--primary-dark) 100%);
    transition: width 0.3s ease;
}

/* ========================================================================
   UTILITIES
   ======================================================================== */

/* Text */
.text-primary { color: var(--text-primary); }
.text-secondary { color: var(--text-secondary); }
.text-muted { color: var(--text-muted); }
.text-danger { color: var(--danger); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-info { color: var(--info); }

.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }

.text-xs { font-size: 12px; }
.text-sm { font-size: 13px; }
.text-md { font-size: 14px; }
.text-lg { font-size: 16px; }
.text-xl { font-size: 18px; }
.text-2xl { font-size: 24px; }

.font-normal { font-weight: 400; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }

/* Spacing */
.m-0 { margin: 0; }
.mt-sm { margin-top: var(--spacing-sm); }
.mt-md { margin-top: var(--spacing-md); }
.mt-lg { margin-top: var(--spacing-lg); }
.mb-sm { margin-bottom: var(--spacing-sm); }
.mb-md { margin-bottom: var(--spacing-md); }
.mb-lg { margin-bottom: var(--spacing-lg); }

.p-0 { padding: 0; }
.p-sm { padding: var(--spacing-sm); }
.p-md { padding: var(--spacing-md); }
.p-lg { padding: var(--spacing-lg); }

/* Display */
.hidden { display: none; }
.block { display: block; }
.flex { display: flex; }
.inline-flex { display: inline-flex; }

.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }

.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }

.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }

.flex-1 { flex: 1; }
.flex-grow { flex-grow: 1; }
.flex-shrink-0 { flex-shrink: 0; }

.gap-xs { gap: var(--spacing-xs); }
.gap-sm { gap: var(--spacing-sm); }
.gap-md { gap: var(--spacing-md); }
.gap-lg { gap: var(--spacing-lg); }

/* Width */
.w-full { width: 100%; }
.w-auto { width: auto; }

/* Borders */
.border { border: 1px solid var(--border); }
.border-t { border-top: 1px solid var(--border); }
.border-b { border-bottom: 1px solid var(--border); }
.border-l { border-left: 1px solid var(--border); }
.border-r { border-right: 1px solid var(--border); }

.rounded { border-radius: var(--radius); }
.rounded-sm { border-radius: var(--radius-sm); }
.rounded-md { border-radius: var(--radius-md); }
.rounded-lg { border-radius: var(--radius-lg); }
.rounded-xl { border-radius: var(--radius-xl); }
.rounded-full { border-radius: var(--radius-full); }

/* Shadows */
.shadow-xs { box-shadow: var(--shadow-xs); }
.shadow-sm { box-shadow: var(--shadow-sm); }
.shadow { box-shadow: var(--shadow); }
.shadow-md { box-shadow: var(--shadow-md); }
.shadow-lg { box-shadow: var(--shadow-lg); }
.shadow-xl { box-shadow: var(--shadow-xl); }
.shadow-2xl { box-shadow: var(--shadow-2xl); }

/* ========================================================================
   RESPONSIVE
   ======================================================================== */

@media (max-width: 1024px) {
    .sidebar {
        width: 280px;
    }

    .masonry-grid {
        grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    }
}

@media (max-width: 768px) {
    :root {
        /* ТЗ §6.2: mobile-хедер 48px (--ds-header-h-mobile) */
        --header-height: var(--ds-header-h-mobile, 48px);
    }

    .app-header {
        padding: 0 var(--spacing-md);
    }

    .kpi-container {
        flex-direction: column;
        align-items: stretch;
    }

    .sidebar {
        display: none;
    }

    /* Cultural Map Mobile */
    .masonry-grid {
        grid-template-columns: 1fr;
        gap: 16px;
    }

    .filter-buttons {
        padding: 12px;
        gap: 8px;
    }

    .filter-btn {
        font-size: 13px;
        padding: 6px 12px;
    }

    #art-stats {
        grid-template-columns: 1fr 1fr;
    }

    .art-card {
        padding: 16px;
    }
}

@media (max-width: 480px) {
    .header-title {
        font-size: 16px;
    }

    /* DS-03 (§12): мобильный компакт-твик .btn удалён — канон components/
       buttons.css (на дашбордах он и так выигрывал каскадом; на standalone-
       страницах без buttons.css твик ужимал кнопки до 13px/8px — ПРОТИВ
       touch-нормы ТЗ §6.4 ≥44px; VR: plans 1.72%, research_templates 0.34% —
       кнопки стали крупнее, эталоны обновлены). */

    .art-card-actions {
        flex-direction: column;
    }

    .art-card-actions .btn {
        width: 100%;
    }

    #art-stats {
        grid-template-columns: 1fr;
    }
}

/* ========================================================================
   UNIVERSAL ACTIVE TAB STYLES (P1.5)
   ======================================================================== */

/* Улучшенные стили для активных табов во всех дашбордах */
.view-tab.active,
.view-switcher-btn.active,
.tab.active,
.central-view-tab.active,
.view-tabs .view-tab.active,
.list-view-tab.active {
    position: relative;
    font-weight: 600;
    box-shadow: 0 2px 4px color-mix(in srgb, var(--status-info) 20%, transparent);
    transform: translateY(-1px);
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Индикатор активного таба (нижняя линия) */
.view-tab.active::before,
.view-switcher-btn.active::before,
.tab.active::after,
.central-view-tab.active::before {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--primary, var(--info));
    transform: scaleX(1);
    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Для табов с вертикальной ориентацией */
.tab.active::after {
    bottom: auto;
    top: 0;
    left: -1px;
    right: auto;
    width: 2px;
    height: 100%;
}

/* Улучшенные hover эффекты для неактивных табов */
.view-tab:not(.active):hover,
.view-switcher-btn:not(.active):hover,
.tab:not(.active):hover,
.central-view-tab:not(.active):hover {
    transform: translateY(-1px);
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ========================================================================
   PRINT
   ======================================================================== */

@media print {
    .app-header,
    .app-footer,
    .sidebar,
    .btn,
    .modal, .modal-overlay {
        display: none !important;
    }
}
/* TEP Wizard Styles */
.tep-wizard {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.tep-tabs {
    display: flex;
    border-bottom: 2px solid var(--border);
    background: var(--bg-secondary);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    overflow: hidden;
}

.tep-tab {
    flex: 1;
    padding: 0.75rem 1rem;
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--text-muted);
    font-weight: 500;
    border-bottom: 3px solid transparent;
    margin-bottom: -2px;
    transition: all 0.3s ease;
    position: relative;
}

.tep-tab:hover {
    background: var(--bg-hover);
    color: var(--text-secondary);
}

.tep-tab.active {
    color: var(--primary);
    background: var(--bg-elevated);
    border-bottom-color: var(--primary);
}

.tep-tab.active::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--color-primary);
}

.tep-tab-content {
    display: none;
    padding: 1.5rem 0;
    animation: tepFadeIn 0.3s ease-out;
}

.tep-tab-content.active {
    display: block;
}

.tep-tab-content h4 {
    margin: 0 0 1.5rem 0;
    color: var(--text-primary);
    font-size: 1.125rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--border);
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.25rem;
}

.tep-modal .form-group {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.tep-modal .form-group label {
    font-weight: 500;
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.tep-modal .form-input {
    padding: 0.625rem 0.875rem;
    border: 1px solid var(--border-strong, var(--border));
    border-radius: var(--radius);
    font-size: 0.95rem;
    transition: all 0.2s ease;
    background: var(--bg-elevated);
    color: var(--text-primary);
}

.tep-modal .form-input:focus {
     border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-success) 15%, transparent);
}

.tep-modal .form-input::placeholder {
    color: var(--text-muted);
    font-size: 0.875rem;
}

.tep-modal .form-group small {
    color: var(--text-muted);
    font-size: 0.8rem;
    margin-top: -0.25rem;
}

/* fadeIn keyframes moved to static/css/components/animations.css */

@keyframes tepFadeOut {
    from {
        opacity: 1;
        transform: translateY(0);
    }
    to {
        opacity: 0;
        transform: translateY(-10px);
    }
}
/* Стили для информации о генерации */
.generation-info {
    margin-top: 1rem;
    padding: 0.75rem;
    background: var(--bg-secondary);
    border-radius: var(--radius-sm);
    border-left: 3px solid var(--primary, var(--info));
}

.generation-info ul {
    margin: 0.5rem 0;
    padding-left: 1.5rem;
}

/* Стили для контейнера статистики мастер-плана */
.masterplan-stats-container {
    margin-top: 1.5rem;
    padding: 1rem;
    background: var(--bg-elevated);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}

.masterplan-stats-container h4 {
    margin-bottom: 1rem;
    color: var(--text-primary);
    border-bottom: 2px solid var(--primary);
    padding-bottom: 0.5rem;
}

.stats-section {
    margin-bottom: 1rem;
    padding: 0.75rem;
    background: var(--bg-light, var(--bg-secondary));
    border-radius: var(--radius-sm);
}

.stats-section h5 {
    margin-bottom: 0.5rem;
    color: var(--text-secondary);
}

.stats-list {
    list-style: none;
    padding: 0;
    margin: 0.5rem 0;
}

.stats-list li {
    padding: 0.25rem 0;
    border-bottom: 1px solid var(--border-color, var(--border));
}

.stats-list li:last-child {
    border-bottom: none;
}

/* Анимация для master-кнопки автопилота мастерпланирования */
#btn-autopilot {
    position: relative;
    overflow: hidden;
    transition: all 0.3s ease;
}

#btn-autopilot:not(:disabled):hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--status-info) 40%, transparent);
}

#btn-autopilot:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* === НОВЫЙ БЛОК: Стили для карты и мудборда v2 === */

/* Улучшенный маркер для арт-объектов */
.art-marker {
    width: 36px;
    height: 36px;
    border-radius: 50% 50% 50% 0;
    transform: rotate(-45deg);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
    border: 2px solid white;
}
.art-marker svg {
    transform: rotate(45deg);
    width: 20px;
    height: 20px;
    color: var(--text-inverse);
}

/* Стандартный маркер для других объектов */
.default-marker {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
    border: 2px solid white;
    box-sizing: border-box; /* ✅ ИСПРАВЛЕНО: учитываем border */
    overflow: hidden; /* ✅ ДОБАВЛЕНО: обрезаем содержимое */
    flex-shrink: 0; /* ✅ ДОБАВЛЕНО: маркер не сжимается */
    text-align: center; /* ✅ ДОБАВЛЕНО: центрирование текста */
    line-height: 1; /* ✅ ДОБАВЛЕНО: выравнивание по вертикали */
}

/* Подсветка карточки при переходе с карты */
.art-card.highlight {
    transition: all 0.5s ease-in-out;
    box-shadow: 0 0 0 3px var(--primary), 0 8px 25px rgba(0,0,0,0.4);
    transform: scale(1.02);
}

/* ========================================================================
   TEXT OVERFLOW & BUTTON UTILITIES (shared across all dashboards)
   ======================================================================== */

/* Clamp text to N lines (use with --line-clamp: N) */
.text-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--line-clamp, 2);
    overflow: hidden;
    word-break: break-word;
}

/* Single-line truncation */
.text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Safe word-wrapping for long content */
.text-wrap-break {
    overflow-wrap: break-word;
    word-break: break-word;
}

/* Map / chart error fallback */
.map-error,
.chart-error {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    min-height: 120px;
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border: 1px dashed var(--border);
    border-radius: var(--radius, 8px);
    font-size: 0.875rem;
    padding: 1rem;
    text-align: center;
}

/* Empty state hint (reusable) */
.empty-state-hint {
    padding: 1rem;
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border: 1px dashed var(--border);
    border-radius: var(--radius, 8px);
    text-align: center;
    font-size: 0.875rem;
    line-height: 1.5;
}

/* Filter / tag pill (reusable) */
.filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.8125rem;
    max-width: 100%;
}

.filter-pill-label {
    color: var(--text-muted);
    white-space: nowrap;
}

.filter-pill-value {
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.filter-pill-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    background: var(--bg-tertiary);
    color: var(--text-muted);
    border-radius: 50%;
    cursor: pointer;
    font-size: 0.75rem;
    line-height: 1;
    flex-shrink: 0;
    transition: background 0.15s, color 0.15s;
}

.filter-pill-remove:hover {
    background: var(--danger);
    color: var(--text-inverse);
}

/* Clue basket (analyst) */
.clue-item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    margin-bottom: 6px;
}

.clue-text {
    flex: 1;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--text-primary);
    overflow-wrap: break-word;
    word-break: break-word;
}

.clue-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: none;
    background: var(--bg-tertiary);
    color: var(--text-muted);
    border-radius: 50%;
    cursor: pointer;
    font-size: 0.875rem;
    line-height: 1;
    flex-shrink: 0;
    transition: background 0.15s, color 0.15s;
}

.clue-remove:hover {
    background: var(--danger);
    color: var(--text-inverse);
}

/* Grant card (producer/patron JS-rendered) */
.grant-card {
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    margin-bottom: 12px;
}

/* Scenario save controls (visionary JS-rendered) */
.scenario-save-controls {
    margin: 10px 0 15px 0;
    padding: 10px;
    background: var(--bg-secondary);
    border-radius: var(--radius-sm);
    border-left: 3px solid var(--primary);
    color: var(--text-primary);
}

/* ============================================================
   Survey wizard (_survey_wizard_steps.html) — form controls и
   геокодер-dropdown.
   Разметка мастера использует Bootstrap-классы (form-control,
   list-group, form-row, col, form-control-sm). Мастер встраивается
   в ДВА места: дашборд урбаниста (bootstrap НЕ грузится) и отдельную
   страницу /admin survey_wizard (bootstrap грузится). dashboard-base.css
   грузится в обоих, поэтому правила здесь — единый источник: поля во всю
   ширину + результаты геокодера как нормальный плавающий dropdown с фоном
   (а не прозрачное наложение на поля «Название/Описание» ниже).
   var(--urbanist-*) с хардкод-fallback — на /admin urbanist.css не загружен.
   ============================================================ */
.survey-wizard label {
    display: block;
    margin-bottom: 6px;
    font-weight: 600;
    color: var(--text-primary);
}

.survey-wizard .form-control {
    display: block;
    width: 100%;
    padding: 10px 14px;
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--text-primary);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    transition: var(--transition-fast);
    box-sizing: border-box;
}

.survey-wizard .form-control:focus {
     border-color: var(--urbanist-primary, var(--color-primary));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-success) 15%, transparent);
}

.survey-wizard .form-control::placeholder {
    color: var(--text-tertiary, var(--gray-400));
}

.survey-wizard textarea.form-control {
    min-height: 96px;
    resize: vertical;
}

.survey-wizard textarea#description {
    min-height: 120px;
}

.survey-wizard .form-control-sm {
    padding: 7px 10px;
    font-size: 0.85rem;
    border-radius: 10px;
}

.survey-wizard small.form-text {
    display: block;
    margin-top: 5px;
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--text-secondary);
}

/* Bootstrap-хелперы, которых нет без bootstrap.min.css */
.survey-wizard .small,
.survey-wizard small {
    font-size: 0.8rem;
    line-height: 1.4;
}

.survey-wizard .text-muted {
    color: var(--text-secondary);
}

.survey-wizard .card-title {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0 0 8px;
}

.survey-wizard .card-text {
    margin: 0 0 10px;
}

/* Подформа «новый город/район»: ряды инпутов в строку (flex, чтобы
   3 поля координат помещались в ряд; перебивает глобальный .form-row grid). */
.survey-wizard .form-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.survey-wizard .form-row > .col {
    flex: 1 1 0;
    min-width: 130px;
}

/* Результаты геокодера — плавающий dropdown, не перекрывает поля ниже.
   Якорится к .form-group (у неё position: relative). */
.survey-wizard #citySearchResults {
    position: absolute;
    top: 100%;
    left: 0;
    width: 100%;
    margin-top: 4px;
    z-index: 1200;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 14px 32px color-mix(in srgb, var(--dark) 18%, transparent);
    max-height: 300px;
    overflow-y: auto;
    padding: 4px;
}

.survey-wizard #citySearchResults .list-group-item {
    display: block;
    width: 100%;
    padding: 10px 12px;
    background: transparent;
    border: none;
    border-radius: var(--radius-md);
    color: var(--text-primary);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.survey-wizard #citySearchResults a.list-group-item-action:hover {
    background: var(--urbanist-primary-light, var(--primary-lightest));
    color: var(--urbanist-primary, var(--color-primary));
}

.survey-wizard #citySearchResults .list-group-item + .list-group-item {
    border-top: 1px solid var(--border);
}

.survey-wizard #citySearchResults .list-group-item-light {
    background: transparent;
    color: var(--text-secondary);
}

/* Подформа нового города поверх соседних полей */
.survey-wizard #newCityForm {
    position: relative;
    z-index: 1100;
}
/* ── A11y (ТЗ §12): видимый фокус для полного keyboard-flow ─────────────────
   :focus-visible срабатывает только при клавиатурной навигации (мышь кольцо
   не рисует). Инпуты с собственным focus-ring (box-shadow) не затрагиваются —
   их правила специфичнее. */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}
[role="tab"]:focus-visible {
    outline-offset: -2px; /* кольцо внутрь — вкладки часто в плотных рядах с overflow */
}

/* §6.9 declutter: нативный accordion сайдбара (канон — перенос inline-стилей
   Аналитика 2026-05-25; у Аналитика остаётся идентичная inline-копия, каскад
   не меняет вид). Используется для «убрать с первого уровня» без потери
   функциональности: id и обработчики внутри details не меняются. */
.sv-accordion { margin-bottom: 8px; }
.sv-accordion > summary {
    cursor: pointer; list-style: none; font-weight: 600; font-size: .95rem;
    padding: 4px 0; display: flex; align-items: center; gap: 6px;
    color: var(--text-primary);
}
.sv-accordion > summary::-webkit-details-marker { display: none; }
.sv-accordion > summary::before {
    content: '▸'; font-size: .8rem; color: var(--text-secondary, var(--gray-500));
    transition: transform .15s ease;
}
.sv-accordion[open] > summary::before { transform: rotate(90deg); }

/* ── Глобальные исследования: полоса шильдиков над картой ─────────────────
   Глобальное исследование живёт сразу в нескольких городах, поэтому у него
   нет одной точки на карте. Отдельная полоса вместо маркера. */
/* Шильдики ПЛАВАЮТ НАД картой, а не занимают полосу над ней. Прежняя
   раскладка (block + border-bottom) сдвигала карту вниз на всю свою высоту —
   на широком экране это была пустая лента во всю ширину ради одного чипа.
   Родитель .map-wrapper уже position: relative (map_overview.css:490).
   Левый верх свободен: NavigationControl в проекте всегда 'top-right'. */
.global-studies-strip {
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 1150;                 /* выше карты, ниже модалок (1500+) */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    max-width: min(320px, calc(100% - 24px));
    max-height: calc(100% - 24px);
    overflow-y: auto;
    padding: 0;
    border: 0;
    background: none;
    /* Контейнер прозрачен для мыши — карта тянется в промежутках между
       чипами; сами чипы события ловят. */
    pointer-events: none;
}
.global-studies-strip[hidden] { display: none; }
.global-study-chip {
    pointer-events: auto;
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    max-width: 100%;
    padding: 7px 13px;
    border: 1px solid var(--border-color, var(--border));
    border-radius: 10px;
    background: var(--bg-primary, var(--white));
    box-shadow: 0 2px 10px color-mix(in srgb, var(--dark) 12%, transparent);
    cursor: pointer;
    text-align: left;
    text-decoration: none;
    /* Только цвет и тень. Подъём `transform: translateY(-1px)` на :hover убран:
       шильдик приподнимался под курсором и возвращался обратно, и это читалось
       как «плавает, но возвращается на место». Отклик на наведение нужен,
       смещение самого элемента — нет. */
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.global-study-chip:hover {
    border-color: var(--accent-color, var(--accent));
    box-shadow: 0 4px 16px color-mix(in srgb, var(--dark) 18%, transparent);
}
.global-study-chip:focus-visible {
    outline: 2px solid var(--accent-color, var(--accent));
    outline-offset: 2px;
}
.global-study-chip__title {
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text-primary, var(--dark));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
.global-study-chip__meta {
    font-size: 0.7rem;
    line-height: 1.3;
    color: var(--text-secondary);
}
.global-studies-strip__error {
    pointer-events: auto;
    font-size: 0.8rem;
    color: var(--danger, var(--danger-dark));
    background: var(--bg-primary, var(--white));
    border: 1px solid var(--danger, var(--danger-dark));
    border-radius: 10px;
    padding: 7px 13px;
    box-shadow: 0 2px 10px color-mix(in srgb, var(--dark) 12%, transparent);
}
/* На узком экране карта и так тесная — чип не должен её закрывать. */
@media (max-width: 640px) {
    .global-studies-strip {
        top: 8px;
        left: 8px;
        max-width: calc(100% - 16px);
        max-height: 40%;
    }
    .global-study-chip { padding: 6px 10px; }
}
/* Удаление — единственное необратимое действие в списке, поэтому оно
   отличается цветом, а не только текстом. */
.gs-danger { color: var(--danger, var(--danger-dark)); }
.gs-danger:hover { background: var(--danger-bg, var(--status-danger-bg)); }

/* ── Глобальные исследования: экран управления («Шаблоны анкет») ─────────
   Цвета берутся из токенов, а не зашиваются в JS: гейт scan_ux_contract
   считает hex в скриптах, и он же ловит нечитаемость в тёмной теме. */
.gs-row-box { padding: 10px 0; border-bottom: 1px solid var(--border-light, var(--bg-tertiary)); }
.gs-panel {
    margin-top: 8px;
    padding: 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.gs-input {
    flex: 1;
    min-width: 180px;
    width: 100%;
    padding: 6px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.gs-error { color: var(--danger, var(--danger-dark)); }

/* По-секционный коллапс сайдбара (макрос _macros.html sidebar_section).
   QA 2026-08-12: правила жили только в citizen_dashboard.css — на дашбордах
   без него (Горинженер, ЖКХ) кнопка ▼ ничего видимого не делала даже с
   обработчиком. JS: shared/collapsible-panels.js (делегированный, один на всех). */
.sidebar-section.collapsible.collapsed .sidebar-section-content {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
}
.sidebar-section.collapsible.collapsed .sidebar-section-toggle {
    transform: rotate(-90deg);
}
/* ── css/components/animations.css ── */
/**
 * Shared keyframe animations — единый источник правды.
 *
 * Все дашборды должны использовать эти анимации вместо
 * дублирования @keyframes в своих CSS файлах.
 *
 * Подключается через dashboard-base.css → @import.
 */

/* ========================================================================
   FADE ANIMATIONS
   ======================================================================== */

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ========================================================================
   SLIDE ANIMATIONS
   ======================================================================== */

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slideInRight {
  /* §7.2/WCAG: без opacity-fade — на промежуточном кадре 0<opacity<1 текст
     композитится с фоном и проваливает контраст (напр. .notification-message
     тоста). Вход из-за правого края уже сообщает появление; fade избыточен. */
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(100%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-100%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ========================================================================
   PULSE / LOADING ANIMATIONS
   ======================================================================== */

/* Универсальный pulse (opacity) — для loading-индикаторов, skeleton, placeholders */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* Pulse с масштабированием — для привлечения внимания (кнопки, badges) */
@keyframes pulse-scale {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

/* Pulse с масштабированием и opacity — для маркеров на карте, иконок */
@keyframes pulse-full {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.05);
    opacity: 0.7;
  }
}

/* ========================================================================
   SPINNER
   ======================================================================== */

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

/* ========================================================================
   SKELETON / SHIMMER
   ======================================================================== */

@keyframes skeleton-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* ========================================================================
   MODAL ANIMATIONS
   ======================================================================== */

@keyframes modalSlideIn {
  from {
    opacity: 0;
    transform: translateY(-30px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}
/* ── css/components/loading.css ── */
/**
 * Loading Overlay + Spinner (shared component)
 * Canonical implementation to avoid conflicts between main.css and dashboard-base.css.
 */

.loading-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay, color-mix(in srgb, var(--bg-primary) 95%, transparent));
  z-index: var(--z-loading);
  display: none;
  align-items: center;
  justify-content: center;
}

@supports (backdrop-filter: blur(10px)) {
  .loading-overlay {
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }
}

.loading-overlay,
.loading-overlay * {
  font-family: var(--font-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif);
}

.loading-overlay.active {
  display: flex;
}

.loading-overlay.show {
  display: flex;
}

.loading-overlay.is-visible {
  display: flex;
}

.loading-content {
  text-align: center;
}

.loading-spinner {
  width: 48px;
  height: 48px;
  border: 4px solid var(--gray-200, var(--border));
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin: 0 auto var(--spacing-md, 16px);
}

.loading-text {
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 500;
}

/* Back-compat aliases used across templates */
.loading-message {
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 500;
}

.loading-spinner-small {
  width: 20px;
  height: 20px;
  border: 3px solid var(--gray-200, var(--border));
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* @keyframes spin — moved to components/animations.css */
/* appSpin is an alias for spin — use spin instead */
/* ── css/map_overview.css ── */
/* Map Overview Modern Styles - Complete Version */

:root {
    /* Цветовые токены (--primary/--success/--warning/--danger) НЕ объявляются
       здесь: единый источник — variables.css + _palette_refresh_2026.css,
       подключаемые в map_overview.html ДО этого файла (Editorial, ТЗ §6.1).
       Локальный indigo-набор удалён 2026-07-16 — он перекрашивал всю
       публичную карту в фиолетовый мимо палитры платформы. */
    --dark: var(--dark);
    --gray-900: var(--text-primary);
    --gray-800: var(--gray-800);
    --gray-700: var(--gray-700);
    --gray-600: var(--text-secondary);
    --gray-500: var(--gray-500);
    --gray-400: var(--gray-400);
    --gray-300: var(--gray-300);
    --gray-200: var(--border);
    --gray-100: var(--bg-tertiary);
    --gray-50: var(--bg-secondary);
    --white: var(--white);

    /* Shadows */
    --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
    --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
    --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
    --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
    --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
    --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
}

/* Reset and Base */
* {
    box-sizing: border-box;
}

body {
    font-family: var(--font-sans);
    background: var(--primary);
    margin: 0;
    padding: 0;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

/* DS-03 delta (осознанная): публичная обзорная карта (/) — самостоятельный
   standalone-layout ВНЕ дашборд-каркаса (_base_dashboard не грузится,
   канонный header dashboard-themes.css сюда не доезжает). Полное
   определение хедера легитимно для этой страницы. */
.dashboard-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 64px;
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
    box-shadow: var(--shadow-sm);
    z-index: 2000;
}

.header-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 100%;
    padding: 0 24px;
    max-width: 1920px;
    margin: 0 auto;
}

.header-left {
    display: flex;
    align-items: center;
    gap: 16px;
    flex: 0 0 auto;
}

.header-title {
    font-size: 20px;
    font-weight: 700;
    color: var(--gray-900);
    margin: 0;
    letter-spacing: -0.02em;
}

/* Center Search Section */
.header-center {
    flex: 1;
    max-width: 480px;
    margin: 0 32px;
}

.search-wrapper {
    position: relative;
    width: 100%;
}

/* Автокомплит поиска: выпадающий список совпадающих городов. */
.search-suggestions {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 4px);
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 10px;
    box-shadow: 0 10px 24px color-mix(in srgb, var(--dark) 12%, transparent);
    max-height: 360px;
    overflow-y: auto;
    z-index: 1100;
    padding: 4px;
}
.search-suggestion {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    color: var(--gray-900, var(--dark));
    transition: background .12s ease;
}
.search-suggestion:hover,
.search-suggestion.is-active {
    background: var(--gray-100);
}
.search-suggestion__title {
    font-size: .92rem;
    font-weight: 600;
    line-height: 1.25;
}
.search-suggestion__meta {
    font-size: .76rem;
    color: var(--gray-500);
    line-height: 1.2;
}
.search-suggestion__type {
    display: inline-block;
    margin-right: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--primary-lightest);
    color: var(--primary);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .02em;
}
.search-suggestions__empty {
    padding: 12px;
    text-align: center;
    color: var(--gray-500);
    font-size: .85rem;
}

.search-icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gray-400);
    pointer-events: none;
    z-index: 1;
}

.search-input-field {
    width: 100%;
    padding: 10px 100px 10px 40px;
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: var(--radius-2xl);
    font-size: 14px;
    font-weight: 400;
    color: var(--gray-900);
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.search-input-field:focus {
     border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 10%, transparent);
}

.search-input-field::placeholder {
    color: var(--gray-400);
}

.search-button {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    padding: 8px 20px;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.search-button:hover:not(:disabled) {
    background: var(--primary-dark);
    box-shadow: var(--shadow-md);
}

.search-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Header Right */
.header-right {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
}

.pro-access-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    color: var(--text-inverse);
    border: none;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: var(--shadow);
}

.pro-access-btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

/* ✅ НОВОЕ: Кнопка создания федерального агента в header */
.federal-agents-create-btn-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--primary) 30%, transparent);
}

.federal-agents-create-btn-header:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 40%, transparent);
    background: var(--primary-dark);
}

/* Main Dashboard Layout */
.dashboard-main {
    position: fixed;
    top: 64px;
    left: 0;
    right: 0;
    bottom: 50px; /* Leave space for footer */
    background: transparent;
}

.main-layout {
    display: flex;
    height: 100%;
}

/* Stats Sidebar */
.stats-sidebar {
    width: 320px;
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-right: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
    padding: 24px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
    height: 100%;
}

/* KPI Panel */
.kpi-panel {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.kpi-card {
    background: var(--white);
    border-radius: var(--radius-lg);
    padding: 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    box-shadow: var(--shadow);
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    cursor: pointer;
}

.kpi-icon {
    font-size: 24px;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--gray-50);
    border-radius: 10px;
}

.kpi-content {
    flex: 1;
}

.kpi-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--gray-500);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}

.kpi-value {
    font-size: 16px;
    font-weight: 600;
    color: var(--gray-900);
    line-height: 1.2;
}

/* Cities Panel */
.cities-panel {
    background: var(--white);
    border-radius: var(--radius-lg);
    padding: 16px;
    box-shadow: var(--shadow);
}

/* КОРЕНЬ «кнопки съезжают вниз»: список новых городов рос по мере загрузки и
   выталкивал «Быстрые действия» за нижний край сайдбара. Высота ограничена,
   лишнее прокручивается ВНУТРИ панели — соседние блоки больше не двигаются. */
.cities-panel .panel-content {
    /* Фиксированная, а не max-height: с max-height панель всё равно росла от
       плейсхолдера «…» к загруженному списку и толкала «Быстрые действия»
       вниз — замерено, сдвиг 108px. Место под три города (бэкенд отдаёт ровно
       три, overview_manager: newest_surveys[:3]) резервируется сразу, поэтому
       после загрузки НИЧЕГО не двигается. Больше трёх — прокрутка внутри. */
    height: 138px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.panel-header {
    font-size: 14px;
    font-weight: 600;
    color: var(--gray-900);
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.panel-title {
    display: flex;
    align-items: center;
    gap: 6px;
}

.panel-content {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Quick Actions Panel */
.quick-actions-panel {
    background: var(--white);
    border-radius: var(--radius-lg);
    padding: 16px;
    box-shadow: var(--shadow);
}

/* Быстрые действия — сетка 2×N вместо колонки: четыре кнопки занимают две
   строки вместо четырёх, панель перестаёт «съезжать» за нижний край. */
.quick-actions-panel .panel-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.quick-action-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 10px;
    background: var(--primary);
    color: var(--text-inverse);
    text-decoration: none;
    border-radius: 9px;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.2;
    min-width: 0;                 /* иначе длинный текст распирает ячейку сетки */
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: var(--shadow-sm);
    /* Отступ снимается: расстояние задаёт gap сетки. Без этого между строками
       набегал двойной зазор. */
    margin-bottom: 0;
}

.quick-action-btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
    background: var(--primary-dark);
}

.quick-action-btn .action-icon {
    font-size: 15px;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    border-radius: var(--radius-md);
    flex-shrink: 0;
}

.quick-action-btn .action-text {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    /* В сетке 2×N ячейка узкая — длинную подпись обрезаем многоточием,
       а не распираем кнопку за край панели. */
    overflow: hidden;
    text-overflow: ellipsis;
}

/* KPI List for cities */
.kpi-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.kpi-list li {
    padding: 8px 12px;
    background: var(--gray-50);
    border-radius: var(--radius-md);
    transition: all 0.2s;
}

.kpi-list li:hover {
    background: var(--gray-100);
}

.kpi-list a {
    color: var(--primary);
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
}

.kpi-list a:hover {
    color: var(--primary-dark);
}

/* Map Wrapper */
.map-wrapper {
    flex: 1;
    position: relative;
    background: var(--bg-tertiary);
}

/* ✅ Academy videos helper */
.academy-videos-toggle {
    position: absolute;
    right: 16px;
    bottom: 70px;
    z-index: 1200;
    border: none;
    cursor: pointer;
    padding: 10px 14px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 13px;
    color: var(--text-inverse);
    background: var(--primary);
    box-shadow: 0 10px 24px color-mix(in srgb, var(--dark) 18%, transparent);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.academy-videos-toggle:hover {
    transform: translateY(-1px);
    box-shadow: 0 14px 28px color-mix(in srgb, var(--dark) 22%, transparent);
}

.academy-videos-panel {
    position: absolute;
    right: 16px;
    bottom: 120px;
    width: min(420px, calc(100% - 32px));
    max-height: min(520px, calc(100% - 140px));
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: var(--radius-xl);
    border: 1px solid color-mix(in srgb, var(--border) 90%, transparent);
    box-shadow: var(--shadow-2xl);
    z-index: 1201;
    overflow: hidden;
}

.academy-videos-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 12%, transparent) 0%, color-mix(in srgb, var(--primary-dark) 12%, transparent) 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
}

.academy-videos-title {
    font-weight: 800;
    font-size: 13px;
    color: var(--gray-900);
}

.academy-videos-close {
    border: none;
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--gray-700);
    font-weight: 800;
}

.academy-videos-close:hover {
    background: var(--gray-50);
}

.academy-videos-body {
    padding: 14px 16px 16px 16px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-height: calc(100% - 52px);
}

.academy-video-card {
    display: grid;
    grid-template-columns: 44px 1fr;
    gap: 12px;
    padding: 12px;
    border-radius: 14px;
    border: 1px solid color-mix(in srgb, var(--border) 90%, transparent);
    background: var(--bg-elevated);
}

.academy-video-thumb {
    width: 44px;
    height: 44px;
    border-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 900;
    color: var(--text-inverse);
    background: var(--primary);
}

.academy-video-name {
    font-weight: 800;
    color: var(--gray-900);
    font-size: 13px;
    line-height: 1.25;
    margin-bottom: 4px;
}

.academy-video-desc {
    color: var(--gray-600);
    font-size: 12px;
    line-height: 1.35;
}

.academy-videos-note {
    margin-top: 4px;
    padding-top: 10px;
    border-top: 1px dashed color-mix(in srgb, var(--gray-300) 90%, transparent);
    font-size: 12px;
    color: var(--gray-600);
}

@media (max-width: 768px) {
    .academy-videos-toggle {
        right: 12px;
        bottom: 58px;
        padding: 10px 12px;
    }
    .academy-videos-panel {
        right: 12px;
        bottom: 106px;
        max-height: min(520px, calc(100% - 120px));
    }
}

#map {
    width: 100%;
    height: 100%;
}

/* Map Loading */
.map-loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: var(--bg-elevated);
    padding: 24px 32px;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2xl);
    font-size: 16px;
    color: var(--gray-700);
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 12px;
}

.map-loading::before {
    content: '';
    width: 24px;
    height: 24px;
    border: 3px solid var(--gray-200);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

/* Custom Marker Styles */
.custom-div-icon {
    background: transparent !important;
    border: none !important;
    pointer-events: auto !important;
    cursor: pointer;
}

/* Ensure MapLibre GL markers with custom elements are always clickable */
.maplibregl-marker {
    pointer-events: auto !important;
    cursor: pointer;
}

.marker-wrapper {
    position: relative;
    width: 40px;
    height: 40px;
    cursor: pointer;
    /* No transform transition — prevents marker jumping during map zoom/pan.
       Hover scale is applied instantly to keep markers firmly pinned. */
}

.marker-wrapper:hover {
    transform: scale(1.15);
}

.marker-pin {
    position: absolute;
    left: 5px;
    top: 4px;
    width: 30px;
    height: 30px;
    background: var(--bg-elevated);
    border-radius: 50% 50% 50% 0;
    transform: rotate(-45deg);
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
    border: 3px solid;
    /* Only animate color/shadow — NOT transform/position.
       'transition: all' was causing markers to jump during zoom/pan
       because it animated the rotate(-45deg) transform. */
    transition: border-color 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
}

.marker-pin::after {
    content: '';
    position: absolute;
    width: 14px;
    height: 14px;
    background: var(--bg-elevated);
    border-radius: 50%;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* Анкеты «в разработке» (БЗ ещё наполняется) — отдельный янтарный пунктир,
   чтобы отличать от готовых городов. Выбор пользователя: показывать всем, цветом. */
.marker-pin--dev {
    border-color: var(--warning) !important;
    border-style: dashed !important;
    background: var(--status-warning-bg) !important;
    opacity: 0.95;
}
.marker-pin--dev::after {
    background: var(--warning);
}
.marker-dev-ribbon {
    position: absolute;
    bottom: -7px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--warning);
    color: var(--white);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.02em;
    padding: 2px 5px;
    border-radius: var(--radius-md);
    white-space: nowrap;
    box-shadow: 0 1px 3px rgba(0,0,0,0.25);
    z-index: 11;
    pointer-events: none;
}
.popup-dev-note {
    margin: 4px 0 6px;
    padding: 5px 8px;
    background: var(--status-warning-bg);
    border-left: 3px solid var(--warning);
    border-radius: var(--radius-sm);
    font-size: 12px;
    color: var(--status-warning);
}

/* «Идёт сбор» (AUDIT-10, решение user 2026-07-29): анкета запущена, ответов 0 —
   бирюзовый пунктир + лента, чтобы отличать и от готовых, и от «в разработке». */
.marker-pin--collect {
    border-color: var(--success) !important;
    border-style: dashed !important;
    background: var(--status-success-bg) !important;
    opacity: 0.95;
}
.marker-pin--collect::after {
    background: var(--success);
}
.marker-collect-ribbon {
    background: var(--success);
}
.popup-collect-note {
    background: var(--status-success-bg);
    border-left-color: var(--success);
    color: var(--status-success);
}

.marker-label {
    position: absolute;
    top: -10px;
    right: -10px;
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-size: 12px;
    font-weight: 700;
    padding: 2px 6px;
    border-radius: 10px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    border: 2px solid;
    min-width: 22px;
    text-align: center;
    z-index: 10;
}

.marker-daily-change {
    position: absolute;
    bottom: -6px;
    right: -6px;
    background: var(--success);
    color: var(--text-inverse);
    font-size: 12px;
    font-weight: 600;
    padding: 2px 5px;
    border-radius: var(--radius-md);
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
    z-index: 11;
}

/* Status Colors */
.status-active {
    border-color: var(--success);
}

.status-active .marker-label {
    background: var(--success);
    color: var(--text-inverse);
    border-color: var(--success);
}

.status-analysis {
    border-color: var(--warning);
}

.status-analysis .marker-label {
    background: var(--warning);
    color: var(--text-inverse);
    border-color: var(--warning);
}

.status-completed {
    border-color: var(--primary);
}

/* ✅ НОВОЕ: Стили для маркеров городов с инсайтами от федеральных агентов */
.insight-city-marker-container {
    background: transparent !important;
    border: none !important;
}

.insight-city-marker {
    position: relative;
    width: 50px;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.insight-marker-pulse {
    position: absolute;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--status-info) 40%, transparent);
    animation: insight-pulse 2s ease-out infinite;
    z-index: 1;
}

.insight-marker-icon {
    position: relative;
    z-index: 2;
    font-size: 24px;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}

.insight-marker-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    background: var(--danger);
    color: var(--text-inverse);
    border-radius: 10px;
    min-width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    padding: 0 5px;
    z-index: 3;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    border: 2px solid white;
}

@keyframes insight-pulse {
    0% {
        transform: scale(1);
        opacity: 1;
    }
    50% {
        transform: scale(1.3);
        opacity: 0.6;
    }
    100% {
        transform: scale(1.6);
        opacity: 0;
    }
}

.status-completed .marker-label {
    background: var(--primary);
    color: var(--text-inverse);
    border-color: var(--primary);
}

.status-default {
    border-color: var(--gray-500);
}

.status-default .marker-label {
    background: var(--gray-500);
    color: var(--text-inverse);
    border-color: var(--gray-500);
}

/* Cluster Styles — контрастный фон и белый текст, чтобы цифры не терялись на карте */
.marker-cluster,
.marker-cluster-num,
.maplibre-cluster {
    background-clip: padding-box;
    border-radius: 20px;
}

.marker-cluster div,
.marker-cluster-num div,
.maplibre-cluster {
    width: 36px;
    height: 36px;
    margin-left: 2px;
    margin-top: 2px;
    text-align: center;
    line-height: 36px;
    border-radius: 18px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-inverse) !important;
    text-shadow: 0 0 1px rgba(0,0,0,0.5), 0 1px 2px rgba(0,0,0,0.3);
}

.marker-cluster span,
.marker-cluster-num span,
.maplibre-cluster span {
    color: var(--text-inverse) !important;
    text-shadow: 0 0 1px rgba(0,0,0,0.5), 0 1px 2px rgba(0,0,0,0.3);
}

.marker-cluster-small {
    background-color: color-mix(in srgb, var(--success) 60%, transparent);
}

.marker-cluster-small div {
    background-color: color-mix(in srgb, var(--success) 95%, transparent);
}

.marker-cluster-medium {
    background-color: color-mix(in srgb, var(--warning) 60%, transparent);
}

.marker-cluster-medium div {
    background-color: color-mix(in srgb, var(--warning) 95%, transparent);
}

.marker-cluster-large {
    background-color: color-mix(in srgb, var(--danger) 60%, transparent);
}

.marker-cluster-large div {
    background-color: color-mix(in srgb, var(--danger) 95%, transparent);
}

/* Fallback для кластеров без размера (maplibre-cluster) — всегда читаемые цифры */
.maplibre-cluster {
    min-width: 36px;
    min-height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: color-mix(in srgb, var(--info) 95%, transparent);
    color: var(--text-inverse) !important;
}

/* Popup Styles */
.leaflet-popup-content-wrapper {
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    border: 1px solid color-mix(in srgb, var(--bg-primary) 80%, transparent);
}

.leaflet-popup-content {
    margin: 16px;
    font-family: var(--font-sans);
    font-size: 14px;
}

.leaflet-popup-content h3 {
    margin: 0 0 12px 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--gray-900);
}

.leaflet-popup-content p {
    margin: 8px 0;
    color: var(--gray-600);
    line-height: 1.5;
}

.popup-links {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--gray-200);
}

/* Popup button fix - Better visibility */
.popup-link {
    display: inline-block;
    padding: 8px 16px;
    background: var(--bg-elevated);
    color: var(--primary);
    text-decoration: none;
    border: 2px solid var(--primary);
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 600;
    transition: all 0.2s;
}

.popup-link:hover {
    background: var(--primary);
    color: var(--text-inverse);
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.popup-surveys-count {
    color: var(--gray-500);
    font-size: 0.9em;
    margin: 0.5em 0;
}

.popup-link-ghost {
    border: none;
    background: none;
    cursor: pointer;
    padding: 0;
    color: inherit;
    font: inherit;
}

.popup-link svg.popup-link-icon {
    vertical-align: middle;
    margin-right: 4px;
}

.city-surveys-empty {
    text-align: center;
    color: var(--gray-500);
    padding: 20px;
}

/* Ссылки лидеров в сайдбаре — переход к цифровому двойнику на карте */
.kpi-leader-link {
    color: var(--primary);
    text-decoration: none;
    font-weight: 600;
}

.kpi-leader-link:hover {
    text-decoration: underline;
}

/* Federal agents insight popup (карта) */
.map-insight-popup {
    padding: 0.5rem;
    max-width: 300px;
}

.map-insight-popup .map-insight-title {
    margin: 0 0 0.5rem 0;
    color: var(--info);
}

.map-insight-popup .map-insight-meta {
    margin: 0.25rem 0;
    font-size: 0.9rem;
    color: var(--gray-500);
}

.map-insight-popup .map-insight-insight {
    margin-top: 0.5rem;
    padding: 0.5rem;
    background: var(--bg-tertiary);
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
}

/* ✅ Панель города (Цифровой двойник) — компактная */
.city-info-panel {
    position: fixed;
    top: 70px;
    right: 16px;
    width: 340px;
    max-height: calc(100vh - 110px);
    background: var(--white);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2xl);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: slideInRight 0.3s ease-out;
}

/* @keyframes slideInRight — moved to components/animations.css */

.city-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    border-bottom: 1px solid color-mix(in srgb, var(--bg-primary) 20%, transparent);
    background: var(--primary);
    color: var(--text-inverse);
    flex-shrink: 0;
}

.city-panel-title {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-inverse);
    line-height: 1.3;
    padding-right: 8px;
}

.city-panel-close {
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    border: none;
    border-radius: var(--radius);
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--text-inverse);
    transition: background 0.2s;
    flex-shrink: 0;
}

.city-panel-close:hover {
    background: color-mix(in srgb, var(--bg-primary) 30%, transparent);
}

.city-panel-content {
    flex: 1;
    overflow-y: auto;
    padding: 10px 12px 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.city-kpi-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
}

.city-kpi-card {
    background: var(--gray-50);
    border-radius: var(--radius-md);
    padding: 8px 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--gray-200);
}

.city-kpi-icon {
    font-size: 1.15rem;
    flex-shrink: 0;
}

.city-kpi-content {
    flex: 1;
    min-width: 0;
}

.city-kpi-value {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--gray-900);
    line-height: 1.2;
}

.city-kpi-label {
    font-size: 0.75rem;
    color: var(--gray-600);
    margin-top: 2px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.city-summary-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
}

.city-summary-card {
    background: var(--white);
    border-radius: var(--radius-md);
    padding: 6px 8px;
    border: 1px solid var(--gray-200);
}

.city-summary-label {
    font-size: 0.75rem;
    color: var(--gray-500);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-bottom: 4px;
}

.city-summary-value {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--gray-900);
}

.city-surveys-section {
    margin-bottom: 0;
}

.city-surveys-title {
    margin: 0 0 8px 0;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--gray-900);
    display: flex;
    align-items: center;
    gap: 6px;
}

.city-surveys-count {
    font-size: 0.75rem;
    color: var(--gray-500);
    font-weight: 500;
}

.city-surveys-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 140px;
    overflow-y: auto;
}

.city-survey-item {
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-md);
    padding: 8px 10px;
    transition: all 0.2s;
    cursor: pointer;
}

.city-survey-item:hover {
    border-color: var(--primary);
    box-shadow: var(--shadow-md);
}

.city-survey-item-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

.city-survey-item-date {
    font-size: 0.75rem;
    color: var(--gray-600);
    font-weight: 500;
}

.city-survey-item-count {
    font-size: 0.75rem;
    color: var(--gray-500);
    background: var(--gray-100);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
}

.city-survey-item-description {
    font-size: 0.75rem;
    color: var(--gray-700);
    line-height: 1.35;
    margin-bottom: 6px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.city-survey-item-note {
    font-size: 0.8rem;
    color: var(--gray-500);
    text-align: center;
}

.city-survey-item-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.75rem;
    color: var(--primary);
    text-decoration: none;
    font-weight: 500;
}

.city-survey-item-link:hover {
    text-decoration: underline;
}

.city-panel-actions {
    padding-top: 8px;
    border-top: 1px solid var(--gray-200);
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex-shrink: 0;
}

.city-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
    transition: all 0.2s;
    border: 1px solid transparent;
    cursor: pointer;
}

.city-action-btn-primary {
    background: var(--primary);
    color: var(--text-inverse);
    border-color: transparent;
}

.city-action-btn-primary:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
    color: var(--text-inverse);
}

.city-action-btn-secondary {
    background: var(--white);
    color: var(--gray-700);
    border-color: var(--gray-200);
}

.city-action-btn-secondary:hover {
    background: var(--gray-50);
    border-color: var(--primary);
    color: var(--primary);
}

/* Quote Container - Modern Design */
.quote-container {
    position: absolute;
    bottom: 60px;
    left: 24px;
    max-width: 420px;
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    padding: 20px;
    padding-top: 36px;
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-xl);
    border: 1px solid color-mix(in srgb, var(--primary) 10%, transparent);
    cursor: move;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 1000;
}

/* Кнопка закрыть/скрыть на карточке цитат */
.quote-close-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.06);
    color: var(--gray-600);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s, color 0.2s;
    z-index: 2;
}
.quote-close-btn:hover {
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
}

.quote-toggle-btn {
    position: absolute;
    bottom: 18px;
    left: 24px;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid var(--gray-200);
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    color: var(--gray-700);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: all 0.2s ease;
    z-index: 1000;
}

.quote-toggle-btn:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.quote-container:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-2xl);
}

.quote-meta {
    font-size: 12px;
    color: var(--gray-500);
    margin-bottom: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 500;
}

.quote-text {
    font-size: 15px;
    line-height: 1.6;
    color: var(--gray-900);
    font-style: italic;
    margin-bottom: 12px;
}

.quote-question {
    font-size: 12px;
    color: var(--gray-600);
    margin-bottom: 12px;
    font-weight: 500;
    padding: 8px;
    background: var(--gray-50);
    border-radius: var(--radius-md);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.quote-details-link {
    display: inline-block;
    color: var(--primary);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    transition: all 0.2s;
}

.quote-details-link:hover {
    color: var(--primary-dark);
    text-decoration: underline;
}

.quote-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: var(--bg-elevated);
    border: 1px solid var(--gray-200);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s;
    font-weight: 600;
    color: var(--gray-500);
    box-shadow: var(--shadow);
}

.quote-nav:hover {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--text-inverse);
    box-shadow: var(--shadow-md);
}

#quote-prev {
    left: -16px;
}

#quote-next {
    right: -16px;
}

/* Professional Footer */
.professional-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 50px;
    background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-top: 1px solid var(--gray-200);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
    z-index: 1500;
    padding: 0 20px;
    display: flex;
    align-items: center;
}

.footer-container {
    display: flex;
    align-items: center;
    height: 100%;
    width: 100%;
    max-width: 1920px;
    margin: 0 auto;
    gap: 20px;
}

.footer-dashboards {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    padding: 0 10px;
    /* 02.09: подвал — ОДНА строка. F-07 ставил здесь flex-wrap: wrap, чтобы
       «Постан…» не срезался краем скролла, — но 12 чипов переносились второй
       строкой поверх карты (подвал фиксированной высоты 50px). Роли убраны из
       полосы в меню .footer-roles-menu, переносить больше нечего.
       overflow-x: auto прежней скролл-полосы снят: он делал и overflow-y auto и
       ОБРЕЗАЛ раскрывающееся вверх меню целиком (проба в Chromium показала
       пустой прямоугольник вместо ролей). */
    flex-wrap: nowrap;
    overflow: visible;
}

.footer-dashboard-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: 20px;
    color: var(--gray-700);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: all 0.2s;
    flex-shrink: 0;
    line-height: 1.4;
}

.footer-dashboard-link:hover {
    background: var(--gray-50);
    border-color: var(--primary);
    color: var(--primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.footer-dashboard-link .dashboard-icon {
    font-size: 14px;
}

.footer-cta {
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    border-color: var(--primary);
    color: var(--text-inverse) !important;
}

.footer-cta:hover {
    background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
    color: var(--text-inverse) !important;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
}

/* Меню «Профессиональные роли» в подвале (02.09). Раскрывается ВВЕРХ над
   полосой: подвал прибит к низу, вниз места нет. Кнопка наследует вид чипа
   .footer-dashboard-link; ссылки внутри — те же .auth-trigger, что раньше
   лежали в полосе. */
.footer-roles {
    position: relative;
    flex-shrink: 0;
}

.footer-roles-toggle {
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
}

.footer-roles-toggle[aria-expanded="true"] {
    background: var(--gray-50);
    border-color: var(--primary);
    color: var(--primary);
}

.footer-roles-caret {
    width: 6px;
    height: 6px;
    margin-top: 3px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-135deg);
    transition: transform 0.2s, margin-top 0.2s;
}

.footer-roles-toggle[aria-expanded="true"] .footer-roles-caret {
    margin-top: -3px;
    transform: rotate(45deg);
}

.footer-roles-menu {
    position: absolute;
    bottom: calc(100% + 10px);
    left: 0;
    display: grid;
    grid-template-columns: repeat(3, minmax(150px, 1fr));
    gap: 4px;
    padding: 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

/* Автор-правило display:grid перебивает UA-правило [hidden]{display:none}
   (одна специфичность, выше источник) — без этой строки меню видно всегда. */
.footer-roles-menu[hidden] {
    display: none;
}

.footer-role-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    color: var(--text-primary);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: background 0.15s, color 0.15s;
}

.footer-role-item:hover,
.footer-role-item:focus-visible {
    background: var(--bg-hover, var(--gray-50));
    color: var(--primary);
}

.footer-role-item .dashboard-icon {
    width: 20px;
    text-align: center;
    font-size: 15px;
}

/* Auth Modal */
.auth-modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: var(--z-modal-backdrop);
    align-items: center;
    justify-content: center;
}

.auth-modal.active {
    display: flex;
    animation: fadeIn 0.2s ease;
}

.auth-modal-content {
    background: var(--bg-elevated);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-2xl);
    max-width: 450px;
    padding: 32px;
    position: relative;
    animation: fadeInUp 0.3s ease;
}

/* @keyframes slideUp — moved to components/animations.css (uses fadeInUp) */

.auth-modal-close {
    position: absolute;
    top: 16px;
    right: 16px;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: var(--gray-500);
    transition: color 0.2s;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
}

.auth-modal-close:hover {
    color: var(--gray-900);
    background: var(--gray-100);
}

.auth-modal-icon {
    width: 64px;
    height: 64px;
    margin: 0 auto 24px;
    background: var(--primary);
    border-radius: var(--radius-xl);
    display: flex;
    align-items: center;
    justify-content: center;
}

.auth-modal-icon svg {
    width: 32px;
    height: 32px;
    color: var(--text-inverse);
}

.auth-modal-title {
    text-align: center;
    font-size: 24px;
    font-weight: 700;
    color: var(--gray-900);
    margin-bottom: 8px;
}

.auth-modal-subtitle {
    text-align: center;
    color: var(--gray-600);
    margin-bottom: 24px;
    line-height: 1.6;
    font-size: 14px;
}

.auth-modal-buttons {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.auth-modal-btn {
    padding: 12px 24px;
    border-radius: 10px;
    font-weight: 600;
    text-align: center;
    transition: all 0.2s;
    cursor: pointer;
    text-decoration: none;
    display: block;
    font-size: 14px;
}

.auth-modal-btn-primary {
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
}

.auth-modal-btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 40%, transparent);
}

.auth-modal-btn-secondary {
    background: var(--bg-elevated);
    color: var(--gray-700);
    border: 2px solid var(--gray-200);
}

.auth-modal-btn-secondary:hover {
    background: var(--gray-50);
    border-color: var(--gray-300);
}

.auth-modal-features {
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--gray-200);
}

.auth-modal-feature {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    color: var(--gray-600);
    font-size: 13px;
}

.auth-modal-feature-icon {
    color: var(--success);
    flex-shrink: 0;
    font-weight: 600;
}

/* Responsive Design */
@media (max-width: 1024px) {
    .stats-sidebar {
        width: 280px;
    }

    .footer-dashboards {
        justify-content: center;
    }
}

@media (max-width: 768px) {
    .dashboard-header {
        height: 56px;
    }

    .dashboard-main {
        top: 56px;
        bottom: 45px;
    }

    .header-container {
        padding: 0 16px;
    }

    /* UX-аудит 2026-07-29 [P0]: поиск города — ГЛАВНОЕ действие публичной
       карты, и на телефоне он был скрыт целиком (лежал за плиткой → sheet →
       поле, то есть за двумя тапами и без визуальной подсказки). Возвращаем
       его в шапку: заголовок ужимается до логотипа-строки, поиск занимает всё
       оставшееся место. Кнопки .header-right по-прежнему в нижнем sheet —
       они второстепенные. */
    .header-center {
        display: flex;
        flex: 1 1 auto;
        min-width: 0;
        margin: 0 8px;
    }

    .header-center .search-wrapper {
        width: 100%;
        min-width: 0;
    }

    .header-center .search-input-field {
        width: 100%;
        min-width: 0;
        font-size: 16px; /* < 16px вызывает автозум при фокусе в iOS Safari */
        /* Под компактную кнопку ниже — иначе текст уезжает под неё */
        padding-right: 84px;
    }

    .header-center .search-button {
        padding: 8px 14px;
        font-size: 13px;
    }

    .header-left {
        flex: 0 0 auto;
        min-width: 0;
    }

    /* Длинное название продукта съедало бы всю строку — на телефоне
       показываем короткую версию (полная остаётся для скринридеров). */
    .header-title {
        font-size: 0;
        white-space: nowrap;
    }

    .header-title::after {
        content: "🌍";
        font-size: 22px;
    }

    /* Три header-кнопки (AI Эксперты / Кочевник / Создать агента) ≈430px не
       влезают в узкую шапку телефона: не переносятся, не сжимаются, вытекают
       вправо и обрезаются `overflow-x:hidden` из mobile-fixes.css — часть
       кнопок физически недостижима. На ≤768px прячем их из шапки и выносим в
       нижний sheet (кнопка ▦ справа-снизу → «Быстрые действия»), как уже
       сделано с поиском и левой панелью. */
    .header-right {
        display: none;
    }

    .stats-sidebar {
        display: none;
    }

    .quote-container {
        bottom: 55px;
        left: 16px;
        right: 16px;
        max-width: none;
    }

    .auth-modal-content {
        margin: 16px;
        max-width: calc(100% - 32px);
        max-height: 90vh;
        max-height: 90dvh;
        overflow-y: auto;
    }

    .professional-footer {
        height: 45px;
        padding: 0 10px;
    }

    .footer-dashboard-link {
        padding: 5px 10px;
        font-size: 12px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }

    .footer-dashboard-link .dashboard-icon {
        font-size: 12px;
    }

    .footer-dashboards {
        gap: 5px;
    }

    /* City-info-panel → bottom-sheet on mobile.
       Full width from the bottom, leaves the map visible above. */
    .city-info-panel {
        top: auto;
        right: 0;
        left: 0;
        bottom: 45px;
        width: 100%;
        max-height: 70vh;
        max-height: 70dvh;
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;
        animation: slideUp 0.3s ease-out;
    }

    /* Leaflet popups must not overflow viewport on narrow screens. */
    .leaflet-popup-content-wrapper,
    .leaflet-popup-content {
        max-width: calc(100vw - 40px) !important;
    }
}

@media (max-width: 480px) {
    /* .header-title { font-size: 16px } УДАЛЕНО 13.08.2026.
       Правило стояло НИЖЕ блока 768px с той же специфичностью (0,1,0) —
       медиа-запрос её не повышает, — и возвращало полное «Карта Городов»
       ровно там, где экран самый узкий. Заголовок распирал .header-left, и
       под текст в поиске города оставалось: 375px → 39.8px, 360px → 24.8px,
       320px → 0px (инпут упирался в min 126px и вылезал из враппера).
       Замерено в headless Chromium на реальной связке CSS+разметки; после
       удаления те же вьюпорты дают 174 / 159 / 119px. Эмодзи-версия из
       блока 768px (font-size: 0 + ::after "🌍") теперь доживает до 320px,
       как и задумывалось комментарием на строке 1847.

       Значение продублировано явно, а не просто убрано: в dashboard-base.css
       (подключается РАНЬШЕ, map_overview.html:25 против :30) лежит такое же
       правило-сирота `.header-title { font-size: 16px }` для 480px. Сейчас
       наш файл выигрывает порядком подключения, но перестановка <link> или
       переезд страницы на дашборд-каркас вернули бы дефект. Явная
       декларация снимает зависимость от порядка. */
    .header-title {
        font-size: 0;
    }

    .pro-access-btn span {
        display: none;
    }

    .quote-container {
        bottom: 50px;
        left: 12px;
        right: 12px;
        padding: 16px;
    }

    /* UX-аудит С-7: на телефоне подпись роли пряталась через display:none, и
       14 ссылок футера превращались в ряд эмодзи БЕЗ доступного имени —
       скринридер зачитывал их как «ссылка», а VoiceOver/TalkBack по эмодзи
       давал «строительный кран». Убираем подпись из ВИДИМОГО слоя, но
       оставляем в дереве доступности: display:none выкидывает узел оттуда,
       clip — нет. Имя ссылки при этом задаёт сама подпись, поэтому ни
       aria-label на 14 элементах, ни JS не нужны — и будущие ссылки получают
       доступное имя автоматически. */
    .footer-dashboard-link span:not(.dashboard-icon) {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }

    .footer-dashboard-link {
        padding: 8px;
    }
}

/* ===== Map overview page overrides (перенесено из inline <style> в шаблоне) ===== */
.professional-footer {
    position: fixed !important;
    bottom: 0 !important;
    left: 0 !important;
    right: 0 !important;
    height: 50px !important;
    background: var(--bg-elevated) !important;
    border-top: 1px solid var(--border) !important;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05) !important;
    z-index: var(--z-fixed, 1400) !important;
    padding: 0 20px !important;
    display: flex !important;
    align-items: center !important;
}

.dashboard-main {
    bottom: 50px !important;
}

.dashboards-footer {
    display: none !important;
}

.federal-agents-toggle-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: var(--radius-md);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    margin-right: 0.75rem;
}

.federal-agents-toggle-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 40%, transparent);
}

.federal-agents-toggle-btn svg {
    flex-shrink: 0;
}

/* author-credit-banner removed — (c) moved to footer */
.footer-copyright {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-left: auto;
    white-space: nowrap;
}
.footer-copyright a:hover { text-decoration: underline; }

/* ===== MOBILE DASHBOARD FAB + BOTTOM SHEET ===== */

/* Вход для гостя в шапке телефона (аудит 02.09). На десктопе скрыт:
   там футер «PRO доступ» и модал роли. */
.header-auth-link {
    display: none;
}

/* Гость в мобильном меню: вход/регистрация первой строкой. */
.mobile-sheet-auth {
    display: flex;
    gap: 8px;
    padding: 0 16px 12px;
}
.mobile-auth-btn {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--primary);
    color: var(--primary);
    background: transparent;
    text-decoration: none;
    font-weight: 600;
    font-size: 15px;
}
.mobile-auth-btn--primary {
    background: var(--primary);
    color: var(--white);
}

.mobile-dashboards-fab {
    display: none; /* shown only on mobile via media query */
    position: fixed;
    bottom: 64px;
    right: 16px;
    z-index: 1500;
    /* Пилюля с подписью «Меню» вместо безымянного круга (аудит 02.09). */
    min-width: 56px;
    height: 56px;
    padding: 0 18px 0 14px;
    gap: 8px;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: var(--white);
    border: none;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--primary) 40%, transparent);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    -webkit-tap-highlight-color: transparent;
    transition: transform 0.2s;
}
.mobile-dashboards-fab:active { transform: scale(0.92); }

.mobile-dashboards-sheet {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    flex-direction: column;
    justify-content: flex-end;
}
.mobile-sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,0.5);
    opacity: 0;
    transition: opacity 0.3s;
}
.mobile-dashboards-sheet.open .mobile-sheet-backdrop { opacity: 1; }

.mobile-sheet-content {
    position: relative;
    background: var(--bg-elevated, var(--gray-800));
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    max-height: 80vh;
    overflow-y: auto;
    padding: 0 16px 24px;
    transform: translateY(100%);
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
    -webkit-overflow-scrolling: touch;
}
.mobile-dashboards-sheet.open .mobile-sheet-content { transform: translateY(0); }

.mobile-sheet-handle {
    width: 36px;
    height: 4px;
    border-radius: var(--radius-xs);
    background: var(--text-muted, var(--gray-400));
    opacity: 0.4;
    margin: 10px auto 8px;
}

.mobile-sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0 12px;
}
.mobile-sheet-header h3 {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text-primary, var(--text-code));
}
.mobile-sheet-close {
    background: none;
    border: none;
    color: var(--text-muted, var(--gray-400));
    font-size: 1.2rem;
    cursor: pointer;
    padding: 4px 8px;
}

.mobile-sheet-city {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    margin-bottom: 12px;
    background: var(--bg-secondary, var(--dark));
    border-radius: 10px;
    font-weight: 600;
    color: var(--text-primary, var(--text-code));
}
.mobile-sheet-city-icon { font-size: 1.1rem; }

.mobile-sheet-search {
    margin-bottom: 14px;
}
.mobile-search-input {
    width: 100%;
    padding: 10px 14px;
    border: 1px solid var(--border, var(--gray-700));
    border-radius: 10px;
    background: var(--bg-secondary, var(--dark));
    color: var(--text-primary, var(--text-code));
    font-size: 0.95rem;
     box-sizing: border-box;
}
.mobile-search-input:focus {
    border-color: var(--primary, var(--info));
}

.mobile-sheet-section {
    margin-bottom: 16px;
}
.mobile-sheet-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, var(--gray-400));
    margin-bottom: 8px;
}

.mobile-sheet-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}
@media (max-width: 480px) {
    .mobile-sheet-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}
@media (max-width: 360px) {
    .mobile-sheet-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

.mobile-dash-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 12px 4px;
    border-radius: var(--radius-lg);
    background: var(--bg-secondary, var(--dark));
    border: 1px solid var(--border, var(--gray-700));
    text-decoration: none;
    color: var(--text-primary, var(--text-code));
    font-size: 0.75rem;
    font-weight: 500;
    text-align: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.15s, border-color 0.15s;
}
.mobile-dash-card:active {
    background: var(--bg-hover, var(--gray-700));
    border-color: var(--primary, var(--info));
}
.mobile-dash-icon { font-size: 1.5rem; }
.mobile-dash-name {
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

/* Only show FAB on mobile */
@media (max-width: 768px) {
    .mobile-dashboards-fab {
        display: flex;
    }
    .mobile-fab-label {
        font-size: 14px;
        font-weight: 600;
        letter-spacing: 0.02em;
    }
    /* «Войти» для гостя рядом с поиском: 44px по высоте, не сжимается. */
    .header-auth-link {
        display: inline-flex;
        align-items: center;
        flex: 0 0 auto;
        min-height: 44px;
        padding: 0 10px;
        margin-left: 4px;
        font-weight: 600;
        font-size: 14px;
        white-space: nowrap;
        color: var(--primary);
        text-decoration: none;
    }
    /* Hide desktop footer dashboard bar on narrow screens — FAB replaces it */
    .professional-footer {
        height: 0 !important;
        padding: 0 !important;
        overflow: hidden !important;
        border: none !important;
    }
    .dashboard-main {
        bottom: 0 !important;
    }
}
/* Discovery (ТЗ 2026-09-06 §6.1): переключатель «Карта | Маркетплейс» в шапке
   и ссылка в панели города. Рендерятся сервером только при включённом контуре. */
.view-switch {
  display: inline-flex; margin-left: 12px; vertical-align: middle;
  border: 1px solid var(--border); border-radius: var(--radius-full); overflow: hidden;
  background: var(--bg-secondary); font-size: .875rem;
}
.view-switch a {
  padding: 6px 12px; min-height: 36px; display: inline-flex; align-items: center;
  color: inherit; text-decoration: none;
}
.view-switch a[aria-current="page"] { background: var(--primary); color: var(--white); }
.view-switch a:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.city-panel-discover { display: inline-block; margin: 4px 0 8px; font-size: .9rem; }
@media (max-width: 768px) {
  /* Не отнимать ширину у мобильного поиска города (ТЗ §16.1): переключатель
     уходит под заголовок отдельной строкой. */
  .view-switch { margin: 6px 0 0; }
}
/* ── css/federal-agents-feed.css ── */
/**
 * Styles for Federal AI Agents Feed Component
 * Версия 2.0: Плавающие окна
 */

/* Main Container */
.federal-agents-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none; /* Позволяет кликать сквозь контейнер */
    /* Must be above the main map header (map_overview.css sets header z-index: 2000) */
    z-index: 2100;
}

/* Floating Window */
.federal-agent-window {
    position: fixed;
    width: 400px;
    max-height: 600px;
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
    display: flex;
    flex-direction: column;
    pointer-events: all; /* Восстанавливаем клики для окон */
    z-index: 2101;
    overflow: hidden;
    animation: windowSlideIn 0.3s ease-out;
}

@keyframes windowSlideIn {
    from {
        opacity: 0;
        transform: translateY(-20px) scale(0.95);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

/* Window Header */
.federal-agent-window-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 1rem;
    background: var(--primary);
    color: var(--text-inverse);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    user-select: none;
    cursor: move;
}

.window-header-left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
}

/* Пиктограмма эксперта в шапке */
.agent-expert-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--bg-primary) 25%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    flex-shrink: 0;
    line-height: 1;
    border: 1px solid color-mix(in srgb, var(--bg-primary) 40%, transparent);
}

.agent-status-icon {
    font-size: 0.75rem;
    flex-shrink: 0;
}

.agent-name {
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.agent-topic-badge {
    font-size: 0.75rem;
    padding: 0.2rem 0.5rem;
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    border-radius: 10px;
    white-space: nowrap;
    flex-shrink: 0;
}

.window-header-controls {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
}

.btn-refresh {
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    border: none;
    color: var(--text-inverse);
    font-size: 1rem;
    cursor: pointer;
    padding: 0;
    width: 24px;
    height: 24px;
    line-height: 1;
    border-radius: var(--radius-sm);
    transition: background 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.btn-refresh:hover {
    background: color-mix(in srgb, var(--bg-primary) 40%, transparent);
}

.btn-minimize,
.btn-close,
.btn-start,
.btn-stop,
.btn-delete {
    background: color-mix(in srgb, var(--bg-primary) 20%, transparent);
    border: none;
    color: var(--text-inverse);
    font-size: 1.2rem;
    cursor: pointer;
    padding: 0;
    width: 24px;
    height: 24px;
    line-height: 1;
    border-radius: var(--radius-sm);
    transition: background 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
}

.btn-minimize:hover,
.btn-close:hover,
.btn-start:hover,
.btn-stop:hover,
.btn-delete:hover {
    background: color-mix(in srgb, var(--bg-primary) 30%, transparent);
}

.btn-start:hover {
    background: color-mix(in srgb, var(--success) 30%, transparent);
}

.btn-stop:hover {
    background: color-mix(in srgb, var(--warning) 30%, transparent);
}

/* Window Body */
.federal-agent-window-body {
    flex: 1;
    overflow-y: auto;
    padding: 1rem;
    max-height: 500px;
}

.agent-feed {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* Строка: аватар эксперта + облако реплики */
.activity-row {
    display: flex;
    gap: 0.5rem;
    align-items: flex-start;
    margin-bottom: 0.75rem;
}

.activity-avatar {
    width: 28px;
    height: 28px;
    min-width: 28px;
    border-radius: 50%;
    background: var(--primary);
    color: var(--text-inverse);
    font-size: 0.75rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    flex-shrink: 0;
    border: 1px solid color-mix(in srgb, var(--bg-primary) 50%, transparent);
}
.activity-row.activity-user .activity-avatar {
    background: linear-gradient(135deg, var(--gray-500) 0%, var(--text-secondary) 100%);
    font-size: 0.75rem;
}

/* Облако реплики (хвостик влево к аватару) */
.activity-bubble {
    position: relative;
    background: color-mix(in srgb, var(--info) 8%, var(--bg-primary));
    border: 1px solid var(--primary-lightest);
    border-radius: var(--radius-lg);
    padding: 0.6rem 0.75rem;
    max-width: calc(100% - 40px);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.activity-bubble::before {
    content: '';
    position: absolute;
    left: -6px;
    top: 10px;
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-right: 8px solid var(--primary-lightest);
}
.activity-bubble::after {
    content: '';
    position: absolute;
    left: -5px;
    top: 11px;
    width: 0;
    height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-right: 7px solid var(--primary-lightest);
}
.activity-bubble-user {
    background: var(--bg-tertiary);
    border-color: var(--border);
}
.activity-bubble-user::before {
    border-right-color: var(--border);
}
.activity-bubble-user::after {
    border-right-color: var(--text-inverse);
}

.activity-row.insight .activity-bubble { border-left: 3px solid var(--warning-light); background: color-mix(in srgb, var(--warning) 8%, var(--bg-primary)); border-color: var(--warning); }
.activity-row.insight .activity-bubble::after { border-right-color: var(--status-warning-bg); }
.activity-row.hypothesis .activity-bubble { border-left: 3px solid var(--info); background: color-mix(in srgb, var(--info) 8%, var(--bg-primary)); border-color: var(--info); }
.activity-row.hypothesis .activity-bubble::after { border-right-color: var(--status-info-bg); }
.activity-row.connection .activity-bubble { border-left: 3px solid var(--success); background: color-mix(in srgb, var(--success) 8%, var(--bg-primary)); border-color: var(--success); }
.activity-row.connection .activity-bubble::after { border-right-color: var(--status-success-bg); }
.activity-row.assistant_message .activity-bubble { border-left: 3px solid var(--primary); border-color: var(--primary-lightest); }
.activity-row.assistant_message .activity-bubble::after { border-right-color: var(--primary-lightest); }

.activity-bubble-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.activity-icon {
    font-size: 0.9rem;
}

.activity-time {
    font-size: 0.75rem;
    color: var(--gray-400);
    white-space: nowrap;
}

.activity-content {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-primary);
    margin-bottom: 0.25rem;
}

.activity-content strong {
    color: var(--primary);
    font-weight: 600;
}

.activity-content .hashtag {
    color: var(--primary);
    font-weight: 500;
}

.activity-metadata {
    margin-top: 0.4rem;
}

.metadata-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.metadata-tags .tag {
    font-size: 0.75rem;
    padding: 0.2rem 0.5rem;
    background: color-mix(in srgb, var(--primary) 8%, var(--bg-primary));
    color: var(--primary);
    border-radius: 10px;
    border: 1px solid var(--border);
}

/* Блок «Спросить эксперта» */
.federal-agent-ask {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}
.federal-agent-ask-label {
    display: block;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 0.5rem;
}
.federal-agent-ask-form {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.federal-agent-ask-input {
    width: 100%;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    font-size: 0.85rem;
    font-family: inherit;
    resize: vertical;
    min-height: 56px;
    transition: border-color 0.2s;
}
.federal-agent-ask-input:focus {
     border-color: var(--primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 15%, transparent);
}
.federal-agent-ask-input::placeholder {
    color: var(--text-muted);
}
.federal-agent-ask-send {
    align-self: flex-end;
    padding: 0.5rem 1rem;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: var(--radius-md);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.2s, opacity 0.2s;
}
.federal-agent-ask-send:hover {
    transform: translateY(-1px);
    opacity: 0.95;
}
.federal-agent-ask-send:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    transform: none;
}

/* Loading & Empty States */
.loading,
.no-activities,
.error-message {
    text-align: center;
    padding: 2rem 1rem;
    color: var(--gray-400);
    font-size: 0.85rem;
}

.error-message {
    color: var(--danger);
    background: var(--status-danger-bg);
    border-radius: var(--radius);
    padding: 1rem;
}

/* Scrollbar */
.federal-agent-window-body::-webkit-scrollbar {
    width: 6px;
}

.federal-agent-window-body::-webkit-scrollbar-track {
    background: var(--bg-tertiary);
    border-radius: 3px;
}

.federal-agent-window-body::-webkit-scrollbar-thumb {
    background: var(--gray-500);
    border-radius: 3px;
}

.federal-agent-window-body::-webkit-scrollbar-thumb:hover {
    background: var(--text-secondary);
}

/* Responsive */
@media (max-width: 768px) {
    .federal-agent-window {
        width: calc(100vw - 20px);
        max-width: 400px;
        max-height: calc(100vh - 100px);
    }
}

/* Toggle Button (for main page) */
.federal-agents-toggle-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: var(--radius-md);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s;
}

.federal-agents-toggle-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.federal-agents-toggle-btn svg {
    flex-shrink: 0;
}

/* Create Agent Button */
.federal-agents-create-btn {
    position: fixed;
    bottom: 20px;
    right: 20px;
    padding: 0.75rem 1.5rem;
    background: var(--primary);
    color: var(--text-inverse);
    border: none;
    border-radius: 25px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--success) 40%, transparent);
    transition: transform 0.2s, box-shadow 0.2s;
    z-index: 1002;
}

.federal-agents-create-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px color-mix(in srgb, var(--success) 50%, transparent);
}

/* Create Agent Modal */
.federal-agent-create-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(4px);
}

.modal-content {
    position: relative;
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    width: 90%;
    max-width: 500px;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    z-index: 1;
    animation: faf-modalSlideIn 0.3s ease-out;
}

@keyframes faf-modalSlideIn {
    from {
        opacity: 0;
        transform: translateY(-20px) scale(0.95);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1.5rem;
    border-bottom: 1px solid var(--border);
}

.modal-header h3 {
    margin: 0;
    font-size: 1.25rem;
    color: var(--text-primary);
}

.modal-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    color: var(--gray-400);
    cursor: pointer;
    padding: 0;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: background 0.2s;
}

.modal-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}

.modal-body {
    padding: 1.5rem;
}

.form-group {
    margin-bottom: 1.25rem;
}

.form-group label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 500;
    color: var(--text-primary);
    font-size: 0.9rem;
}

.form-group input,
.form-group textarea {
    width: 100%;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-family: inherit;
    transition: border-color 0.2s;
}

.form-group input:focus,
.form-group textarea:focus {
     border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 10%, transparent);
}

.form-group textarea {
    resize: vertical;
    min-height: 80px;
}

.form-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
    margin-top: 1.5rem;
}

.btn-cancel,
.btn-create {
    padding: 0.75rem 1.5rem;
    border: none;
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

.btn-cancel {
    background: var(--bg-secondary);
    color: var(--text-muted);
}

.btn-cancel:hover {
    background: var(--bg-hover);
}

.btn-create {
    background: var(--primary);
    color: var(--text-inverse);
}

.btn-create:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.btn-create:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none;
}
/* ── css/mobile-fixes.css ── */
/* Global mobile safeguards.
   Loaded after component CSS in _base_dashboard.html so these rules
   act as last-resort caps without rewriting every dashboard. */

/* iOS dynamic viewport: prevent 100vh content from being clipped
   by the address bar. Only applied where the dashboard already sets
   100vh — this extends it with the dvh fallback. */
@supports (height: 100dvh) {
    .dashboard-container,
    .dashboard-layout,
    .pulse-shell,
    .map-fullscreen {
        min-height: 100dvh;
    }
}

/* ---- Modals: never wider/taller than the viewport ---- */
.modal,
.modal-dialog,
.modal-content,
[class*="modal-dialog"] {
    max-width: min(95vw, var(--modal-max-width, 1200px));
}

@media (max-width: 640px) {
    .modal,
    .modal-dialog,
    .modal-content,
    [class*="modal-dialog"] {
        width: 95vw !important;
        max-width: 95vw !important;
        max-height: 90vh;
        max-height: 90dvh;
        margin: 16px auto;
    }
    .modal-body {
        overflow-y: auto;
    }
}

/* ---- Touch targets: buttons and links should be at least 44×44 ---- */
@media (max-width: 768px) and (pointer: coarse) {
    button:not(.nav-sidebar-toggle):not(.close-btn):not(.icon-btn-sm):not(.panel-hide-btn),
    .btn,
    a.btn,
    input[type="button"],
    input[type="submit"],
    .footer-dashboard-link {
        min-height: 44px;
    }
}

/* ---- Tables: force horizontal scroll if author forgot a wrapper ---- */
@media (max-width: 768px) {
    .content-area table,
    .dashboard-main table:not(.no-mobile-scroll),
    .widget-content table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 100%;
    }
}

/* ---- Prevent horizontal page scroll from rogue wide children ---- */
@media (max-width: 640px) {
    body {
        overflow-x: hidden;
    }
    img, video, canvas, iframe {
        max-width: 100%;
        height: auto;
    }
}

/* ---- Leaflet/MapLibre popups: cap width on narrow screens ---- */
@media (max-width: 640px) {
    .leaflet-popup-content-wrapper,
    .leaflet-popup-content,
    .maplibregl-popup-content {
        max-width: calc(100vw - 32px) !important;
        box-sizing: border-box;
    }
}

/* ---- Nav sidebar: never take more than 85vw when opened on mobile ---- */
@media (max-width: 640px) {
    .nav-sidebar.mobile-open,
    .dashboard-sidebar-left.mobile-open,
    .dashboard-sidebar-right.mobile-open {
        max-width: 85vw;
    }
}

/* ---- Widget grid: fall back to one column on very narrow devices.
   Only affects grids that use the `widget-grid` contract; other
   layouts keep their explicit columns. */
@media (max-width: 480px) {
    .widget-grid,
    .widgets-grid {
        grid-template-columns: 1fr !important;
    }
}

/* ---- Minimum readable font size for body copy on mobile ---- */
@media (max-width: 480px) {
    .widget-content,
    .card-body,
    .dashboard-main p,
    .dashboard-main li {
        font-size: max(13px, 0.85rem);
    }
}

/* ---- Header-right overflow safety на узких экранах ----
   При насыщенных header-actions (copilot + city badge + 2-3 кнопки)
   header-right может переполняться. Решение: горизонтальный скролл
   как fallback (не идеально, но лучше обрезанной кнопки). */
@media (max-width: 640px) {
    body[data-dashboard-theme] .dashboard-header .header-right {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 70vw;
        scrollbar-width: none;
    }
    body[data-dashboard-theme] .dashboard-header .header-right::-webkit-scrollbar {
        display: none;
    }
}

/* ---- Compact button padding в header на самых узких экранах ----
   Стандарт touch-target 44px переопределён только для header-кнопок
   (40px height вписывается в header-height-mobile). Но padding можно
   сжать чтобы влезали 3-4 кнопки. */
@media (max-width: 420px) {
    body[data-dashboard-theme] .dashboard-header .btn-sm,
    body[data-dashboard-theme] .dashboard-header .btn {
        padding-left: 10px;
        padding-right: 10px;
    }
}

/* =========================================================================
 * Mobile UX audit 2026-05-16 — устранение P0/P1 проблем на iPhone (375px).
 * До этого header-right делал overflow-x: auto (показывал scroll-bar — UX-грязь).
 * Теперь: на <640px text-label кнопок скрывается, остаётся только icon.
 * ========================================================================= */

/* ---- Header-right: icon-only кнопки на узких экранах ---- */
@media (max-width: 640px) {
    /* Кнопки в header'е — компактные, иконка + ничего */
    body[data-dashboard-theme] .dashboard-header .header-right .btn,
    body[data-dashboard-theme] .dashboard-header .header-right .btn-sm,
    .profile-header-action-btn {
        padding: 8px 10px;
        min-height: 36px;
        font-size: 0.85rem;
    }
    /* LLM-балансный виджет: показываем только иконку и цифру */
    .dashboard-header .llm-balance-widget {
        gap: 4px;
        padding: 4px 8px;
        font-size: 0.75rem;
    }
    .dashboard-header .llm-balance-widget .label,
    .dashboard-header .llm-balance-widget .cost,
    .dashboard-header .llm-balance-widget .details-link {
        display: none;
    }
    /* User-info-panel: имя пользователя скрываем, оставляем avatar */
    .dashboard-header .user-info-panel .user-name,
    .dashboard-header .user-info-panel .user-roles {
        display: none;
    }
    /* Header больше не должен иметь горизонтальный scroll (visible scrollbar
       — это код-смесь на iPhone). Если кнопки не помещаются — wrap. */
    body[data-dashboard-theme] .dashboard-header .header-right {
        flex-wrap: wrap;
        overflow-x: visible;
        max-width: 100%;
        row-gap: 4px;
    }
}

/* ---- Profile-v2 header actions: компактнее на мобиле ---- */
@media (max-width: 480px) {
    .profile-header-actions-inline {
        gap: 0.25rem;
    }
    .profile-header-action-btn {
        padding: 6px 8px;
        font-size: 0.75rem;
        min-height: 34px;
    }
    /* Stats-блок: на 375px показываем только 2 главные метрики. */
    .profile-header-stats-inline .stat-item-inline:nth-child(n+3) {
        display: none;
    }
    /* Avatar shrink — экран узкий, экономим место. */
    .profile-header-avatar {
        width: 36px;
        height: 36px;
    }
    /* Роли — только 1 chip + counter (раньше 3 chip + counter). */
    .profile-header-role-chips .profile-header-role-chip:nth-child(n+2):not(.profile-header-role-chip--more) {
        display: none;
    }
}

/* ---- Methodologist editor toolbar: добавить media query (раньше не было) ---- */
@media (max-width: 640px) {
    /* Toolbar редактора модели методолога — 6 кнопок (↶ ↷ ✏️ 💾 ⋯).
       Раньше .model-actions имела gap:10px без media → на 375px кнопки
       перепрыгивали. Теперь компактный gap + flex-wrap. */
    body[data-dashboard-theme="methodologist"] .model-actions {
        gap: 4px;
        flex-wrap: wrap;
        row-gap: 4px;
    }
    body[data-dashboard-theme="methodologist"] .model-actions .btn,
    body[data-dashboard-theme="methodologist"] .model-actions .btn-sm {
        padding: 6px 8px;
        font-size: 0.78rem;
        min-height: 34px;
    }
}

/* ---- Strategist tabs nav: горизонтальный scroll с snap ---- */
@media (max-width: 640px) {
    body[data-dashboard-theme="strategist"] .sv-tab-group,
    body[data-dashboard-theme="strategist"] .strategist-tabs {
        overflow-x: auto;
        flex-wrap: nowrap;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    body[data-dashboard-theme="strategist"] .sv-tab-group::-webkit-scrollbar,
    body[data-dashboard-theme="strategist"] .strategist-tabs::-webkit-scrollbar {
        display: none;
    }
    body[data-dashboard-theme="strategist"] .sv-tab-group > *,
    body[data-dashboard-theme="strategist"] .strategist-tabs > * {
        scroll-snap-align: start;
        flex-shrink: 0;
    }
}
