/* ===== Base Variables ===== */
:root {
    --viz-font: 'Inter', 'Helvetica Neue', Arial, sans-serif;
    --viz-bg: #ffffff;
    --viz-text: #1f2937;
    --viz-border: #e5e7eb;
    --viz-accent: #3b82f6;
    --viz-node-bg: #eff6ff;
    --viz-node-border: #93c5fd;
    --viz-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

/* ===== Presets ===== */

/* Deep Ocean (深海のような深いブルーとシアン) */
.viz-preset-ocean {
    --viz-bg: #082f49; /* Tailwind sky-900 */
    --viz-text: #ffffff;
    --viz-border: #0ea5e9;
    --viz-accent: #38bdf8;
    --viz-node-bg: #0c4a6e;
    --viz-node-border: #0284c7;
    --viz-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
}

/* Dark Forest (深い森のようなダークグリーン) */
.viz-preset-forest {
    --viz-bg: #052e16; /* Tailwind green-900 */
    --viz-text: #f0fdf4;
    --viz-border: #166534;
    --viz-accent: #4ade80;
    --viz-node-bg: #14532d;
    --viz-node-border: #22c55e;
    --viz-shadow: 0 8px 16px rgba(0, 0, 0, 0.4);
}

/* Synthwave (80sレトロフューチャーな紫とピンク) */
.viz-preset-synthwave {
    --viz-bg: linear-gradient(135deg, #2b0b3f 0%, #1a0b2e 100%);
    --viz-text: #ffffff;
    --viz-border: #8b5cf6;
    --viz-accent: #f472b6; /* Hot Pink */
    --viz-node-bg: rgba(139, 92, 246, 0.2);
    --viz-node-border: #d946ef;
    --viz-shadow: 0 0 15px rgba(217, 70, 239, 0.3);
}

/* Dracula Theme (人気のエディタテーマ風) */
.viz-preset-dracula {
    --viz-bg: #282a36;
    --viz-text: #f8f8f2;
    --viz-border: #44475a;
    --viz-accent: #ff79c6; /* Pink */
    --viz-node-bg: #44475a;
    --viz-node-border: #6272a4;
    --viz-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}

/* Midnight Sunset (夜更けの夕焼けグラデーション) */
.viz-preset-sunset {
    --viz-bg: linear-gradient(to bottom, #1e1025, #4a154b, #93294b);
    --viz-text: #ffffff;
    --viz-border: rgba(255, 255, 255, 0.2);
    --viz-accent: #fbbf24; /* Warm Gold */
    --viz-node-bg: rgba(0, 0, 0, 0.25);
    --viz-node-border: #f59e0b;
    --viz-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
}

/* Royal Gold (高級感のあるネイビーとゴールド) */
.viz-preset-royal {
    --viz-bg: #171720;
    --viz-text: #ffffff;
    --viz-border: #333344;
    --viz-accent: #d4af37; /* Metallic Gold */
    --viz-node-bg: #1e1e28;
    --viz-node-border: #8c7322;
    --viz-shadow: 0 4px 15px rgba(212, 175, 55, 0.15);
}

/* Hacker Terminal (ハッカー風の黒背景＋緑文字アクセント) */
.viz-preset-terminal {
    --viz-font: 'Fira Code', 'Courier New', Courier, monospace;
    --viz-bg: #000000;
    --viz-text: #ffffff; /* 白文字前提 */
    --viz-border: #22c55e;
    --viz-accent: #4ade80; /* Matrix Green */
    --viz-node-bg: #05200f;
    --viz-node-border: #166534;
    --viz-shadow: 0 0 10px rgba(34, 197, 94, 0.2);
}

/* Blood Crimson (ダークで力強い赤黒テーマ) */
.viz-preset-crimson {
    --viz-bg: #1a0505;
    --viz-text: #ffffff;
    --viz-border: #450a0a;
    --viz-accent: #ef4444;
    --viz-node-bg: #2b0808;
    --viz-node-border: #7f1d1d;
    --viz-shadow: 0 5px 15px rgba(239, 68, 68, 0.2);
}

/* Pure Monochrome (完全な白黒のミニマルダーク) */
.viz-preset-monochrome {
    --viz-bg: #000000;
    --viz-text: #ffffff;
    --viz-border: #333333;
    --viz-accent: #ffffff;
    --viz-node-bg: #111111;
    --viz-node-border: #555555;
    --viz-shadow: none;
}

/* Northern Aurora (極北のオーロラのようなグラデーション) */
.viz-preset-aurora {
    --viz-bg: #0f172a;
    background-image: radial-gradient(circle at top left, #0f172a 0%, #064e3b 50%, #0f172a 100%);
    --viz-text: #ffffff;
    --viz-border: #059669;
    --viz-accent: #34d399; /* Emerald */
    --viz-node-bg: rgba(255, 255, 255, 0.05);
    --viz-node-border: #10b981;
    --viz-shadow: 0 0 20px rgba(16, 185, 129, 0.15);
}
/* Minimal */
.viz-preset-minimal {
    --viz-bg: #ffffff;
    --viz-text: #111827;
    --viz-border: #d1d5db;
    --viz-accent: #111827;
    --viz-node-bg: #ffffff;
    --viz-node-border: #d1d5db;
    --viz-shadow: none;
}

/* Dark Space */
.viz-preset-dark {
    --viz-bg: #0f172a;
    --viz-text: #f8fafc;
    --viz-border: #334155;
    --viz-accent: #38bdf8;
    --viz-node-bg: #1e293b;
    --viz-node-border: #475569;
    --viz-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
}

/* Glassmorphism */
.viz-preset-glass {
    --viz-bg: rgba(255, 255, 255, 0.15);
    background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.1) 100%);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    --viz-text: #ffffff;
    --viz-border: rgba(255, 255, 255, 0.3);
    --viz-accent: #f472b6;
    --viz-node-bg: rgba(255, 255, 255, 0.2);
    --viz-node-border: rgba(255, 255, 255, 0.4);
    --viz-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
}

/* Cyber Neon */
.viz-preset-neon {
    --viz-bg: #050510;
    --viz-text: #e0e7ff;
    --viz-border: #1e1e3f;
    --viz-accent: #00ffcc;
    --viz-node-bg: #0b0b1a;
    --viz-node-border: #00ffcc;
    --viz-shadow: 0 0 10px rgba(0, 255, 204, 0.5), inset 0 0 10px rgba(0, 255, 204, 0.2);
}

/* Prototyping (Sketch) */
.viz-preset-sketch {
    --viz-font: 'Comic Sans MS', 'Chalkboard SE', 'Caveat', cursive, sans-serif;
    --viz-bg: #fdfaf6;
    --viz-text: #2c2c2c;
    --viz-border: #888;
    --viz-accent: #d97706;
    --viz-node-bg: #ffffff;
    --viz-node-border: #444;
    --viz-shadow: 2px 2px 0px rgba(0, 0, 0, 0.8);
}

.viz-preset-sketch .viz-canvas svg {
    filter: url(#viz-rough-filter) drop-shadow(2px 2px 0px rgba(0, 0, 0, 0.3));
}

.viz-preset-sketch .node rect,
.viz-preset-sketch .node polygon,
.viz-preset-sketch .node circle {
    stroke-dasharray: 4, 2;
    stroke-width: 2px;
}

/* ===== Layout & UI ===== */
.viz-wrapper {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--viz-border);
    border-radius: 12px;
    background: var(--viz-bg);
    color: var(--viz-text);
    box-shadow: var(--viz-shadow);
    overflow: hidden;
    font-family: var(--viz-font);
    margin-bottom: 2rem;
    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.viz-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    background: rgba(0, 0, 0, 0.03);
    border-bottom: 1px solid var(--viz-border);
}

.viz-preset-dark .viz-header,
.viz-preset-neon .viz-header,
.viz-preset-glass .viz-header {
    background: rgba(255, 255, 255, 0.05);
}

.viz-title {
    font-weight: 600;
    font-size: 0.95rem;
    letter-spacing: 0.5px;
}

.viz-controls {
    display: flex;
    gap: 12px;
    align-items: center;
}

.viz-btn,
.viz-preset-selector {
    background: var(--viz-node-bg);
    color: var(--viz-text);
    border: 1px solid var(--viz-border);
    padding: 6px 12px;
    border-radius: 6px;
    font-size: 0.85rem;
    cursor: pointer;
    transition: all 0.2s;
    outline: none;
}

.viz-btn:hover,
.viz-preset-selector:hover {
    border-color: var(--viz-accent);
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}

.viz-preset-neon .viz-btn:hover {
    box-shadow: 0 0 8px var(--viz-accent);
}

.viz-btn-render {
    background: var(--viz-accent);
    color: #fff;
    border: none;
    font-weight: bold;
}

.viz-btn-export:disabled,
.viz-btn-busy {
    opacity: 0.7;
    cursor: progress;
}

.viz-preset-neon .viz-btn-render {
    color: #050510;
}

.viz-zoom-controls {
    display: flex;
    gap: 4px;
    background: rgba(0, 0, 0, 0.05);
    padding: 3px;
    border-radius: 8px;
}

.viz-preset-dark .viz-zoom-controls,
.viz-preset-neon .viz-zoom-controls {
    background: rgba(255, 255, 255, 0.05);
}

.viz-body {
    display: flex;
    flex-direction: column;
    height: var(--viz-height, 500px);
}

@media (min-width: 768px) {
    .viz-body {
        flex-direction: row;
    }
}

.viz-editor {
    flex: 1;
    min-width: 250px;
    padding: 20px;
    border: none;
    border-right: 1px solid var(--viz-border);
    background: rgba(0, 0, 0, 0.02);
    color: var(--viz-text);
    font-family: 'Fira Code', Consolas, monospace;
    font-size: 0.9rem;
    line-height: 1.6;
    resize: none;
}

.viz-preset-dark .viz-editor,
.viz-preset-neon .viz-editor {
    background: rgba(0, 0, 0, 0.2);
}

.viz-editor:focus {
    outline: none;
}

.viz-canvas-container {
    flex: 3;
    overflow: hidden;
    position: relative;
    cursor: grab;
    display: flex;
    justify-content: center;
    align-items: center;
}

.viz-canvas-container:active {
    cursor: grabbing;
}

.viz-canvas {
    transform-origin: 0 0;
    will-change: auto;
    /* transition is handled by JS dynamically, but default fallback below */
    transition: transform 0.1s ease-out;
    display: inline-block;
    position: relative;
}

.viz-canvas svg {
    overflow: visible;
    shape-rendering: geometricPrecision;
    text-rendering: geometricPrecision;
}

.viz-canvas .edgeLabel,
.viz-canvas .edgeLabel * {
    pointer-events: all !important;
    user-select: none;
    cursor: pointer;
}

/* Cinematic zoom transition */
.viz-canvas.viz-cinematic {
    transition: transform 1.2s cubic-bezier(0.25, 1, 0.5, 1) !important;
}

/* Glassmorphism Tooltip */
.viz-tooltip {
    position: absolute;
    top: 0;
    left: 0;
    background: rgba(255, 255, 255, 0.7);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.5);
    padding: 8px 12px;
    border-radius: 8px;
    font-size: 0.8rem;
    color: #333;
    pointer-events: none;
    opacity: 0;
    transform: translateY(10px);
    transition: all 0.2s ease-out;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    z-index: 100;
}

.viz-tooltip.viz-show {
    opacity: 1;
    transform: translateY(0);
}

.viz-preset-dark .viz-tooltip,
.viz-preset-neon .viz-tooltip {
    background: rgba(15, 23, 42, 0.8);
    color: #fff;
    border-color: rgba(255, 255, 255, 0.1);
}

/* Particle effect */
.viz-particle {
    position: absolute;
    width: 6px;
    height: 6px;
    background: var(--viz-accent);
    border-radius: 50%;
    pointer-events: none;
    animation: viz-particle-anim 0.6s ease-out forwards;
    z-index: 50;
    box-shadow: 0 0 6px var(--viz-accent);
}

@keyframes viz-particle-anim {
    0% {
        transform: scale(1) translate(0, 0);
        opacity: 1;
    }

    100% {
        transform: scale(0) translate(var(--tx), var(--ty));
        opacity: 0;
    }
}

/* Ripple effect */
.viz-ripple {
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.4);
    transform: scale(0);
    animation: viz-ripple-anim 0.6s linear;
    pointer-events: none;
}

.viz-preset-dark .viz-ripple,
.viz-preset-neon .viz-ripple {
    background: rgba(255, 255, 255, 0.2);
}

@keyframes viz-ripple-anim {
    to {
        transform: scale(4);
        opacity: 0;
    }
}

/* Sequential Fade-in (Typing style) */
.viz-node-hidden {
    opacity: 0 !important;
    transform: translateY(-10px);
}

.viz-node-reveal {
    animation: viz-reveal-anim 0.4s ease-out forwards;
}

@keyframes viz-reveal-anim {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ===== Node Custom Behaviors / Animations ===== */

/* Nodes dimming effect */
.viz-node-dimmed {
    opacity: 0.2 !important;
    filter: grayscale(80%) blur(1px);
    transition: all 0.3s ease;
}

.viz-edge-dimmed,
.viz-edge-dimmed path.path,
.viz-edge-dimmed path {
    opacity: 0.1 !important;
    transition: all 0.3s ease;
}

/* Active nodes */
.viz-node-active {
    transform-origin: center;
    transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    filter: drop-shadow(0 0 10px var(--viz-accent));
}

/* Edge flow animation */
.viz-edge-animated,
.viz-edge-animated.path,
.viz-edge-animated path.path,
.viz-edge-animated path {
    stroke: var(--viz-accent) !important;
    stroke-width: 3.2px !important;
    stroke-linecap: round;
    stroke-dasharray: 18, 10 !important;
    filter: drop-shadow(0 0 6px var(--viz-accent));
    animation: viz-flow 0.9s linear infinite, viz-flow-glow 1.8s ease-in-out infinite;
}

@keyframes viz-flow {
    to {
        stroke-dashoffset: -56;
    }
}

@keyframes viz-flow-glow {

    0%,
    100% {
        opacity: 0.9;
        filter: drop-shadow(0 0 4px var(--viz-accent));
    }

    50% {
        opacity: 1;
        filter: drop-shadow(0 0 12px var(--viz-accent));
    }
}

/* ===== Mermaid Stage Motion ===== */
.viz-canvas svg .viz-mermaid-entity {
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
    animation: viz-mermaid-entity-in 0.62s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
    animation-delay: var(--viz-seq, 0s);
    transition: transform 0.25s ease, filter 0.25s ease;
}

.viz-canvas svg .viz-mermaid-text {
    opacity: 0;
    animation: viz-mermaid-text-in 0.45s ease-out forwards;
    animation-delay: var(--viz-text-seq, 0.1s);
}

.viz-canvas svg .viz-mermaid-edge {
    opacity: 0.22;
    stroke-dasharray: 22 14;
    stroke-dashoffset: 140;
    animation: viz-mermaid-edge-draw 0.95s cubic-bezier(0.2, 0.75, 0.25, 1) forwards, viz-flow 0.9s linear infinite;
    animation-delay: var(--viz-edge-seq, 0s), calc(var(--viz-edge-seq, 0s) + 0.9s);
    transition: opacity 0.2s ease, filter 0.2s ease, stroke-width 0.2s ease;
}

@keyframes viz-mermaid-entity-in {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes viz-mermaid-text-in {
    0% {
        opacity: 0;
        letter-spacing: 0.06em;
    }

    100% {
        opacity: 1;
        letter-spacing: normal;
    }
}

@keyframes viz-mermaid-edge-draw {
    0% {
        opacity: 0.15;
        stroke-dashoffset: 140;
    }

    100% {
        opacity: 1;
        stroke-dashoffset: 0;
    }
}

/* Type-specific accents */
.viz-canvas.viz-motion-timeline svg .viz-mermaid-entity,
.viz-canvas.viz-motion-journey svg .viz-mermaid-entity {
    animation-name: viz-mermaid-rise-in;
}

@keyframes viz-mermaid-rise-in {
    0% {
        opacity: 0;
        transform: translateY(18px) scale(0.96);
    }

    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

.viz-canvas.viz-motion-gantt svg .viz-mermaid-edge,
.viz-canvas.viz-motion-gitgraph svg .viz-mermaid-edge {
    animation-duration: 0.72s, 0.78s;
}

.viz-canvas.viz-motion-pie svg .viz-mermaid-entity {
    animation-name: viz-mermaid-pop-in;
}

@keyframes viz-mermaid-pop-in {
    0% {
        opacity: 0;
        transform: scale(0.75);
    }

    70% {
        opacity: 1;
        transform: scale(1.05);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.viz-canvas.viz-motion-architecture svg .viz-mermaid-entity,
.viz-canvas.viz-motion-c4 svg .viz-mermaid-entity {
    filter: drop-shadow(0 0 8px color-mix(in srgb, var(--viz-accent) 42%, transparent));
    animation-name: viz-mermaid-glow-in;
}

@keyframes viz-mermaid-glow-in {
    0% {
        opacity: 0;
        transform: translateY(10px) scale(0.95);
        filter: drop-shadow(0 0 0 transparent);
    }

    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
        filter: drop-shadow(0 0 8px color-mix(in srgb, var(--viz-accent) 40%, transparent));
    }
}

.viz-canvas.viz-motion-mindmap svg .viz-mermaid-entity,
.viz-canvas.viz-motion-wbs svg .viz-mermaid-entity {
    animation-name: viz-mermaid-bloom-in;
}

@keyframes viz-mermaid-bloom-in {
    0% {
        opacity: 0;
        transform: scale(0.88);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.viz-canvas.viz-motion-sequence svg .viz-mermaid-edge,
.viz-canvas.viz-motion-logic svg .viz-mermaid-edge {
    stroke-dasharray: 16 9;
    animation-duration: 0.84s, 0.95s;
}

/* Interaction enhancements */
.viz-canvas svg .viz-mermaid-entity:hover {
    filter: drop-shadow(0 0 8px color-mix(in srgb, var(--viz-accent) 55%, transparent));
}

.viz-canvas svg .viz-mermaid-edge:hover {
    opacity: 1;
    stroke-width: 3.2px;
    filter: drop-shadow(0 0 7px color-mix(in srgb, var(--viz-accent) 55%, transparent));
}

.viz-canvas svg .viz-entity-selected,
.viz-canvas svg .viz-pie-selected {
    filter: drop-shadow(0 0 10px color-mix(in srgb, var(--viz-accent) 65%, transparent));
}

.viz-canvas svg .viz-pie-selected path,
.viz-canvas svg path.viz-pie-selected,
.viz-canvas svg .slice.viz-pie-selected path {
    stroke: var(--viz-accent) !important;
    stroke-width: 3px !important;
}

.viz-canvas svg .viz-edge-selected,
.viz-canvas svg .viz-edge-selected path {
    stroke: var(--viz-accent) !important;
    stroke-width: 3.2px !important;
    filter: drop-shadow(0 0 10px color-mix(in srgb, var(--viz-accent) 65%, transparent));
}

@media (prefers-reduced-motion: reduce) {
    .viz-canvas svg .viz-mermaid-entity,
    .viz-canvas svg .viz-mermaid-text,
    .viz-canvas svg .viz-mermaid-edge {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
        stroke-dasharray: none !important;
        stroke-dashoffset: 0 !important;
        filter: none !important;
    }

    .viz-canvas svg .viz-entity-selected,
    .viz-canvas svg .viz-pie-selected,
    .viz-canvas svg .viz-edge-selected {
        animation: none !important;
    }
}
/* ===== Generic Extended UI ===== */
.viz-status-bar {
    padding: 8px 14px;
    font-size: 0.78rem;
    border-bottom: 1px solid var(--viz-border);
    background: rgba(0, 0, 0, 0.03);
    color: var(--viz-text);
}

.viz-status-success {
    color: #15803d;
}

.viz-status-warn {
    color: #b45309;
}

.viz-status-error {
    color: #b91c1c;
}

.viz-preset-dark .viz-status-bar,
.viz-preset-neon .viz-status-bar,
.viz-preset-glass .viz-status-bar {
    background: rgba(255, 255, 255, 0.06);
}

.viz-preset-dark .viz-status-success,
.viz-preset-neon .viz-status-success,
.viz-preset-glass .viz-status-success {
    color: #86efac;
}

.viz-preset-dark .viz-status-warn,
.viz-preset-neon .viz-status-warn,
.viz-preset-glass .viz-status-warn {
    color: #fde047;
}

.viz-preset-dark .viz-status-error,
.viz-preset-neon .viz-status-error,
.viz-preset-glass .viz-status-error {
    color: #fca5a5;
}

.viz-editor-hint {
    border-bottom: 1px dashed var(--viz-border);
    padding: 7px 14px;
    font-size: 0.74rem;
    color: rgba(17, 24, 39, 0.75);
    background: rgba(0, 0, 0, 0.015);
}

.viz-preset-dark .viz-editor-hint,
.viz-preset-neon .viz-editor-hint,
.viz-preset-glass .viz-editor-hint {
    color: rgba(248, 250, 252, 0.75);
    background: rgba(255, 255, 255, 0.04);
}

.viz-item-active {
    outline: 2px solid var(--viz-accent) !important;
    outline-offset: 2px;
    filter: drop-shadow(0 0 8px color-mix(in srgb, var(--viz-accent) 60%, transparent));
}

/* ===== Matrix ===== */
.viz-matrix-grid {
    display: grid;
    grid-template-columns: minmax(120px, 180px) repeat(var(--viz-matrix-cols), minmax(150px, 1fr));
    border: 1px solid var(--viz-border);
    border-radius: 12px;
    overflow: hidden;
    min-width: 520px;
    background: color-mix(in srgb, var(--viz-bg) 94%, #000 6%);
}

.viz-matrix-corner,
.viz-matrix-col-header,
.viz-matrix-row-header,
.viz-matrix-cell {
    padding: 12px;
    border-right: 1px solid color-mix(in srgb, var(--viz-border) 80%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--viz-border) 80%, transparent);
    min-height: 64px;
}

.viz-matrix-corner {
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 0.72rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--viz-node-bg) 65%, var(--viz-bg) 35%);
}

.viz-matrix-col-header,
.viz-matrix-row-header {
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-size: 0.84rem;
    background: color-mix(in srgb, var(--viz-node-bg) 75%, var(--viz-bg) 25%);
    animation: viz-reveal-anim 0.35s ease both;
}

.viz-matrix-row-header {
    justify-content: flex-start;
}

.viz-matrix-cell {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    align-content: flex-start;
    gap: 8px;
    background: color-mix(in srgb, var(--viz-bg) 92%, var(--viz-node-bg) 8%);
    animation: viz-reveal-anim 0.3s ease both;
}

.viz-matrix-tag {
    display: inline-flex;
    align-items: center;
    padding: 4px 9px;
    border-radius: 999px;
    font-size: 0.74rem;
    border: 1px solid color-mix(in srgb, var(--viz-node-border) 75%, transparent);
    background: color-mix(in srgb, var(--viz-node-bg) 72%, var(--viz-bg) 28%);
}

.viz-matrix-empty {
    opacity: 0.45;
    font-size: 0.75rem;
}

/* ===== SWOT ===== */
.viz-swot-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(220px, 1fr));
    gap: 12px;
    min-width: 460px;
}

.viz-swot-quadrant {
    border: 1px solid color-mix(in srgb, var(--viz-border) 88%, transparent);
    border-radius: 12px;
    background: color-mix(in srgb, var(--viz-node-bg) 24%, var(--viz-bg) 76%);
    padding: 12px;
    min-height: 150px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.viz-swot-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    font-size: 0.9rem;
}

.viz-swot-badge {
    width: 24px;
    height: 24px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    border: 1px solid color-mix(in srgb, var(--viz-node-border) 88%, transparent);
    background: color-mix(in srgb, var(--viz-node-bg) 85%, var(--viz-bg) 15%);
}

.viz-swot-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.viz-swot-item,
.viz-swot-empty {
    font-size: 0.82rem;
    border: 1px solid color-mix(in srgb, var(--viz-border) 84%, transparent);
    border-radius: 8px;
    padding: 7px 9px;
    background: color-mix(in srgb, var(--viz-bg) 95%, #000 5%);
    animation: viz-reveal-anim 0.28s ease both;
}

.viz-swot-empty {
    opacity: 0.65;
    font-style: italic;
}

.viz-swot-strengths .viz-swot-badge {
    color: #15803d;
}

.viz-swot-weaknesses .viz-swot-badge {
    color: #b45309;
}

.viz-swot-opportunities .viz-swot-badge {
    color: #0369a1;
}

.viz-swot-threats .viz-swot-badge {
    color: #b91c1c;
}

@media (max-width: 900px) {
    .viz-swot-grid {
        grid-template-columns: 1fr;
        min-width: 280px;
    }

    .viz-matrix-grid {
        min-width: 420px;
    }
}

/* ===== Aurora専用アニメーション ===== */
.viz-preset-aurora {
    /* 既存の背景をグラデーションアニメーション用に上書き */
    background: linear-gradient(-45deg, #0f172a, #064e3b, #0f172a, #115e59);
    background-size: 400% 400%;
    animation: viz-aurora-shift 15s ease infinite;
}

@keyframes viz-aurora-shift {
    0% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* ===== Synthwave専用アニメーション ===== */
.viz-preset-synthwave {
    animation: viz-synthwave-pulse 4s infinite alternate;
}

.viz-preset-synthwave .viz-canvas svg .viz-mermaid-entity {
    animation: viz-synthwave-float 3s ease-in-out infinite alternate;
}

@keyframes viz-synthwave-pulse {
    0%, 100% { box-shadow: 0 0 15px rgba(217, 70, 239, 0.3); }
    50% { box-shadow: 0 0 25px rgba(217, 70, 239, 0.6), inset 0 0 10px rgba(217, 70, 239, 0.2); }
}

@keyframes viz-synthwave-float {
    0% { transform: translateY(0px); filter: drop-shadow(0 0 5px var(--viz-accent)); }
    100% { transform: translateY(-4px); filter: drop-shadow(0 0 12px var(--viz-accent)); }
}

/* ===== Cyber Neon専用アニメーション ===== */
.viz-preset-neon .viz-title,
.viz-preset-neon .viz-btn-render {
    animation: viz-neon-flicker 5s infinite;
}

@keyframes viz-neon-flicker {
    0%, 18%, 22%, 25%, 53%, 57%, 100% {
        text-shadow: 0 0 5px var(--viz-accent), 0 0 10px var(--viz-accent);
        opacity: 1;
    }
    20%, 24%, 55% {
        text-shadow: none;
        opacity: 0.8;
    }
}

/* ===== Hacker Terminal専用アニメーション ===== */
.viz-preset-terminal .viz-title::after {
    content: " █";
    color: var(--viz-accent);
    animation: viz-terminal-blink 1s step-end infinite;
}

@keyframes viz-terminal-blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

/* 矢印の線そのものがクリックイベントを確実に受け取るようにする */
.edgePath path {
    pointer-events: stroke !important;
    cursor: pointer;
}

/* ラベルの背景などがクリックを遮らないように調整 */
.edgeLabel rect {
    pointer-events: none; /* ラベルの背景四角形はクリックを透過させる */
}
.edgeLabel text {
    pointer-events: auto; /* テキスト部分はクリックに反応させる */
}

/* ノード・テキスト・線の初期状態とアニメーション設定 */
.viz-mermaid-entity,
.viz-mermaid-text {
    opacity: 0;
    animation: vizFadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    animation-delay: var(--viz-seq, var(--viz-text-seq, 0s));
}

.viz-mermaid-edge {
    stroke-dasharray: 1000;
    stroke-dashoffset: 1000;
    animation: vizDrawLine 1s ease-out forwards;
    animation-delay: var(--viz-edge-seq, 0s);
}

/* ホバー時のリアクション（ノード） */
.viz-mermaid-entity:hover {
    cursor: pointer;
    filter: brightness(0.9) drop-shadow(0 4px 6px rgba(0,0,0,0.1));
    transition: all 0.2s ease;
}

/* 選択時のハイライト */
.viz-entity-selected rect,
.viz-entity-selected polygon,
.viz-entity-selected circle {
    stroke: #3b82f6 !important; /* 青色のハイライト */
    stroke-width: 3px !important;
}

/* 修正版：キーフレームから transform を削除して座標リセットを防ぐ */
@keyframes vizFadeInUp {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

/**
 * 独立版 Sequence Visualizer (visualizer-sequence.js)
 * フローチャート版のUX（ズーム、パン、フォーカス）を継承しつつ、
 * シーケンス図特有のDOM構造に合わせたハイライト機能とパフォーマンス改善を実装。
 */
document.addEventListener('DOMContentLoaded', () => {
    const VIZ_BUILD = '2026-03-05-sequence-standalone';

    // Mermaidの初期化（テーマは描画時に上書きするためダミー設定）
    if (typeof mermaid !== 'undefined') {
        mermaid.initialize({
            startOnLoad: false,
            securityLevel: 'strict'
        });
    }

    const wrappers = document.querySelectorAll('.viz-wrapper');

    wrappers.forEach(wrapper => {
        // 'sequence' タイプのラッパーのみ処理
        const vizType = wrapper.dataset.vizType || 'sequence';
        if (vizType !== 'sequence') return;

        wrapper.setAttribute('data-viz-build', VIZ_BUILD);

        const editor = wrapper.querySelector('.viz-editor');
        const canvasContainer = wrapper.querySelector('.viz-canvas-container');
        const canvas = wrapper.querySelector('.viz-canvas');
        const renderBtn = wrapper.querySelector('.viz-btn-render');
        const presetSelect = wrapper.querySelector('.viz-preset-selector');
        const tooltip = wrapper.querySelector('.viz-tooltip');

        // Zoom/Pan controls
        const btnZoomIn = wrapper.querySelector('.viz-btn-zoom-in');
        const btnZoomOut = wrapper.querySelector('.viz-btn-zoom-out');
        const btnZoomReset = wrapper.querySelector('.viz-btn-zoom-reset');
        const btnFocus = wrapper.querySelector('.viz-btn-focus');

        let scale = 1;
        let x = 0;
        let y = 0;
        let isDragging = false;
        let startX, startY;
        let dragDistance = 0;

        // --- Viewport Management (Zoom & Pan) ---
        const updateTransform = (smooth = false) => {
            canvas.style.transition = smooth ? 'transform 0.3s cubic-bezier(0.25, 1, 0.5, 1)' : 'none';
            canvas.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
        };

        const zoomToCurrentPointer = (pointerX, pointerY, dir, zoomSpeed = 0.1) => {
            const newScale = Math.min(Math.max(0.2, scale + (dir * zoomSpeed)), 5);
            const scaleRatio = newScale / scale;
            x = pointerX - (pointerX - x) * scaleRatio;
            y = pointerY - (pointerY - y) * scaleRatio;
            scale = newScale;
            updateTransform();
        };

        wrapper.addEventListener('wheel', (e) => {
            if (e.target.closest('.viz-editor')) return;
            e.preventDefault();
            const rect = canvasContainer.getBoundingClientRect();
            const pointerX = e.clientX - rect.left;
            const pointerY = e.clientY - rect.top;
            const dir = Math.sign(e.deltaY) * -1;
            zoomToCurrentPointer(pointerX, pointerY, dir, 0.05);
        }, { passive: false });

        canvasContainer.addEventListener('pointerdown', (e) => {
            // シーケンス図の要素（アクター、メッセージ、ノート）をクリックした場合はドラッグ開始しない
            const isTargetInteractable = e.target.closest('.actor, .messageLine0, .messageLine1, .messageText, .note, .noteText');
            if (isTargetInteractable) return;
            
            isDragging = true;
            dragDistance = 0;
            startX = e.clientX - x;
            startY = e.clientY - y;
            canvasContainer.setPointerCapture(e.pointerId);
            canvas.style.transition = 'none';
        });

        canvasContainer.addEventListener('pointermove', (e) => {
            if (!isDragging) return;
            
            dragDistance += Math.abs(e.movementX) + Math.abs(e.movementY);
            x = e.clientX - startX;
            y = e.clientY - startY;
            updateTransform();
        });

        canvasContainer.addEventListener('pointerup', (e) => {
            isDragging = false;
            if (canvasContainer.hasPointerCapture(e.pointerId)) {
                canvasContainer.releasePointerCapture(e.pointerId);
            }
        });

        // Center function
        const centerCanvas = (smooth = true) => {
            const containerRect = canvasContainer.getBoundingClientRect();
            const svgEl = canvas.querySelector('svg');
            if (svgEl) {
                const svgRect = svgEl.getBoundingClientRect();
                x = (containerRect.width - (svgRect.width / scale)) / 2;
                y = (containerRect.height - (svgRect.height / scale)) / 2;
            } else {
                x = 0; y = 0;
            }
            updateTransform(smooth);
        };

        // --- Buttons & Keyboard ---
        btnZoomIn?.addEventListener('click', () => {
            const containerRect = canvasContainer.getBoundingClientRect();
            zoomToCurrentPointer(containerRect.width / 2, containerRect.height / 2, 1, 0.3);
        });
        
        btnZoomOut?.addEventListener('click', () => {
            const containerRect = canvasContainer.getBoundingClientRect();
            zoomToCurrentPointer(containerRect.width / 2, containerRect.height / 2, -1, 0.3);
        });
        
        btnZoomReset?.addEventListener('click', () => { scale = 1; centerCanvas(); });

        btnFocus?.addEventListener('click', () => {
            canvas.classList.add('viz-cinematic');
            const svgEl = canvas.querySelector('svg');
            if (svgEl) {
                const containerRect = canvasContainer.getBoundingClientRect();
                const bbox = svgEl.getBBox();
                if (bbox.width > 0 && bbox.height > 0) {
                    const scaleX = (containerRect.width * 0.9) / bbox.width;
                    const scaleY = (containerRect.height * 0.9) / bbox.height;
                    scale = Math.min(scaleX, scaleY, 2);
                }
            }
            centerCanvas(false);
            setTimeout(() => canvas.classList.remove('viz-cinematic'), 1200);
        });

        wrapper.addEventListener('keydown', (e) => {
            if (document.activeElement === editor) return;
            switch (e.key) {
                case '1': scale = 1; centerCanvas(); break;
                case 'f':
                case 'F': btnFocus?.click(); break;
                case '=':
                case '+': btnZoomIn?.click(); break;
                case '-': btnZoomOut?.click(); break;
                case 'ArrowLeft': x += 50; updateTransform(true); break;
                case 'ArrowRight': x -= 50; updateTransform(true); break;
                case 'ArrowUp': y += 50; updateTransform(true); break;
                case 'ArrowDown': y -= 50; updateTransform(true); break;
            }
        });

        // --- Interactions (Sequence Specific) ---
        // パフォーマンス改善: イベントリスナーはラッパーに対して1度だけ登録する（イベント委譲）
        canvasContainer.addEventListener('click', (e) => {
            if (dragDistance > 10) return; // ドラッグによる誤爆防止

            const target = e.target;
            const isSvgClick = target === canvas || target.tagName.toLowerCase() === 'svg';
            
            // 背景クリックでハイライト解除
            if (isSvgClick) {
                resetSequenceHighlight();
                return;
            }

            // クリックエフェクト（波紋）
            createClickFx(e);

            // アクター（参加者）のクリック
            const actor = target.closest('.actor, text.actor');
            if (actor) {
                e.stopPropagation();
                highlightActor(actor);
                return;
            }

            // メッセージ（矢印・テキスト）のクリック
            const message = target.closest('.messageLine0, .messageLine1, .messageText, .sequenceNumber');
            if (message) {
                e.stopPropagation();
                highlightElementGroup(message, 'message');
                return;
            }

            // ノート（メモ）のクリック
            const note = target.closest('.note, .noteText');
            if (note) {
                e.stopPropagation();
                highlightElementGroup(note, 'note');
                return;
            }
        });

        const resetSequenceHighlight = () => {
            const allElements = canvas.querySelectorAll('.actor, .messageLine0, .messageLine1, .messageText, .note, .noteText, .sequenceNumber');
            allElements.forEach(el => {
                el.classList.remove('viz-seq-active', 'viz-seq-dimmed');
            });
        };

        const highlightElementGroup = (targetEl, type) => {
            resetSequenceHighlight();
            
            const allElements = canvas.querySelectorAll('.actor, .messageLine0, .messageLine1, .messageText, .note, .noteText, .sequenceNumber');
            
            // シーケンス図は要素同士の明確な繋がり（DOMツリー上）が薄いため、
            // 選択された要素に直接関連する周辺の要素を推測してハイライトします
            let groupToHighlight = [targetEl];
            
            if (targetEl.tagName.toLowerCase() === 'text') {
                // テキストをクリックした場合、近くの図形（パスや矩形）も一緒に光らせるための簡易処理
                const previousSibling = targetEl.previousElementSibling;
                if (previousSibling) groupToHighlight.push(previousSibling);
            }

            allElements.forEach(el => {
                if (groupToHighlight.includes(el) || groupToHighlight.includes(el.nextElementSibling)) {
                    el.classList.add('viz-seq-active');
                } else {
                    el.classList.add('viz-seq-dimmed');
                }
            });
        };

        const highlightActor = (actorEl) => {
            resetSequenceHighlight();
            const allElements = Array.from(canvas.querySelectorAll('.actor, .messageLine0, .messageLine1, .messageText, .note, .noteText, .sequenceNumber'));
            
            // アクター名テキストを取得
            const actorText = actorEl.textContent || '';
            
            allElements.forEach(el => {
                // 同名のアクター（上下に配置されることが多い）はハイライト
                if (el.classList.contains('actor') && el.textContent === actorText) {
                    el.classList.add('viz-seq-active');
                } 
                // それ以外は暗くする（※シーケンス図は線の判定が複雑なため、アクターのみ強調する仕様に）
                else {
                    el.classList.add('viz-seq-dimmed');
                }
            });
        };

        const createClickFx = (event) => {
            const rRect = canvasContainer.getBoundingClientRect();
            const ripple = document.createElement('div');
            ripple.className = 'viz-ripple';
            ripple.style.left = `${event.clientX - rRect.left - 20}px`;
            ripple.style.top = `${event.clientY - rRect.top - 20}px`;
            ripple.style.width = '40px';
            ripple.style.height = '40px';
            canvasContainer.appendChild(ripple);
            setTimeout(() => ripple.remove(), 600);
        };

        // --- Rendering ---
        const renderCode = async () => {
            const code = editor ? editor.value.trim() : '';
            if (!code) return;

            try {
                // Get computed styles for dynamic Mermaid theming
                const styles = getComputedStyle(wrapper);
                const bgColor = styles.getPropertyValue('--viz-node-bg').trim() || '#ffffff';
                const borderColor = styles.getPropertyValue('--viz-node-border').trim() || '#d1d5db';
                const textColor = styles.getPropertyValue('--viz-text').trim() || '#111827';
                const fontFamily = styles.getPropertyValue('--viz-font').trim() || 'sans-serif';
                const primaryColor = styles.getPropertyValue('--viz-primary').trim() || '#3b82f6';

                // シーケンス図特有の変数（themeVariables）を設定
                mermaid.initialize({
                    startOnLoad: false,
                    securityLevel: 'strict',
                    theme: 'base',
                    themeVariables: {
                        fontFamily: fontFamily,
                        actorBkg: bgColor,
                        actorBorder: borderColor,
                        actorTextColor: textColor,
                        actorLineColor: borderColor,
                        signalColor: textColor,
                        signalTextColor: textColor,
                        noteBkg: bgColor,
                        noteBorderColor: borderColor,
                        noteTextColor: textColor,
                        activationBkgColor: primaryColor,
                        sequenceNumberColor: '#ffffff'
                    }
                });

                const id = 'viz-mermaid-seq-' + Math.random().toString(36).substr(2, 9);
                const { svg } = await mermaid.render(id, code);
                canvas.innerHTML = svg;

                // Cinematic initial render focus
                const isFirstRender = !canvas.hasAttribute('data-rendered');
                if (isFirstRender) {
                    canvas.setAttribute('data-rendered', 'true');
                    const actors = canvas.querySelectorAll('.actor');
                    actors.forEach((n, i) => {
                        n.classList.add('viz-node-hidden');
                        setTimeout(() => n.classList.add('viz-node-reveal'), i * 80);
                    });
                }

                if(renderBtn) {
                    renderBtn.style.transform = 'scale(0.95)';
                    setTimeout(() => renderBtn.style.transform = 'scale(1)', 150);
                }

            } catch (err) {
                console.error("Mermaid Sequence parsing error:", err);
                canvas.innerHTML = `<div style="color: #ef4444; padding: 20px;">Syntax Error: <br/>${err.message}</div>`;
            }
        };

        // UI Events
        renderBtn?.addEventListener('click', renderCode);

        // Ctrl+Enter rendering
        editor?.addEventListener('keydown', (e) => {
            if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                renderCode();
            }
        });

        presetSelect?.addEventListener('change', (e) => {
            const val = e.target.value;
            wrapper.className = wrapper.className.replace(/\bviz-preset-\S+/g, '');
            wrapper.classList.add(`viz-preset-${val}`);
            renderCode();
        });

        // Make it focusable for keyboard shortcuts
        wrapper.setAttribute('tabindex', '0');

        // Initialize Render
        renderCode();
    });
});
