:root { color-scheme: light; --font-body: Arial, "PingFang SC", "Microsoft YaHei", sans-serif; --bg: #f6f7f9; --panel-bg: #ffffff; --panel-soft: #f3f4f6; --border-subtle: #e5e7eb; --text: #111827; --muted: #6b7280; --primary: #2563eb; --primary-weak: #e0e7ff; --primary-border: #93c5fd; --button-bg: #ffffff; --button-hover-bg: #eef2ff; --button-muted-bg: #f9fafb; --canvas-bg: #ffffff; --warning: #f59e0b; --danger: #ef4444; --success: #10b981; --danger-weak: #fef2f2; --danger-border: #fecaca; --warning-weak: #fffbeb; --radius: 6px; --control-font-size: 12px; --table-head-bg: var(--panel-soft); --table-head-text: var(--text); --table-row-border: var(--border-subtle); --table-row-hover: var(--panel-soft); --table-row-alt: var(--button-muted-bg); --space-1: 4px; --space-2: 8px; --space-3: 12px; --control-height: 32px; --control-height-sm: 28px; --dialog-width: 640px; --dialog-lg-width: 920px; --dialog-label-width: 140px; --form-label-width: 110px; --dialog-body-max-height: 65vh; --focus-ring: 0 0 0 2px var(--primary-border); --transition-fast: 0.15s ease; --transition-mid: 0.2s ease; } :root[data-theme="dark"] { color-scheme: dark; --bg: #0f172a; --panel-bg: #111827; --panel-soft: #1f2937; --border-subtle: #374151; --text: #e2e8f0; --muted: #94a3b8; --primary: #60a5fa; --primary-weak: #1e3a8a; --primary-border: #3b82f6; --button-bg: #111827; --button-hover-bg: #1f2937; --button-muted-bg: #0b1220; --canvas-bg: #111827; --warning: #fbbf24; --danger: #f87171; --success: #34d399; --danger-weak: #3f1d1d; --danger-border: #7f1d1d; --warning-weak: #3a2a09; } :root[data-theme="red"] { color-scheme: light; --bg: #fff5f5; --panel-bg: #ffffff; --panel-soft: #ffe4e6; --border-subtle: #ffe4e6; --text: #7f1d1d; --muted: #b91c1c; --primary: #dc2626; --primary-weak: #fee2e2; --primary-border: #fca5a5; --button-bg: #ffffff; --button-hover-bg: #fff1f2; --button-muted-bg: #fff5f5; --canvas-bg: #ffffff; --danger: #dc2626; } :root[data-theme="orange"] { color-scheme: light; --bg: #fff7ed; --panel-bg: #ffffff; --panel-soft: #ffedd5; --border-subtle: #ffedd5; --text: #7c2d12; --muted: #c2410c; --primary: #ea580c; --primary-weak: #ffedd5; --primary-border: #fdba74; --button-bg: #ffffff; --button-hover-bg: #fff1e6; --button-muted-bg: #fff7ed; --canvas-bg: #ffffff; --danger: #ea580c; } :root[data-theme="yellow"] { color-scheme: light; --bg: #fffbeb; --panel-bg: #ffffff; --panel-soft: #fef3c7; --border-subtle: #fef3c7; --text: #78350f; --muted: #a16207; --primary: #ca8a04; --primary-weak: #fef3c7; --primary-border: #fcd34d; --button-bg: #ffffff; --button-hover-bg: #fffbeb; --button-muted-bg: #fffbeb; --canvas-bg: #ffffff; --danger: #ca8a04; --success: #16a34a; } :root[data-theme="green"] { color-scheme: light; --bg: #f0fdf4; --panel-bg: #ffffff; --panel-soft: #dcfce7; --border-subtle: #dcfce7; --text: #14532d; --muted: #166534; --primary: #16a34a; --primary-weak: #dcfce7; --primary-border: #86efac; --button-bg: #ffffff; --button-hover-bg: #dcfce7; --button-muted-bg: #f0fdf4; --canvas-bg: #ffffff; --success: #16a34a; } :root[data-theme="cyan"] { color-scheme: light; --bg: #ecfeff; --panel-bg: #ffffff; --panel-soft: #cffafe; --border-subtle: #cffafe; --text: #155e75; --muted: #0e7490; --primary: #0891b2; --primary-weak: #cffafe; --primary-border: #67e8f9; --button-bg: #ffffff; --button-hover-bg: #cffafe; --button-muted-bg: #ecfeff; --canvas-bg: #ffffff; } :root[data-theme="blue"] { color-scheme: light; --bg: #eff6ff; --panel-bg: #ffffff; --panel-soft: #dbeafe; --border-subtle: #dbeafe; --text: #1e3a8a; --muted: #1d4ed8; --primary: #2563eb; --primary-weak: #dbeafe; --primary-border: #93c5fd; --button-bg: #ffffff; --button-hover-bg: #dbeafe; --button-muted-bg: #eff6ff; --canvas-bg: #ffffff; } :root[data-theme="purple"] { color-scheme: light; --bg: #f5f3ff; --panel-bg: #ffffff; --panel-soft: #ede9fe; --border-subtle: #ede9fe; --text: #4c1d95; --muted: #6d28d9; --primary: #9333ea; --primary-weak: #ede9fe; --primary-border: #c4b5fd; --button-bg: #ffffff; --button-hover-bg: #ede9fe; --button-muted-bg: #f5f3ff; --canvas-bg: #ffffff; } * { box-sizing: border-box; } html, body { height: 100%; } body { margin: 0; font-family: var(--font-body); font-size: 14px; color: var(--text); background: var(--bg); overflow: hidden; line-height: 1.5; } ::selection { background: var(--primary-weak); color: var(--text); } .app { min-height: 100vh; height: 100vh; display: flex; flex-direction: column; } .app-header, .app-footer { background: var(--panel-bg); border-bottom: 1px solid var(--border-subtle); } .app-header { padding: var(--space-2) var(--space-2); display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); } .app-brand { display: flex; flex-direction: column; gap: 2px; } .app-title { font-size: 16px; font-weight: 600; letter-spacing: 0.02em; } .app-subtitle { font-size: 12px; color: var(--muted); } .app-header-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; justify-content: flex-end; } .app-actions { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; } .app-container { display: grid; --toolbar-width: 240px; --property-width: 320px; grid-template-columns: var(--toolbar-width) minmax(0, 1fr) var(--property-width); grid-template-areas: "toolbar map property"; grid-template-rows: minmax(0, 1fr); gap: var(--space-1); padding: var(--space-2); flex: 1 1 auto; min-height: 0; position: relative; } .toolbar { grid-area: toolbar; min-height: 0; } .map { grid-area: map; min-width: 0; min-height: 0; } .property { grid-area: property; min-height: 0; } .panel { background: var(--panel-bg); border: 1px solid var(--border-subtle); border-radius: var(--radius); display: flex; flex-direction: column; min-height: 0; overflow: hidden; transition: border-color var(--transition-fast); } .panel:focus-within { border-color: var(--primary-border); box-shadow: var(--focus-ring); } .panel-header { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border-subtle); font-weight: 600; background: var(--panel-soft); display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); letter-spacing: 0.02em; } .panel-header-actions { display: flex; align-items: center; gap: var(--space-1); } .panel-action.panel-collapse { min-width: 32px; padding: 4px 6px; font-weight: 700; line-height: 1; } .panel.is-collapsed .panel-body { display: none; } .panel.is-collapsed .panel-header { padding: var(--space-2) var(--space-1); flex-direction: column; align-items: center; justify-content: center; gap: var(--space-1); } .panel.is-collapsed .panel-header > span { writing-mode: vertical-rl; text-orientation: mixed; white-space: nowrap; } .panel.is-collapsed .panel-header-actions { flex-direction: column; } .panel.is-collapsed .panel-action { padding: 4px 6px; } .panel-body { padding: var(--space-2); overflow: auto; min-height: 0; flex: 1 1 auto; } .property .panel-body { overflow-x: hidden; } .settings-panel .panel-body { overflow: hidden; display: flex; flex-direction: column; gap: var(--space-2); } .settings-panel .tabProperty { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; gap: var(--space-2); overflow: auto; } .panel-actions { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; } .settings-panel { position: fixed; top: calc(var(--space-2) + 64px); right: var(--space-2); width: 600px; height: calc(80vh - (var(--space-2) + 64px)); z-index: 100; } .settings-panel[hidden] { display: none; } .layer-panel-inline, .group-panel-inline { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-1); margin: 0; flex: 1 1 auto; min-height: 0; } .layer-list, .group-list { display: flex; flex-direction: column; gap: var(--space-1); overflow: auto; flex: 1 1 auto; min-height: 0; padding-right: 2px; } .layer-item, .group-item { display: flex; align-items: center; gap: var(--space-1); padding: var(--space-1); border: 1px solid var(--border-subtle); border-radius: var(--radius); background: var(--button-muted-bg); } .layer-item.is-active, .group-item.is-active { border-color: var(--primary-border); background: var(--primary-weak); } .layer-item .layer-name, .group-item .group-name { flex: 1; text-align: left; background: transparent; border: none; color: var(--text); padding: 0 var(--space-1); cursor: pointer; } .layer-count, .group-count { min-width: 28px; text-align: center; font-size: 12px; color: var(--muted); padding: 0 var(--space-1); } .layer-input, .group-input { flex: 1; min-width: 0; padding: 2px var(--space-1); border-radius: var(--radius); border: 1px solid var(--border-subtle); background: var(--panel-bg); color: var(--text); font: inherit; display: none; } .layer-item .layer-toggle { min-width: 36px; } .layer-item.is-editing .layer-name, .layer-item.is-editing .layer-count, .group-item.is-editing .group-name, .group-item.is-editing .group-count { display: none; } .layer-item.is-editing .layer-input, .group-item.is-editing .group-input { display: block; } .layer-item .layer-toggle[aria-pressed="true"] { background: var(--button-bg); border-color: var(--primary-border); color: var(--text); } .toolbar .panel-body { display: flex; flex-direction: column; gap: var(--space-2); } .toolbar-search { display: flex; align-items: center; gap: var(--space-1); } .toolbar-search input { flex: 1; min-width: 0; } .toolbar-filters { display: flex; flex-wrap: wrap; gap: var(--space-1); } .tool-empty { display: none; padding: var(--space-2); border-radius: var(--radius); background: var(--danger-weak); border: 1px solid var(--danger-border); color: var(--danger); font-size: 12px; } .is-hidden { display: none !important; } .tool-group { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-1); border-radius: calc(var(--radius) + 2px); border: 1px solid transparent; } .tool-group:hover, .tool-group:focus-within { border-color: var(--border-subtle); background: var(--panel-soft); } .tool-group-title { font-size: 12px; color: var(--muted); } .tool-group-body { display: flex; flex-direction: column; gap: var(--space-1); } button { padding: 6px 10px; border: 1px solid var(--border-subtle); border-radius: calc(var(--radius) + 2px); background: var(--button-bg); color: var(--text); cursor: pointer; min-height: var(--control-height); font-size: var(--control-font-size); font-family: inherit; font-weight: 500; line-height: 1.2; transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); } button:hover { border-color: var(--primary-border); color: var(--primary); background: var(--button-hover-bg); } button:disabled { cursor: not-allowed; opacity: 0.6; } button:active { background: var(--button-hover-bg); } .command { width: 100%; text-align: left; } .command.switch, .action.active { background: var(--primary-weak); border-color: var(--primary-border); color: var(--primary); } .command.switch.active, .action.primary { background: var(--primary); border-color: var(--primary); color: #ffffff; } .action { padding: 6px 12px; } .action-select { flex: 0 0 auto; padding: 6px 10px; border-radius: var(--radius); font-size: var(--control-font-size); min-width: 110px; min-height: var(--control-height); background: var(--button-bg); color: var(--text); border: 1px solid var(--border-subtle); transition: border-color var(--transition-fast), background var(--transition-fast); } .action-select:hover { border-color: var(--primary-border); } .action-select:focus { border-color: var(--primary); background: var(--panel-bg); } .chip { padding: 4px 10px; border-radius: var(--radius); color: var(--muted); font-size: 12px; min-height: var(--control-height-sm); } .chip.active { background: var(--primary-weak); border-color: var(--primary-border); color: var(--primary); } .map .panel-body { display: flex; flex-direction: column; gap: var(--space-1); } .map-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); } .map-title { display: flex; align-items: center; gap: var(--space-1); } .map-meta { font-size: 12px; color: var(--muted); } .map-header-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font-size: 12px; font-weight: 400; } .map-quick-actions { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; } .map-search { display: flex; align-items: center; gap: var(--space-1); } .map-controls { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; } .footer-toolbar { display: flex; gap: var(--space-1); flex-wrap: wrap; } .footer-toolbar .command, .map-controls .command { width: auto; } .footer-toolbar.end { margin-left: auto; } #map { flex: 1 1 auto; border: 1px solid var(--border-subtle); border-radius: var(--radius); background: var(--panel-bg); min-height: 0; overflow: hidden; display: flex; } #map:focus-within { border-color: var(--primary-border); } #canvas { width: 100%; height: 100%; display: block; touch-action: none; flex: 1 1 auto; min-height: 0; background: var(--canvas-bg); border: none; border-radius: 0; } #canvas:focus-visible { outline: 2px solid var(--primary-border); outline-offset: 1px; } fieldset { border: 1px solid var(--border-subtle); border-radius: var(--radius); margin: 0 0 var(--space-2) 0; padding: var(--space-2); background: transparent; } legend { padding: 0 var(--space-1); color: var(--muted); font-size: 12px; font-weight: 600; } form fieldset > div:not(.layer-panel-inline):not(.group-panel-inline) { display: flex; align-items: flex-start; gap: var(--space-2); margin: var(--space-1) 0; flex-wrap: wrap; } form label { width: var(--form-label-width); text-align: right; color: var(--muted); align-self: center; } input, select, textarea { flex: 1; min-width: 0; padding: 4px 6px; border: 1px solid var(--border-subtle); border-radius: var(--radius); background: var(--button-bg); color: var(--text); font-size: var(--control-font-size); font-family: inherit; transition: border-color var(--transition-fast), background var(--transition-fast); } input:not([type="checkbox"]):not([type="color"]), select { min-height: var(--control-height); } input:hover, select:hover, textarea:hover { border-color: var(--primary-border); } input:focus, select:focus, textarea:focus { border-color: var(--primary); background: var(--panel-bg); box-shadow: var(--focus-ring); } input:disabled, select:disabled, textarea:disabled { background: var(--button-muted-bg); color: var(--muted); cursor: not-allowed; } input[type="checkbox"] { width: auto; flex: 0 0 auto; accent-color: var(--primary); } input[type="color"] { padding: 0; height: 28px; border-radius: var(--radius); } textarea { min-height: 84px; resize: vertical; } input::placeholder, textarea::placeholder { color: var(--muted); opacity: 0.7; } .property-tab-header { display: flex; flex-wrap: wrap; gap: var(--space-1); padding: var(--space-1); border: 1px solid var(--border-subtle); border-radius: var(--radius); background: transparent; margin-bottom: var(--space-2); } .property-tab-button { border-radius: 999px; padding: 4px 12px; color: var(--muted); font-size: 12px; min-height: var(--control-height-sm); } .property-tab-button.active { background: var(--primary-weak); border-color: var(--primary-border); color: var(--primary); } .tabProperty>form { display: none; } .tabProperty>form.active { display: block; } .tabProperty form fieldset>legend { display: none; } button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--primary-border); outline-offset: 1px; } .app-header-subtitle { margin-left: var(--space-1); font-weight: 400; color: var(--muted); } .app-footer { border-top: 1px solid var(--border-subtle); border-bottom: none; } .status-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2); font-size: 12px; color: var(--muted); flex-wrap: wrap; } .status-group { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; } .status-label { font-size: 16px; font-weight: 600; } .status-value { font-size: 12px; color: var(--muted); } .data-table { width: 100%; border-collapse: collapse; font-size: 12px; background: var(--panel-bg); } .data-table thead th { text-align: left; font-weight: 600; color: var(--table-head-text); background: var(--table-head-bg); padding: 8px 10px; border-bottom: 1px solid var(--table-row-border); white-space: nowrap; position: sticky; top: 0; z-index: 1; } .data-table th, .data-table td { padding: 8px 10px; border-bottom: 1px solid var(--table-row-border); text-align: left; vertical-align: middle; } .data-table td { word-break: break-word; } .data-table tbody tr:nth-child(even) { background: var(--table-row-alt); } .data-table tbody tr:hover { background: var(--table-row-hover); } .data-table tbody tr:last-child td { border-bottom: none; } dialog { border: 1px solid var(--border-subtle); border-radius: var(--radius); padding: 0; width: min(var(--dialog-width), 94vw); max-width: 100%; background: var(--panel-bg); } dialog::backdrop { background: rgba(0, 0, 0, 0.35); } .dialogHeader, .dialogFooter { padding: var(--space-2) var(--space-3); background: var(--panel-bg); } .dialogHeader { border-bottom: 1px solid var(--border-subtle); font-weight: 600; } .dialogBody { padding: var(--space-2) var(--space-3); max-height: var(--dialog-body-max-height); overflow: auto; min-height: 0; } .dialog-message { margin: 0; color: var(--text); line-height: 1.5; } .dialogFooter { border-top: 1px solid var(--border-subtle); display: flex; justify-content: flex-end; gap: var(--space-2); } .dialogFooter button[name="ok"], .dialogFooter button[name="ok"]:hover { background: var(--primary); border-color: var(--primary); color: #ffffff; } .dialog-toolbar { display: flex; gap: var(--space-1); flex-wrap: wrap; margin-bottom: var(--space-2); } .dialog-toolbar .action { font-size: 12px; padding: 4px 10px; min-height: var(--control-height-sm); } .dialog-table { width: 100%; border-collapse: collapse; font-size: 12px; } .dialog-table thead th { background: var(--table-head-bg); color: var(--table-head-text); font-weight: 600; position: sticky; top: 0; z-index: 1; } .dialog-table th, .dialog-table td { padding: 6px 8px; border-bottom: 1px solid var(--table-row-border); text-align: left; vertical-align: top; } .dialog-table tbody tr { cursor: pointer; } .dialog-table tbody tr:hover { background: var(--table-row-hover); } .dialog-table tbody tr.is-selected { background: var(--primary-weak); } .dialog-table tbody tr:focus-visible { outline: 2px solid var(--primary-border); outline-offset: -2px; background: var(--primary-weak); } button[aria-pressed="true"] { background: var(--primary-weak); border-color: var(--primary-border); color: var(--primary); } .dialog-empty { padding: var(--space-3); border: 1px dashed var(--border-subtle); border-radius: var(--radius); color: var(--muted); text-align: center; margin-top: var(--space-2); } .dialog-meta { font-size: 12px; color: var(--muted); } .dialog-inline { display: flex; align-items: center; gap: var(--space-1); flex: 1 1 auto; } .toast-stack { position: fixed; right: var(--space-3); bottom: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); z-index: 9999; pointer-events: none; max-width: min(360px, 92vw); } .toast { pointer-events: auto; display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; gap: var(--space-2); align-items: start; padding: var(--space-2) var(--space-3); border-radius: var(--radius); background: var(--panel-bg); border: 1px solid var(--border-subtle); color: var(--text); opacity: 0; transform: translateY(8px); transition: opacity var(--transition-fast), transform var(--transition-fast); } .toast.show { opacity: 1; transform: translateY(0); } .toast-indicator { width: 10px; height: 10px; border-radius: 999px; background: var(--primary); margin-top: 6px; } .toast-text { font-size: 14px; line-height: 1.6; white-space: pre-line; } .toast-close { padding: 0 6px; min-height: 24px; border-radius: var(--radius); border: 1px solid transparent; background: transparent; color: var(--muted); font-size: 16px; line-height: 1; } .toast-close:hover { color: var(--text); border-color: var(--border-subtle); background: var(--button-hover-bg); } .toast-info { border-color: var(--primary-border); background: var(--primary-weak); } .toast-info .toast-indicator { background: var(--primary); } .toast-success { border-color: var(--success); } .toast-success .toast-indicator { background: var(--success); } .toast-warning { border-color: var(--warning); background: var(--warning-weak); } .toast-warning .toast-indicator { background: var(--warning); } .toast-error { border-color: var(--danger); background: var(--danger-weak); } .toast-error .toast-indicator { background: var(--danger); } dialog.dialog-lg { width: min(var(--dialog-lg-width), 96vw); } dialog form { width: 100%; display: flex; flex-direction: column; min-height: 0; } .dialogBody fieldset, dialog fieldset { width: 100%; min-width: 0; max-width: none; } dialog form label { width: var(--dialog-label-width); text-align: right; justify-self: end; padding-top: 0; align-self: center; } dialog form fieldset>div { display: grid; grid-template-columns: var(--dialog-label-width) minmax(0, 1fr); align-items: center; gap: var(--space-2); } dialog form fieldset>div>input, dialog form fieldset>div>select, dialog form fieldset>div>textarea, dialog form fieldset>div>.dialog-inline { width: 100%; } dialog textarea { min-height: 120px; } form fieldset > div:has(textarea) { align-items: flex-start; } form fieldset > div:has(textarea) > label { align-self: flex-start; } dialog form fieldset>div:has(textarea) { align-items: start; } dialog form fieldset>div:has(textarea) > label { align-self: start; } @media (prefers-reduced-motion: reduce) { * { transition: none !important; } } @media (max-width: 1280px) { .app-container { --toolbar-width: 220px; --property-width: 280px; } } @media (max-width: 1024px) { .app-container { grid-template-columns: 1fr; grid-template-rows: minmax(360px, 1fr) auto auto; grid-template-areas: "map" "toolbar" "property"; } .app-header { flex-direction: column; align-items: flex-start; } .app-header-actions { width: 100%; justify-content: flex-start; } .toolbar .panel-body, .property .panel-body { max-height: 40vh; } .tool-group-body { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); } } @media (max-width: 720px) { .map-header { flex-direction: column; align-items: flex-start; } .status-bar { flex-direction: column; align-items: flex-start; } .footer-toolbar.end { margin-left: 0; } .map-header-actions, .map-controls, .map-search { width: 100%; } .map-search input { flex: 1; min-width: 0; } dialog form fieldset>div { grid-template-columns: 1fr; align-items: flex-start; } dialog form label { width: auto; } .toast-stack { left: var(--space-3); right: var(--space-3); max-width: none; } }