<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{APPLICATION_NAME}} - Analyse métier</title>
    <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
    <script>mermaid.initialize({ startOnLoad: false, theme: 'dark', securityLevel: 'loose' });</script>
    <style>
/* --- 01-variables.css --- */
/* ============================================
   DESIGN SYSTEM - SmartStack Business Analysis
   ============================================ */
:root {
    --primary: #6366f1;
    --primary-dark: #4f46e5;
    --primary-light: #818cf8;
    --secondary: #f97316;
    --accent: #06b6d4;
    --bg-dark: #0f172a;
    --bg-card: #1e293b;
    --bg-hover: #334155;
    --bg-input: #151d2e;
    --text: #b8c4d1;
    --text-muted: #8a9bb0;
    --text-bright: #e2e8f0;
    --border: #334155;
    --border-light: #475569;
    --success: #22c55e;
    --warning: #eab308;
    --error: #ef4444;
    --info: #3b82f6;
    --sidebar-width: 280px;
    --header-height: 52px;
    --transition-fast: 0.15s ease;
    --transition-normal: 0.3s ease;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
    font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
    background: var(--bg-dark);
    color: var(--text);
    line-height: 1.7;
    min-height: 100vh;
}


/* --- 02-layout.css --- */
/* ============================================
   LAYOUT
   ============================================ */
.app { display: flex; flex-direction: column; min-height: 100vh; }

.header {
    background: var(--bg-card);
    border-bottom: 1px solid var(--border);
    height: var(--header-height);
    display: flex;
    align-items: center;
    padding: 0 1.5rem;
    gap: 1rem;
    position: sticky;
    top: 0;
    z-index: 100;
}

.header-logo {
    width: 32px; height: 32px;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    border-radius: 6px;
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.85rem; color: #fff;
    flex-shrink: 0;
}

.header-title { font-size: 1rem; font-weight: 600; color: var(--text-bright); }
.header-sep { width: 1px; height: 24px; background: var(--border); }
.header-app-name { font-size: 0.9rem; color: var(--primary-light); font-weight: 500; }
.header-spacer { flex: 1; }

.header-actions { display: flex; gap: 0.5rem; }

.body { display: flex; flex: 1; }

/* ============================================
   SIDEBAR - Container
   ============================================ */
.sidebar {
    width: var(--sidebar-width);
    background: var(--bg-card);
    border-right: 1px solid var(--border);
    overflow-y: auto;
    height: calc(100vh - var(--header-height));
    position: sticky;
    top: var(--header-height);
    flex-shrink: 0;
}

.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

/* ============================================
   MAIN CONTENT - FULL WIDTH
   ============================================ */
.main {
    flex: 1;
    padding: 2rem 3rem;
    overflow-y: auto;
    height: calc(100vh - var(--header-height));
}

.section { margin-bottom: 4rem; }
.section-title {
    font-size: 1.4rem;
    color: var(--text-bright);
    font-weight: 600;
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 2px solid var(--primary);
}
.section-subtitle {
    font-size: 0.9rem;
    color: var(--text-muted);
    margin-bottom: 1.5rem;
}

/* ============================================
   RESPONSIVE
   ============================================ */
.hamburger-btn {
    display: none;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 1.2rem;
    padding: 0.2rem 0.5rem;
    cursor: pointer;
    flex-shrink: 0;
}
.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 149;
}
.sidebar-overlay.visible { display: block; }

@media (max-width: 768px) {
    .hamburger-btn { display: block; }
    .sidebar {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        height: 100vh;
        z-index: 150;
        box-shadow: 4px 0 24px rgba(0,0,0,0.3);
    }
    .sidebar.mobile-open { display: block; }
    .main { padding: 1rem; }
    .form-row { grid-template-columns: 1fr; }
    .stakeholder-grid { grid-template-columns: 1fr; }
    .module-grid { grid-template-columns: 1fr; }
    .stat-grid { grid-template-columns: repeat(2, 1fr); }
    .dm-entity-grid { grid-template-columns: 1fr; }
    .mock-form-row { grid-template-columns: 1fr; }
    .mock-kpi-grid { grid-template-columns: repeat(2, 1fr); }
    .header-actions { gap: 0.25rem; }
    .header-actions .btn-sm { padding: 0.2rem 0.4rem; font-size: 0.7rem; }
    .header-title { display: none; }
    .header-sep { display: none; }
}

/* ============================================
   SEARCH
   ============================================ */
.sidebar-search {
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
}
.sidebar-search input {
    width: 100%;
    padding: 0.4rem 0.6rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 0.8rem;
    font-family: inherit;
}
.sidebar-search input:focus {
    outline: none;
    border-color: var(--primary);
}
.nav-item.search-hidden { display: none; }
.nav-group.search-hidden { display: none; }
.search-highlight { background: rgba(234,179,8,0.3); border-radius: 2px; }

/* ============================================
   PROGRESS INDICATOR
   ============================================ */
.progress-bar-container {
    width: 100%;
    height: 8px;
    background: var(--bg-hover);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 0.5rem;
}
.progress-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--primary), var(--success));
    border-radius: 4px;
    transition: width 0.5s ease;
}
.progress-label {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 0.75rem;
}
.progress-checks {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0.3rem;
}
.progress-check {
    font-size: 0.8rem;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.progress-check.done { color: var(--success); }
.progress-check-icon { font-size: 0.9rem; width: 16px; text-align: center; }

/* ============================================
   PRINT
   ============================================ */
@media print {
    .sidebar, .header-actions, .add-btn, .uc-actions, .inline-form, .module-card-remove, .hamburger-btn, .sidebar-search { display: none !important; }
    .main { max-width: 100%; padding: 0.5cm; height: auto; overflow: visible; }
    .body { display: block; }
    .section { display: block !important; page-break-inside: avoid; margin-bottom: 1cm; }
    .section + .section { page-break-before: auto; }
    body { background: #fff !important; color: #1a1a1a !important; }
    * { color-adjust: exact; -webkit-print-color-adjust: exact; }
    .card, .uc-item, .br-item, .module-card, .entity-block, .interaction-item {
        border-color: #ddd !important;
        background: #fff !important;
        color: #1a1a1a !important;
    }
    .card-label, .uc-detail-label, .section-subtitle, .form-label { color: #666 !important; }
    .section-title { color: #1a1a1a !important; border-bottom-color: #333 !important; }
    .tab-panel { display: block !important; page-break-inside: avoid; }
    .tab-bar { display: none !important; }
    .review-panel, .comment-btn-container, .notification, .wireframe-comment, [contenteditable] { display: none !important; }
    .editable { border: none !important; padding: 0 !important; }
    .header { position: static; background: #fff !important; border-bottom-color: #ddd !important; }
    .header-logo { background: #333 !important; }
    .header-title, .header-app-name { color: #1a1a1a !important; }
    a { text-decoration: none !important; color: inherit !important; }
}


/* --- 03-navigation.css --- */
/* ============================================
   SIDEBAR - Hierarchical Tree Navigation
   ============================================ */

/* Sidebar header */
.sidebar-header {
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-hover);
}
.sidebar-app-name {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--primary-light);
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Nav groups (top-level: Cadrage, Modules, Consolidation, Synthèse) */
.nav-group { padding: 0.4rem 0; }
.nav-group + .nav-group { border-top: 1px solid var(--border); }

.nav-group-title {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    padding: 0.4rem 1rem;
    margin-bottom: 0.15rem;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    user-select: none;
    transition: color var(--transition-fast);
}
.nav-group-title:hover { color: var(--text-bright); }

/* Chevron icon for expand/collapse */
.nav-chevron {
    font-size: 0.6rem;
    display: inline-block;
    transition: transform var(--transition-fast);
    color: var(--text-muted);
    width: 12px;
    text-align: center;
    flex-shrink: 0;
}
.nav-chevron.expanded { transform: rotate(90deg); }

/* Nav items (leaf nodes) */
.nav-item {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 1rem;
    color: var(--text);
    text-decoration: none;
    font-size: 0.82rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    border-left: 3px solid transparent;
}
.nav-item:hover { background: var(--bg-hover); color: var(--text-bright); }
.nav-item.active {
    background: rgba(99,102,241,0.1);
    border-left-color: var(--primary);
    color: var(--primary-light);
    font-weight: 500;
}

.nav-item .nav-icon {
    font-size: 0.45rem;
    width: 12px;
    text-align: center;
    color: var(--border-light);
    flex-shrink: 0;
}
.nav-item .nav-badge {
    margin-left: auto;
    font-size: 0.6rem;
    background: var(--bg-hover);
    padding: 0.1rem 0.35rem;
    border-radius: 10px;
    color: var(--text-muted);
    min-width: 16px;
    text-align: center;
}

/* Nested children (indented) */
.nav-children { margin-left: 0; }
.nav-children .nav-item { padding-left: 1.6rem; font-size: 0.8rem; }
.nav-children .nav-children .nav-item { padding-left: 2.4rem; font-size: 0.78rem; }
.nav-children .nav-children .nav-children .nav-item { padding-left: 3rem; font-size: 0.75rem; }

/* Module header in nav (collapsible) */
.nav-module-header {
    font-weight: 500;
    color: var(--text-bright);
    font-size: 0.85rem;
}
.nav-module-header:hover { color: var(--primary-light); }

/* Section/Resource items in nav */
.nav-section-item { margin-top: 0.1rem; }
.nav-section-link { font-style: italic; }
.nav-icon-section { font-size: 0.5rem; color: var(--accent); }
.nav-icon-resource { font-size: 0.7rem; color: var(--border-light); }
.nav-resource-link {
    cursor: pointer;
    font-size: 0.72rem;
    color: var(--text-muted);
    padding-top: 0.2rem;
    padding-bottom: 0.2rem;
}
.nav-resource-link:hover { background: var(--bg-hover); color: var(--accent); }
.nav-resources { margin-left: 0.5rem; }


/* --- 04-cards.css --- */
/* ============================================
   BUTTONS
   ============================================ */
.btn {
    padding: 0.4rem 0.9rem;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--bg-hover);
    color: var(--text);
    font-size: 0.8rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    font-family: inherit;
}
.btn:hover { border-color: var(--primary); color: var(--text-bright); }
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); }
.btn-success { background: var(--success); border-color: var(--success); color: #fff; }
.btn-sm { padding: 0.25rem 0.6rem; font-size: 0.75rem; }

/* ============================================
   EDITABLE CARDS
   ============================================ */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.5rem;
    margin-bottom: 1rem;
    transition: border-color var(--transition-fast);
}
.card:hover { border-color: var(--border-light); }

.card-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}
.card-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    font-weight: 600;
}
.card-title {
    font-size: 1.05rem;
    color: var(--text-bright);
    font-weight: 600;
}

.editable {
    border: 1px dashed transparent;
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    transition: all var(--transition-fast);
    min-height: 1.5em;
    outline: none;
}
.editable:hover { border-color: var(--border-light); background: var(--bg-input); }
.editable:focus { border-color: var(--primary); background: var(--bg-input); box-shadow: 0 0 0 2px rgba(99,102,241,0.2); }
.editable[data-placeholder]:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    font-style: italic;
}

/* ============================================
   PRIORITY BADGES
   ============================================ */
.priority {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.6rem;
    border-radius: 12px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.priority-inscope { background: rgba(59,130,246,0.15); color: #60a5fa; border: 1px solid rgba(59,130,246,0.3); }
.priority-outofscope { background: rgba(100,116,139,0.15); color: #94a3b8; border: 1px solid rgba(100,116,139,0.3); }

/* ============================================
   STATUS BADGES
   ============================================ */
.status {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.15rem 0.5rem; border-radius: 10px;
    font-size: 0.7rem; font-weight: 500;
}
.status-dot { width: 6px; height: 6px; border-radius: 50%; }
.status-draft .status-dot { background: var(--text-muted); }
.status-draft { color: var(--text-muted); }
.status-progress .status-dot { background: var(--info); }
.status-progress { color: var(--info); }
.status-done .status-dot { background: var(--success); }
.status-done { color: var(--success); }

/* ============================================
   ADD BUTTON
   ============================================ */
.add-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.75rem;
    border: 2px dashed var(--border);
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    font-family: inherit;
}
.add-btn:hover {
    border-color: var(--primary);
    color: var(--primary-light);
    background: rgba(99,102,241,0.05);
}

/* ============================================
   INLINE FORM (for adding items)
   ============================================ */
.inline-form {
    background: var(--bg-card);
    border: 2px solid var(--primary);
    border-radius: 10px;
    padding: 1.25rem;
    margin-bottom: 1rem;
    display: none;
}
.inline-form.visible { display: block; }
.inline-form-title {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--primary-light);
    margin-bottom: 1rem;
}
.form-group { margin-bottom: 0.75rem; }
.form-label {
    display: block;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
    font-weight: 500;
}
.form-input, .form-textarea, .form-select {
    width: 100%;
    padding: 0.5rem 0.75rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 0.85rem;
    font-family: inherit;
    transition: border-color var(--transition-fast);
}
.form-input:focus, .form-textarea:focus, .form-select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 2px rgba(99,102,241,0.2);
}
.form-textarea { min-height: 80px; resize: vertical; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.form-actions {
    display: flex; gap: 0.5rem; justify-content: flex-end;
    margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--border);
}

/* ============================================
   NOTIFICATION BAR
   ============================================ */
.notification {
    position: fixed;
    bottom: 1.5rem;
    right: 1.5rem;
    padding: 0.75rem 1.25rem;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 500;
    z-index: 200;
    transform: translateY(100px);
    opacity: 0;
    transition: all 0.3s ease;
}
.notification.visible { transform: translateY(0); opacity: 1; }
.notification-success { background: var(--success); color: #fff; }
.notification-info { background: var(--info); color: #fff; }


/* --- 05-modules.css --- */
/* ============================================
   USE CASE LIST
   ============================================ */
.uc-list { list-style: none; }

.uc-item {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1rem 1.25rem;
    margin-bottom: 0.75rem;
    transition: border-color var(--transition-fast);
}
.uc-item:hover { border-color: var(--border-light); }

.uc-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}
.uc-id {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--primary-light);
    background: rgba(99,102,241,0.1);
    padding: 0.15rem 0.5rem;
    border-radius: 4px;
}
.uc-title { font-weight: 600; color: var(--text-bright); flex: 1; }
.uc-actions { display: flex; gap: 0.3rem; opacity: 0; transition: opacity var(--transition-fast); }
.uc-item:hover .uc-actions { opacity: 1; }

.uc-detail { font-size: 0.875rem; color: var(--text); }
.uc-detail-label { color: var(--text-muted); font-size: 0.75rem; font-weight: 600; margin-top: 0.5rem; }

.uc-actors {
    display: flex; gap: 0.4rem; margin-top: 0.3rem; flex-wrap: wrap;
}
.uc-actor {
    font-size: 0.7rem;
    padding: 0.1rem 0.4rem;
    background: rgba(6,182,212,0.1);
    color: var(--accent);
    border-radius: 4px;
    border: 1px solid rgba(6,182,212,0.2);
}

/* ============================================
   BUSINESS RULE LIST
   ============================================ */
.br-item {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.5rem;
}
.br-category {
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    padding: 0.15rem 0.4rem;
    border-radius: 4px;
    flex-shrink: 0;
    min-width: 70px;
    text-align: center;
}
.br-cat-validation { background: rgba(99,102,241,0.15); color: var(--primary-light); }
.br-cat-calculation { background: rgba(234,179,8,0.15); color: #facc15; }
.br-cat-workflow { background: rgba(249,115,22,0.15); color: var(--secondary); }
.br-cat-security { background: rgba(239,68,68,0.15); color: #f87171; }
.br-cat-data { background: rgba(6,182,212,0.15); color: var(--accent); }
.br-text { flex: 1; font-size: 0.875rem; }

/* ============================================
   STAKEHOLDER TABLE
   ============================================ */
.stakeholder-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1rem;
}
.stakeholder-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1rem;
}
.stakeholder-card:hover { border-color: var(--border-light); }
.stakeholder-role { font-weight: 600; color: var(--text-bright); margin-bottom: 0.25rem; }
.stakeholder-function { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 0.5rem; }
.stakeholder-tasks { list-style: none; }
.stakeholder-tasks li {
    font-size: 0.8rem;
    padding: 0.15rem 0;
    color: var(--text);
}
.stakeholder-tasks li::before { content: "- "; color: var(--primary-light); }
.stakeholder-meta {
    display: flex; gap: 0.75rem; margin-top: 0.5rem; padding-top: 0.5rem;
    border-top: 1px solid var(--border);
}
.stakeholder-meta span { font-size: 0.7rem; color: var(--text-muted); }

/* ============================================
   PROCESS FLOW
   ============================================ */
.process-flow {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    overflow-x: auto;
    padding: 1rem 0;
}
.process-step {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.75rem 1rem;
    min-width: 140px;
    text-align: center;
    flex-shrink: 0;
}
.process-step:hover { border-color: var(--primary); }
.process-step-number {
    font-size: 0.65rem;
    color: var(--primary-light);
    font-weight: 700;
}
.process-step-label { font-size: 0.8rem; color: var(--text-bright); font-weight: 500; }
.process-arrow { color: var(--text-muted); font-size: 1.2rem; flex-shrink: 0; }

/* ============================================
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    gap: 1rem;
    align-items: center;
    padding: 0.75rem 1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.5rem;
}
    width: 10px; height: 10px;
    border-radius: 50%;
}
    font-size: 0.7rem;
    color: var(--text-muted);
    text-align: center;
}
/* ============================================
   MODULE CARDS (Decomposition)
   ============================================ */
.module-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 1rem;
}
.module-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    position: relative;
}
.module-card:hover { border-color: var(--primary); }
.module-card.selected { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(99,102,241,0.2); }
.module-card-header { display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.5rem; }
.module-card-code { font-weight: 700; color: var(--text-bright); font-size: 1rem; }
.module-card-type {
    font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em;
    padding: 0.15rem 0.5rem; border-radius: 4px;
    background: rgba(99,102,241,0.1); color: var(--primary-light);
}
.module-card-desc { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 0.5rem; }
.module-card-meta { display: flex; gap: 0.75rem; font-size: 0.7rem; color: var(--text-muted); }
.module-card-meta span { display: flex; align-items: center; gap: 0.2rem; }
.module-card-remove {
    position: absolute; top: 0.5rem; right: 0.5rem;
    background: none; border: none; color: var(--text-muted);
    cursor: pointer; font-size: 0.8rem; opacity: 0;
    transition: opacity var(--transition-fast);
}
.module-card:hover .module-card-remove { opacity: 1; }
.module-card-remove:hover { color: var(--error); }

/* ============================================
   TABS (Module Specification)
   ============================================ */
.tab-bar {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1.5rem;
    overflow-x: auto;
}
.tab-btn {
    padding: 0.6rem 1rem;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: all var(--transition-fast);
}
.tab-btn:hover { color: var(--text-bright); background: var(--bg-hover); }
.tab-btn.active { color: var(--primary-light); border-bottom-color: var(--primary); font-weight: 500; }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ============================================
   ENTITY TABLE
   ============================================ */
.entity-block {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-bottom: 1rem;
    overflow: hidden;
}
.entity-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.75rem 1rem;
    background: var(--bg-hover);
    border-bottom: 1px solid var(--border);
}
.entity-name { font-weight: 600; color: var(--text-bright); }
.entity-desc { font-size: 0.8rem; color: var(--text-muted); }
.attr-table { width: 100%; border-collapse: collapse; }
.attr-table th {
    text-align: left; font-size: 0.7rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--text-muted); padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border); font-weight: 600;
}
.attr-table td {
    padding: 0.5rem 0.75rem; font-size: 0.85rem;
    border-bottom: 1px solid rgba(51,65,85,0.3);
}
.attr-required { color: var(--error); font-weight: 700; }

/* ============================================
   DEPENDENCY VISUALIZATION
   ============================================ */
.dep-graph {
    display: flex; flex-direction: column; gap: 1.5rem;
    padding: 1.5rem; background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 10px;
}
.dep-layer {
    display: flex; align-items: center; gap: 1rem;
}
.dep-layer-label {
    font-size: 0.7rem; color: var(--text-muted); text-transform: uppercase;
    letter-spacing: 0.05em; min-width: 80px; font-weight: 600;
}
.dep-layer-modules { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.dep-module {
    padding: 0.4rem 0.8rem; border-radius: 6px;
    background: rgba(99,102,241,0.1); border: 1px solid rgba(99,102,241,0.3);
    color: var(--primary-light); font-size: 0.8rem; font-weight: 500;
}
.dep-arrow {
    text-align: center; color: var(--text-muted); font-size: 1.2rem;
    padding-left: 80px;
}

/* ============================================
   STAT CARDS (Handoff)
   ============================================ */
.stat-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem; margin-bottom: 1.5rem;
}
.stat-card {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 10px; padding: 1rem; text-align: center;
}
.stat-value { font-size: 1.8rem; font-weight: 700; color: var(--text-bright); }
.stat-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem; }

/* ============================================
   CONSOLIDATION
   ============================================ */
.interaction-item {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.75rem 1rem; background: var(--bg-card);
    border: 1px solid var(--border); border-radius: 8px;
    margin-bottom: 0.5rem; font-size: 0.85rem;
}
.interaction-arrow { color: var(--primary-light); font-weight: 700; font-size: 1.1rem; }
.interaction-type {
    font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em;
    padding: 0.15rem 0.4rem; border-radius: 4px;
    background: rgba(6,182,212,0.1); color: var(--accent);
}
.e2e-flow {
    display: flex; align-items: center; gap: 0.3rem;
    overflow-x: auto; padding: 1rem 0;
}
.e2e-step {
    padding: 0.5rem 0.75rem; border-radius: 6px; text-align: center;
    font-size: 0.75rem; flex-shrink: 0;
    background: var(--bg-card); border: 1px solid var(--border);
}
.e2e-step-module { font-weight: 600; color: var(--primary-light); font-size: 0.65rem; }
.e2e-step-action { color: var(--text-bright); }

/* ============================================
   DATA MODEL (Consolidation)
   ============================================ */
.dm-summary {
    display: flex; gap: 1.5rem; margin-bottom: 1.5rem;
    padding: 1rem 1.5rem; background: var(--bg-card);
    border: 1px solid var(--border); border-radius: 10px;
}
.dm-summary-item { display: flex; align-items: baseline; gap: 0.4rem; }
.dm-summary-value { font-size: 1.4rem; font-weight: 700; color: var(--text-bright); }
.dm-summary-label { font-size: 0.8rem; color: var(--text-muted); }
.dm-module-group { margin-bottom: 1.5rem; }
.dm-module-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.5rem 0; margin-bottom: 0.75rem;
    border-bottom: 2px solid var(--primary);
}
.dm-module-name { font-weight: 700; color: var(--primary-light); font-size: 1rem; }
.dm-module-count { font-size: 0.75rem; color: var(--text-muted); }
.dm-entity-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 1rem;
}
.dm-entity-card {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 10px; overflow: hidden;
    transition: border-color var(--transition-fast);
}
.dm-entity-card:hover { border-color: var(--border-light); }
.dm-entity-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.6rem 0.75rem; background: var(--bg-hover);
    border-bottom: 1px solid var(--border);
}
.dm-entity-name { font-weight: 600; color: var(--text-bright); font-size: 0.95rem; }
.dm-entity-attr-count {
    font-size: 0.65rem; color: var(--text-muted);
    background: rgba(99,102,241,0.1); padding: 0.1rem 0.4rem; border-radius: 4px;
}
.dm-entity-desc {
    padding: 0.5rem 0.75rem; font-size: 0.8rem; color: var(--text-muted);
    border-bottom: 1px solid var(--border);
}
.dm-attr-table { width: 100%; border-collapse: collapse; }
.dm-attr-table th {
    text-align: left; font-size: 0.65rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--text-muted); padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--border); font-weight: 600;
}
.dm-attr-table td { padding: 0.35rem 0.75rem; font-size: 0.8rem; border-bottom: 1px solid rgba(51,65,85,0.2); }
.dm-attr-name { font-weight: 500; color: var(--text-bright); white-space: nowrap; }
.dm-attr-desc { color: var(--text-muted); }
.dm-relations {
    padding: 0.5rem 0.75rem; border-top: 1px solid var(--border);
    background: rgba(6,182,212,0.03);
}
.dm-relations-title {
    font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--accent); font-weight: 600; margin-bottom: 0.3rem;
}
.dm-relation-item {
    font-size: 0.8rem; color: var(--text); padding: 0.15rem 0;
    padding-left: 0.75rem; border-left: 2px solid var(--accent);
    margin-bottom: 0.2rem;
}

/* ============================================
   STRUCTURE TAB (Sections/Resources)
   ============================================ */
.struct-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-bottom: 1rem;
    overflow: hidden;
}
.struct-section-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--bg-hover);
    border-bottom: 1px solid var(--border);
}
.struct-section-code {
    font-weight: 600;
    color: var(--text-bright);
    font-size: 0.95rem;
}
.struct-section-desc {
    flex: 1;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.struct-section-badge {
    font-size: 0.65rem;
    color: var(--text-muted);
    background: rgba(99,102,241,0.1);
    padding: 0.1rem 0.5rem;
    border-radius: 4px;
    white-space: nowrap;
}
.struct-resources {
    padding: 0.5rem 0;
}
.struct-resource {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.35rem 1rem 0.35rem 1.5rem;
    font-size: 0.85rem;
    transition: background var(--transition-fast);
}
.struct-resource:hover {
    background: var(--bg-hover);
}
.struct-resource-icon {
    color: var(--primary-light);
    font-size: 0.7rem;
    flex-shrink: 0;
}
.struct-resource-name {
    font-weight: 500;
    color: var(--text-bright);
}
.struct-resource-desc {
    font-size: 0.8rem;
    color: var(--text-muted);
}

/* ============================================
   STRUCTURE LEGEND
   ============================================ */
.struct-legend {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 0.75rem 1rem;
    margin-bottom: 1.25rem;
}
.struct-legend-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 0.5rem;
}
.struct-legend-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.4rem 1.5rem;
}
.struct-legend-item {
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.4;
}
.struct-legend-code {
    display: inline-block;
    font-weight: 600;
    color: var(--accent);
    background: rgba(6,182,212,0.1);
    padding: 0.05rem 0.4rem;
    border-radius: 3px;
    font-size: 0.72rem;
    margin-right: 0.3rem;
    font-family: monospace;
}

/* ============================================
   SECTION GROUPS (Hierarchical Mode)
   ============================================ */
.section-group {
    margin-bottom: 1.5rem;
    border-left: 3px solid var(--primary);
    padding-left: 0;
}
.section-group-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: rgba(99,102,241,0.05);
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.5rem;
    border-radius: 0 6px 0 0;
}
.section-group-icon {
    font-size: 0.6rem;
    color: var(--primary-light);
}
.section-group-label {
    font-weight: 600;
    color: var(--primary-light);
    font-size: 0.9rem;
}
.section-group-route {
    font-size: 0.7rem;
    color: var(--text-muted);
    font-family: 'Courier New', monospace;
    background: var(--bg-input);
    padding: 0.1rem 0.4rem;
    border-radius: 3px;
}


/* --- 06-wireframes.css --- */
/* ============================================
   MOCKUP FRAME
   ============================================ */
.mockup-frame {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    overflow: hidden;
    margin: 1rem 0;
}
.mockup-toolbar {
    background: var(--bg-hover);
    padding: 0.5rem 1rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border-bottom: 1px solid var(--border);
}
.mockup-dot { width: 8px; height: 8px; border-radius: 50%; }
.mockup-dot-red { background: #ef4444; }
.mockup-dot-yellow { background: #eab308; }
.mockup-dot-green { background: #22c55e; }
.mockup-title {
    font-size: 0.75rem; color: var(--text-muted);
    margin-left: 0.5rem;
}

.mockup-content {
    padding: 1.5rem;
    min-height: 200px;
}

.wireframe-comment {
    padding: 0.75rem 1.5rem 1rem;
    border-top: 1px solid var(--border);
    background: var(--bg-input);
    border-radius: 0 0 10px 10px;
}

/* Wireframe rendering */
.ascii-wireframe {
    font-family: 'Courier New', 'Consolas', monospace;
    font-size: 0.7rem;
    line-height: 1.3;
    color: var(--primary-light);
    background: var(--bg-dark);
    padding: 1rem;
    border-radius: 6px;
    overflow-x: auto;
    white-space: pre;
    margin: 0;
}

.svg-wireframe {
    background: var(--bg-dark);
    padding: 1rem;
    border-radius: 6px;
    overflow-x: auto;
}

.svg-wireframe svg {
    max-width: 100%;
    height: auto;
    display: block;
}

/* ============================================
   WIREFRAME VIEW TOGGLE (SVG / ASCII)
   ============================================ */
.wireframe-toggle {
    display: flex;
    gap: 2px;
    background: var(--bg-dark);
    border-radius: 6px;
    padding: 2px;
    border: 1px solid var(--border);
    margin-left: auto;
}

.wireframe-toggle-btn {
    padding: 0.25rem 0.6rem;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.02em;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    background: transparent;
    color: var(--text-muted);
    transition: all 0.15s ease;
    font-family: inherit;
}

.wireframe-toggle-btn:hover {
    color: var(--text-bright);
    background: var(--bg-hover);
}

.wireframe-toggle-btn.active {
    background: var(--primary);
    color: #ffffff;
}

.wireframe-view:not(.active) {
    display: none;
}

.wireframe-description {
    padding: 0.75rem 1rem;
    font-size: 0.85rem;
    color: var(--text);
    border-top: 1px solid var(--border);
    background: var(--bg-input);
}

.wireframe-metadata {
    padding: 0.75rem 1rem;
    font-size: 0.8rem;
    color: var(--text-muted);
    border-top: 1px solid var(--border);
}

.wireframe-details {
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--border);
    background: var(--bg-input);
}

.wireframe-details summary {
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--primary-light);
    font-weight: 500;
    user-select: none;
}

.wireframe-details summary:hover {
    color: var(--primary);
}

.mapping-table {
    width: 100%;
    margin-top: 0.75rem;
    border-collapse: collapse;
    font-size: 0.8rem;
}

.mapping-table th {
    background: var(--bg-hover);
    padding: 0.5rem;
    text-align: left;
    font-weight: 500;
    color: var(--text-bright);
    border: 1px solid var(--border);
}

.mapping-table td {
    padding: 0.5rem;
    border: 1px solid var(--border);
    color: var(--text);
}

.mapping-table code {
    background: var(--bg-dark);
    padding: 0.2rem 0.4rem;
    border-radius: 3px;
    font-size: 0.75rem;
    color: var(--accent);
}

/* Mockup components */
.mock-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 1rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border);
}
.mock-title { font-size: 1.1rem; font-weight: 600; color: var(--text-bright); }
.mock-btn {
    padding: 0.35rem 0.8rem;
    background: var(--primary);
    color: #fff;
    border-radius: 6px;
    font-size: 0.8rem;
    font-weight: 500;
}
.mock-search {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.4rem 0.8rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    margin-bottom: 1rem;
    color: var(--text-muted);
    font-size: 0.8rem;
}
.mock-table {
    width: 100%;
    border-collapse: collapse;
}
.mock-table th {
    text-align: left;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
    font-weight: 600;
}
.mock-table td {
    padding: 0.6rem 0.75rem;
    font-size: 0.85rem;
    border-bottom: 1px solid rgba(51,65,85,0.5);
}
.mock-table tr:hover td { background: rgba(99,102,241,0.05); }

.mock-status {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.15rem 0.5rem; border-radius: 10px; font-size: 0.75rem;
}
.mock-status-active { background: rgba(34,197,94,0.15); color: #4ade80; }
.mock-status-pending { background: rgba(234,179,8,0.15); color: #facc15; }
.mock-status-draft { background: rgba(100,116,139,0.15); color: #94a3b8; }

.mock-form-group { margin-bottom: 1rem; }
.mock-label {
    display: block;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
    font-weight: 500;
}
.mock-input {
    width: 100%;
    padding: 0.5rem 0.75rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 0.85rem;
}
.mock-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.mock-form-actions {
    display: flex; gap: 0.5rem; justify-content: flex-end;
    padding-top: 1rem; border-top: 1px solid var(--border);
}

/* Dashboard mockup */
.mock-kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1.5rem; }
.mock-kpi {
    background: var(--bg-hover);
    border-radius: 8px;
    padding: 0.75rem;
    text-align: center;
}
.mock-kpi-value { font-size: 1.3rem; font-weight: 700; color: var(--text-bright); }
.mock-kpi-label { font-size: 0.7rem; color: var(--text-muted); margin-top: 0.2rem; }
@media (max-width: 768px) {
    .mock-kpi-grid { grid-template-columns: repeat(2, 1fr); }
}


/* --- 07-comments.css --- */
/* ============================================
   INLINE COMMENTS
   ============================================ */
.comment-btn-container {
    margin-top: 0.75rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
}

.comment-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.75rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    font-family: inherit;
}
.comment-toggle-btn:hover {
    border-color: var(--primary);
    color: var(--primary-light);
    background: rgba(99,102,241,0.05);
}
.comment-toggle-btn .comment-count {
    background: var(--primary);
    color: #fff;
    padding: 0.05rem 0.35rem;
    border-radius: 8px;
    font-size: 0.65rem;
    font-weight: 700;
    min-width: 16px;
    text-align: center;
}
.comment-toggle-btn .comment-count.empty {
    background: var(--bg-hover);
    color: var(--text-muted);
}

/* Comment thread under a card */
.comment-thread {
    margin-top: 0.5rem;
    display: none;
}
.comment-thread.visible { display: block; }

.comment-item {
    display: flex;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.4rem;
    font-size: 0.8rem;
    align-items: flex-start;
}

.comment-avatar {
    width: 28px; height: 28px;
    border-radius: 50%;
    background: var(--primary);
    display: flex; align-items: center; justify-content: center;
    color: #fff; font-size: 0.65rem; font-weight: 700;
    flex-shrink: 0;
}

.comment-body { flex: 1; min-width: 0; }

.comment-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.2rem;
}

.comment-author {
    font-weight: 600;
    color: var(--text-bright);
    font-size: 0.75rem;
}

.comment-date {
    font-size: 0.65rem;
    color: var(--text-muted);
}

.comment-category {
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.1rem 0.35rem;
    border-radius: 4px;
    font-weight: 600;
}
.comment-category-clarification { background: rgba(59,130,246,0.15); color: var(--info); }
.comment-category-correction { background: rgba(239,68,68,0.15); color: #f87171; }
.comment-category-suggestion { background: rgba(34,197,94,0.15); color: #4ade80; }

.comment-status {
    font-size: 0.6rem;
    padding: 0.1rem 0.35rem;
    border-radius: 4px;
    font-weight: 600;
    margin-left: auto;
}
.comment-status-to-review { background: rgba(234,179,8,0.15); color: #facc15; }
.comment-status-validated { background: rgba(34,197,94,0.15); color: #4ade80; }

.comment-text {
    color: var(--text);
    line-height: 1.5;
    word-wrap: break-word;
}

.comment-actions {
    display: flex;
    gap: 0.3rem;
    margin-top: 0.3rem;
}

.comment-action-btn {
    padding: 0.15rem 0.4rem;
    border: none;
    background: none;
    color: var(--text-muted);
    font-size: 0.7rem;
    cursor: pointer;
    border-radius: 4px;
    font-family: inherit;
}
.comment-action-btn:hover { background: var(--bg-hover); color: var(--text-bright); }

/* Add comment form */
.comment-add-form {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.4rem;
    align-items: flex-start;
}

.comment-add-form textarea {
    flex: 1;
    padding: 0.4rem 0.6rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 0.8rem;
    font-family: inherit;
    min-height: 36px;
    resize: vertical;
}
.comment-add-form textarea:focus {
    outline: none;
    border-color: var(--primary);
}

.comment-add-form select {
    padding: 0.4rem 0.5rem;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-size: 0.75rem;
    font-family: inherit;
}

.comment-add-form button {
    padding: 0.4rem 0.7rem;
    background: var(--primary);
    border: none;
    border-radius: 6px;
    color: #fff;
    font-size: 0.75rem;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
}
.comment-add-form button:hover { background: var(--primary-dark); }


/* --- 08-review-panel.css --- */
/* ============================================
   REVIEW PANEL - Right sidebar
   ============================================ */

/* Toggle button in header */
.review-toggle-btn {
    position: relative;
    padding: 0.4rem 0.9rem;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--bg-hover);
    color: var(--text);
    font-size: 0.8rem;
    cursor: pointer;
    transition: all var(--transition-fast);
    font-family: inherit;
}
.review-toggle-btn:hover { border-color: var(--primary); color: var(--text-bright); }
.review-toggle-btn.active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.review-badge {
    position: absolute;
    top: -6px; right: -6px;
    background: var(--error);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    padding: 0.1rem 0.35rem;
    border-radius: 8px;
    min-width: 16px;
    text-align: center;
}
.review-badge.hidden { display: none; }

/* Layout adaptation when panel is open */
.body.review-open {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr 340px;
}

.body.review-open .main {
    overflow-y: auto;
}

/* Panel itself */
.review-panel {
    display: none;
    width: 340px;
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    height: calc(100vh - var(--header-height));
    position: sticky;
    top: var(--header-height);
    overflow-y: auto;
    flex-shrink: 0;
}

.review-panel.visible { display: flex; flex-direction: column; }

.review-panel-header {
    padding: 1rem;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.review-panel-title {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-bright);
}

.review-panel-close {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1.1rem;
    padding: 0.2rem;
}
.review-panel-close:hover { color: var(--text-bright); }

/* Filters */
.review-filters {
    display: flex;
    gap: 0.3rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
}

.review-filter-btn {
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.7rem;
    cursor: pointer;
    font-family: inherit;
    transition: all var(--transition-fast);
}
.review-filter-btn:hover { border-color: var(--primary); color: var(--text-bright); }
.review-filter-btn.active {
    background: rgba(99,102,241,0.15);
    border-color: var(--primary);
    color: var(--primary-light);
    font-weight: 500;
}

/* Comment list in panel */
.review-comments {
    flex: 1;
    overflow-y: auto;
    padding: 0.75rem;
}

.review-comment-item {
    padding: 0.75rem;
    background: var(--bg-dark);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.5rem;
    cursor: pointer;
    transition: all var(--transition-fast);
}
.review-comment-item:hover { border-color: var(--primary); }

.review-comment-section {
    font-size: 0.65rem;
    color: var(--accent);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.3rem;
}

.review-comment-text {
    font-size: 0.8rem;
    color: var(--text);
    margin-bottom: 0.4rem;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.review-comment-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.review-comment-author {
    font-size: 0.7rem;
    color: var(--text-muted);
}

.review-comment-actions {
    display: flex;
    gap: 0.2rem;
}

.review-action-btn {
    padding: 0.2rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.65rem;
    cursor: pointer;
    font-family: inherit;
    transition: all var(--transition-fast);
}
.review-action-btn:hover { border-color: var(--primary); color: var(--text-bright); }
.review-action-btn.validate { border-color: rgba(34,197,94,0.3); color: var(--success); }
.review-action-btn.validate:hover { background: rgba(34,197,94,0.1); }
.review-action-btn.reject { border-color: rgba(234,179,8,0.3); color: var(--warning); }
.review-action-btn.reject:hover { background: rgba(234,179,8,0.1); }
.review-action-btn.delete { border-color: rgba(239,68,68,0.3); color: var(--error); }
.review-action-btn.delete:hover { background: rgba(239,68,68,0.1); }

/* Empty state */
.review-empty {
    text-align: center;
    padding: 2rem 1rem;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Stats summary */
.review-stats {
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: space-around;
    font-size: 0.75rem;
}

.review-stat {
    text-align: center;
}
.review-stat-value {
    font-weight: 700;
    color: var(--text-bright);
    font-size: 1.1rem;
}
.review-stat-label {
    color: var(--text-muted);
    font-size: 0.65rem;
}

/* Review save button */
.btn-review {
    background: var(--success);
    color: #fff;
    border-color: var(--success);
    font-weight: 600;
}
.btn-review:hover {
    background: #16a34a;
    border-color: #16a34a;
}

@media (max-width: 768px) {
    .body.review-open {
        grid-template-columns: 1fr;
    }
    .review-panel {
        position: fixed;
        right: 0;
        top: var(--header-height);
        z-index: 90;
        box-shadow: -4px 0 20px rgba(0,0,0,0.3);
    }
}


/* --- 09-mockups-html.css --- */
/* ============================================
   HTML MOCKUPS - Realistic component previews
   ============================================ */

/* Screen section container */
.screen-section {
    margin-bottom: 2rem;
}

.screen-section h3 {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* Mockup frame enhancements for HTML mockups */
.mockup-frame .mock-header {
    margin-bottom: 1rem;
}

/* SmartTable inside mockups */
.mockup-content .mock-table {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}

.mockup-content .mock-table th {
    background: var(--bg-hover);
}

/* SmartForm tabs */
.mockup-content .form-tab-bar {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1.5rem;
}

.mockup-content .form-tab {
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
}

.mockup-content .form-tab.active {
    border-bottom-color: var(--primary);
    color: var(--primary-light);
}

/* SmartKanban columns */
.mockup-content .kanban-board {
    display: flex;
    gap: 1rem;
    overflow-x: auto;
    padding-bottom: 0.5rem;
}

.mockup-content .kanban-column {
    min-width: 200px;
    flex: 1;
    background: var(--bg-hover);
    border-radius: 8px;
    padding: 0.75rem;
}

.mockup-content .kanban-column-header {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--text-bright);
    margin-bottom: 0.75rem;
    display: flex;
    justify-content: space-between;
}

.mockup-content .kanban-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.5rem;
    margin-bottom: 0.5rem;
    font-size: 0.8rem;
}

/* SmartDashboard KPI */
.mockup-content .mock-kpi-grid {
    margin-bottom: 1.5rem;
}

/* SmartFilter pills */
.mockup-content .filter-pill {
    padding: 0.3rem 0.7rem;
    border-radius: 16px;
    font-size: 0.8rem;
    cursor: pointer;
    transition: all var(--transition-fast);
}

.mockup-content .filter-pill:hover {
    background: var(--bg-hover);
    border-color: var(--primary);
}

.mockup-content .filter-pill.active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}

/* Subtable in forms */
.mockup-content .subtable-container {
    margin: 1rem 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.mockup-content .subtable-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.5rem 0.75rem;
    background: var(--bg-hover);
}

/* Permission annotation in mockup toolbar */
.mockup-toolbar .permission-badge {
    margin-left: auto;
    font-size: 0.65rem;
    color: var(--text-muted);
    background: var(--bg-dark);
    padding: 0.15rem 0.5rem;
    border-radius: 4px;
}

/* ---- Mock Charts (SVG previews) ---- */
.mock-chart-container {
    margin: 0.75rem 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.mock-chart-header {
    padding: 0.5rem 0.75rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-bright);
    background: var(--bg-hover);
    border-bottom: 1px solid var(--border);
}

.mock-chart-body {
    padding: 1rem;
}

.mock-pie-svg {
    width: 120px;
    height: 120px;
    flex-shrink: 0;
}

.mock-bar-svg,
.mock-line-svg {
    width: 100%;
    height: 140px;
}

.mock-chart-legend {
    font-size: 0.8rem;
    color: var(--text);
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.mock-legend-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    margin-right: 0.4rem;
    vertical-align: middle;
}

/* ---- Form Tab Switching ---- */
.mock-form-tab-bar {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1.5rem;
}

.mock-form-tab {
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    transition: all var(--transition-fast);
}

.mock-form-tab:hover {
    color: var(--text);
}

.mock-form-tab.active {
    border-bottom-color: var(--primary);
    color: var(--primary-light);
}

.mock-form-tab-content {
    display: none;
}

.mock-form-tab-content.active {
    display: block;
}


/* --- 10-diagrams.css --- */
/* ==========================================
   MERMAID DIAGRAMS
   ========================================== */

.diagram-container {
    margin: 1.5rem 0;
    padding: 1rem;
    background: var(--bg-card);
    border-radius: 8px;
    border: 1px solid var(--border);
    overflow-x: auto;
}

.diagram-container h3,
.diagram-container h4 {
    color: var(--text-bright);
    margin-bottom: 1rem;
    font-size: 1.1rem;
}

.diagram-container .mermaid {
    display: flex;
    justify-content: center;
    min-height: 200px;
}

.diagram-container .mermaid svg {
    max-width: 100%;
    height: auto;
}

/* ERD specific */
.diagram-erd {
    margin-bottom: 2rem;
    border-left: 3px solid var(--primary);
}

/* State machine specific */
.diagram-state-machine {
    border-left: 3px solid var(--accent);
}

/* Sequence diagram specific */
.diagram-sequence {
    border-left: 3px solid var(--success);
}

/* Diagram section header */
.diagram-section-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
    color: var(--text-bright);
    font-size: 1.2rem;
    font-weight: 600;
}

.diagram-section-header::before {
    content: '';
    width: 4px;
    height: 1.2em;
    background: var(--primary);
    border-radius: 2px;
}

/* No diagrams fallback */
.diagram-empty {
    color: var(--text-muted);
    font-style: italic;
    padding: 1rem;
    text-align: center;
}

    </style>
</head>
<body>
    <div class="app">
        <!-- ============================================
             HEADER
             ============================================ -->
        <header class="header" role="banner">
            <button class="hamburger-btn" onclick="toggleMobileSidebar()" aria-label="Ouvrir le menu de navigation">&#9776;</button>
            <div class="header-logo" aria-hidden="true">BA</div>
            <span class="header-title">Analyse métier</span>
            <div class="header-sep"></div>
            <span class="header-app-name" id="appName">{{APPLICATION_NAME}}</span>
            <div class="header-spacer"></div>
            <div class="header-actions">
                <button class="btn btn-sm" onclick="resetToEmbedded()" title="Réinitialiser depuis les données d'origine (supprime les modifications locales)" aria-label="Réinitialiser les données">Reset</button>
                <button class="btn btn-sm" onclick="saveToLocalStorage()" title="Sauvegarder les modifications dans le navigateur" aria-label="Sauvegarder">Sauvegarder</button>
                <button class="btn btn-sm btn-review" onclick="saveReviewJSON()" title="Sauvegarder les corrections pour créer une nouvelle version" aria-label="Sauvegarder les corrections">Sauvegarder corrections</button>
                <button class="btn btn-sm btn-primary" onclick="exportJSON()" title="Exporter les données au format JSON pour l'extraction" aria-label="Exporter en JSON">Exporter JSON</button>
                <button class="btn btn-sm review-toggle-btn" id="reviewToggleBtn" onclick="toggleReviewPanel()" title="Ouvrir/fermer le panneau de review" aria-label="Panneau de review">
                    Review
                    <span class="review-badge hidden" id="reviewBadge" aria-live="polite">0</span>
                </button>
            </div>
        </header>

        <div class="body" id="appBody">
            <!-- ============================================
                 SIDEBAR - Navigation hiérarchique
                 ============================================ -->
            <div class="sidebar-overlay" id="sidebarOverlay" onclick="toggleMobileSidebar()"></div>
            <aside class="sidebar" id="sidebarAside" role="navigation" aria-label="Navigation principale">
                <!-- Application Name -->
                <div class="sidebar-header">
                    <span class="sidebar-app-name" id="sidebarAppName">{{APPLICATION_NAME}}</span>
                </div>
                <!-- Search -->
                <div class="sidebar-search">
                    <input type="search" id="sidebarSearchInput" placeholder="Rechercher..." oninput="filterNavItems(this.value)" aria-label="Rechercher dans le document">
                </div>
                <!-- Dynamic Tree Navigation -->
                <div id="sidebarNav">
                    <!-- Populated by buildNavTree() -->
                </div>
            </aside>

            <!-- ============================================
                 MAIN CONTENT
                 ============================================ -->
            <main class="main" id="mainContent" role="main">

                <!-- SECTION: Contexte (merged: problem + current + vision) -->
                <div class="section" id="cadrage-context">
                    <h2 class="section-title">Contexte du projet</h2>
                    <p class="section-subtitle">Vue synthétique du besoin : problème, situation actuelle et objectif visé.</p>

                    <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-bottom:1.5rem;">
                        <div class="card" style="border-left:3px solid #f87171;">
                            <div class="card-label" style="color:#f87171;">Problème identifié</div>
                            <div class="editable" contenteditable="true" data-field="context.problem" data-placeholder="Quel problème ce projet doit-il résoudre ?"></div>
                            <div style="margin-top:0.75rem;font-size:0.8rem;color:var(--text-muted);">
                                <strong>Déclencheur :</strong>
                                <div class="editable" contenteditable="true" data-field="context.trigger" data-placeholder="Événement déclencheur" style="display:inline;"></div>
                            </div>
                        </div>

                        <div class="card" style="border-left:3px solid #facc15;">
                            <div class="card-label" style="color:#facc15;">Aujourd'hui</div>
                            <div class="editable" contenteditable="true" data-field="context.currentSituation" data-placeholder="Comment les choses fonctionnent actuellement ?"></div>
                            <div style="margin-top:0.75rem;font-size:0.8rem;color:var(--text-muted);">
                                <strong>Points douleur :</strong>
                                <div class="editable" contenteditable="true" data-field="context.painPoints" data-placeholder="Problemes recurrents" style="display:inline;"></div>
                            </div>
                        </div>

                        <div class="card" style="border-left:3px solid #4ade80;">
                            <div class="card-label" style="color:#4ade80;">Objectif</div>
                            <div class="editable" contenteditable="true" data-field="context.desiredSituation" data-placeholder="Que doit permettre le système cible ?"></div>
                            <div style="margin-top:0.75rem;font-size:0.8rem;color:var(--text-muted);">
                                <strong>Critères :</strong>
                                <div class="editable" contenteditable="true" data-field="context.acceptanceCriteria" data-placeholder="Critères de succès" style="display:inline;"></div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- SECTION: Parties prenantes -->
                <div class="section" id="cadrage-stakeholders" style="display:none;">
                    <h2 class="section-title">Parties prenantes</h2>
                    <p class="section-subtitle">Toutes les personnes concernées par ce projet et leurs besoins.</p>

                    <div class="stakeholder-grid" id="stakeholderGrid">
                        <!-- Populated dynamically -->
                    </div>

                    <button class="add-btn" onclick="toggleForm('addStakeholderForm')">+ Ajouter un profil utilisateur</button>

                    <div class="inline-form" id="addStakeholderForm">
                        <div class="inline-form-title">Nouveau profil utilisateur</div>
                        <div class="form-group">
                            <label class="form-label">Titre du profil (exemple : Responsable de production)</label>
                            <input type="text" class="form-input" id="sh-role" placeholder="Titre ou description du profil">
                        </div>
                        <div class="form-group">
                            <label class="form-label">Fonction dans l'entreprise</label>
                            <input type="text" class="form-input" id="sh-function" placeholder="Ce qu'il fait dans l'organisation">
                        </div>
                        <div class="form-group">
                            <label class="form-label">Tâches principales (une par ligne)</label>
                            <textarea class="form-textarea" id="sh-tasks" placeholder="Tâche 1&#10;Tâche 2&#10;Tâche 3"></textarea>
                        </div>
                        <div class="form-row">
                            <div class="form-group">
                                <label class="form-label">Fréquence d'utilisation</label>
                                <select class="form-select" id="sh-frequency">
                                    <option value="daily">Quotidienne</option>
                                    <option value="weekly">Hebdomadaire</option>
                                    <option value="monthly">Mensuelle</option>
                                    <option value="occasional">Occasionnelle</option>
                                </select>
                            </div>
                            <div class="form-group">
                                <label class="form-label">Niveau d'accès</label>
                                <select class="form-select" id="sh-access">
                                    <option value="admin">Administration complète</option>
                                    <option value="manager">Supervision et validation</option>
                                    <option value="contributor">Saisie et modification</option>
                                    <option value="viewer">Consultation seule</option>
                                </select>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="form-label">Frustrations actuelles</label>
                            <textarea class="form-textarea" id="sh-frustrations" placeholder="Quelles sont les 2-3 plus grandes frustrations de ce profil avec la façon de travailler actuelle ?"></textarea>
                        </div>
                        <div class="form-actions">
                            <button class="btn" onclick="toggleForm('addStakeholderForm')">Annuler</button>
                            <button class="btn btn-primary" onclick="addStakeholder()">Ajouter ce profil</button>
                        </div>
                    </div>
                </div>

                <!-- SECTION: Périmètre fonctionnel -->
                <div class="section" id="cadrage-scope" style="display:none;">
                    <h2 class="section-title">Périmètre fonctionnel</h2>
                    <p class="section-subtitle">Ce que le système doit faire et ne pas faire.</p>

                    <h3 style="color: var(--text-bright); font-size: 1rem; margin-bottom: 0.75rem;">
                        <span style="color: #60a5fa;">&#9632;</span> Dans le périmètre
                    </h3>
                    <div id="scopeInScope" class="uc-list"></div>
                    <button class="add-btn" onclick="toggleForm('addScopeForm-inscope')">+ Ajouter une fonctionnalité</button>
                    <div class="inline-form" id="addScopeForm-inscope">
                        <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-inscope" placeholder="Ex: Gestion des commandes"></div>
                        <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-inscope" placeholder="Courte description"></div>
                        <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-inscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('inscope')">Ajouter</button></div>
                    </div>

                    <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
                        <span style="color: #94a3b8;">&#9632;</span> Hors périmètre
                    </h3>
                    <div id="scopeOutOfScope" class="uc-list"></div>
                    <button class="add-btn" onclick="toggleForm('addScopeForm-outofscope')">+ Ajouter une exclusion</button>
                    <div class="inline-form" id="addScopeForm-outofscope">
                        <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-outofscope" placeholder="Ex: Gestion de la paie"></div>
                        <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-outofscope" placeholder="Pourquoi hors périmètre"></div>
                        <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-outofscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('outofscope')">Ajouter</button></div>
                    </div>
                </div>

                <!-- SECTION: Critères de réussite -->
                <div class="section" id="cadrage-success" style="display:none;">
                    <h2 class="section-title">Critères de réussite</h2>
                    <p class="section-subtitle">Comment mesurer objectivement que le projet est un succès.</p>

                    <div class="card">
                        <div class="card-label">Définition du succès</div>
                        <div class="editable" contenteditable="true" data-field="success.definition" data-placeholder="Comment saurez-vous que le projet est un succès ? Quel changement concret observerez-vous ?"></div>
                    </div>

                    <div class="card" data-vibe-hide>
                        <div class="card-label">Objectifs mesurables</div>
                        <div class="editable" contenteditable="true" data-field="success.metrics" data-placeholder="Quels chiffres présenteriez-vous à votre direction pour prouver le succès ? (temps, erreurs, satisfaction...)"></div>
                    </div>

                    <div class="card" data-vibe-hide>
                        <div class="card-label">Délai d'évaluation</div>
                        <div class="editable" contenteditable="true" data-field="success.timeline" data-placeholder="Au bout de combien de temps pourrez-vous juger si ça fonctionne ? 1 semaine ? 1 mois ? 3 mois ?"></div>
                    </div>

                    <div class="card" data-vibe-hide>
                        <div class="card-label">Conditions minimales de mise en service</div>
                        <div class="editable" contenteditable="true" data-field="success.minimumConditions" data-placeholder="Quelles conditions minimales pour mettre le système en service ? (fonctionnalités présentes, données migrées, formation faite...)"></div>
                    </div>

                    <h3 style="color: var(--text-bright); font-size: 1rem; margin: 2rem 0 0.75rem;">Critères d'acceptation</h3>
                    <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Critères concrets et mesurables pour valider le succès du projet.</p>
                    <div id="criteriaList" class="uc-list"></div>
                    <button class="add-btn" onclick="toggleForm('addCriterionForm')">+ Ajouter un critère d'acceptation</button>
                    <div class="inline-form" id="addCriterionForm">
                        <div class="form-group"><label class="form-label">Critère (mesurable)</label><input type="text" class="form-input" id="criterion-text" placeholder="Ex: 80% des employés saisissent leurs heures chaque semaine"></div>
                        <div class="form-actions"><button class="btn" onclick="toggleForm('addCriterionForm')">Annuler</button><button class="btn btn-primary" onclick="addCriterion()">Ajouter</button></div>
                    </div>
                </div>

                <!-- ================================================================
                     PHASE 2 : DECOMPOSITION
                     ================================================================ -->

                <!-- SECTION: Domaines fonctionnels -->
                <div class="section" id="decomp-modules" style="display:none;">
                    <h2 class="section-title">Domaines fonctionnels</h2>
                    <p class="section-subtitle">Identifiez les grands domaines de votre application. Chaque domaine regroupe des fonctionnalités cohérentes et indépendantes.</p>

                    <div class="module-grid" id="moduleGrid">
                        <!-- Populated dynamically -->
                    </div>

                    <button class="add-btn" onclick="toggleForm('addModuleForm')" style="margin-top:1rem;">+ Ajouter un domaine fonctionnel</button>

                    <div class="inline-form" id="addModuleForm">
                        <div class="inline-form-title">Nouveau domaine fonctionnel</div>
                        <div class="form-group">
                            <label class="form-label">Nom du domaine (exemple : Gestion des commandes)</label>
                            <input type="text" class="form-input" id="mod-name" placeholder="Nom clair et explicite">
                        </div>
                        <div class="form-group">
                            <label class="form-label">Description en une ou deux phrases</label>
                            <textarea class="form-textarea" id="mod-desc" placeholder="À quoi sert ce domaine ? Quel problème résout-il ?"></textarea>
                        </div>
                        <div class="form-row">
                            <div class="form-group">
                                <label class="form-label">Type de domaine</label>
                                <select class="form-select" id="mod-type">
                                    <option value="data-centric">Gestion de données (listes, fiches, formulaires)</option>
                                    <option value="workflow">Processus métier (étapes, validations, approbations)</option>
                                    <option value="reporting">Tableaux de bord et rapports</option>
                                    <option value="integration">Intégration avec des systèmes externes</option>
                                    <option value="full-module">Domaine complet (données + processus + rapports)</option>
                                </select>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="form-label">Principales données gérées (une par ligne)</label>
                            <textarea class="form-textarea" id="mod-entities" placeholder="Commande&#10;Ligne de commande&#10;Facture"></textarea>
                        </div>
                        <div class="form-actions">
                            <button class="btn" onclick="toggleForm('addModuleForm')">Annuler</button>
                            <button class="btn btn-primary" onclick="addModule()">Ajouter ce domaine</button>
                        </div>
                    </div>
                </div>

                <!-- SECTION: Dépendances -->
                <div class="section" id="decomp-dependencies" style="display:none;">
                    <h2 class="section-title">Dépendances entre domaines</h2>
                    <p class="section-subtitle">Indiquez quels domaines dépendent d'autres domaines. Par exemple, les Commandes dépendent des Clients et des Produits.</p>

                    <div id="depGraphContainer">
                        <div class="dep-graph" id="depGraph">
                            <p style="color:var(--text-muted);text-align:center;padding:2rem;">Ajoutez des domaines fonctionnels pour visualiser les dépendances.</p>
                        </div>
                    </div>

                    <div style="margin-top:1.5rem;">
                        <h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:0.75rem;">Ajouter une dépendance</h3>
                        <div class="form-row">
                            <div class="form-group">
                                <label class="form-label">Ce domaine...</label>
                                <select class="form-select" id="dep-from"></select>
                            </div>
                            <div class="form-group">
                                <label class="form-label">...dépend de</label>
                                <select class="form-select" id="dep-to"></select>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="form-label">Nature de la dépendance</label>
                            <input type="text" class="form-input" id="dep-desc" placeholder="Exemple : La commande référence un client existant">
                        </div>
                        <button class="btn btn-primary" onclick="addDependency()" style="margin-top:0.5rem;">Ajouter cette dépendance</button>
                    </div>

                    <div id="depList" style="margin-top:1.5rem;"></div>

                    <div style="margin-top:2rem;">
                        <h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:0.75rem;">Ordre de traitement proposé</h3>
                        <p class="section-subtitle">Les domaines sont traités dans l'ordre de leurs dépendances : les fondations d'abord, puis les domaines qui en dépendent.</p>
                        <div id="processingOrder" class="process-flow"></div>
                    </div>
                </div>

                <!-- ================================================================
                     PHASE 3 : SPECIFICATION PAR MODULE
                     ================================================================ -->

                <!-- Container dynamique pour les specs de chaque module -->
                <div id="moduleSpecContainer">
                    <!-- Generated dynamically by renderModuleSpec() -->
                </div>

                <!-- ================================================================
                     PHASE 4 : CONSOLIDATION
                     ================================================================ -->

                <!-- SECTION: Modèle de données -->
                <div class="section" id="consol-datamodel" style="display:none;">
                    <h2 class="section-title">Modèle de données</h2>
                    <p class="section-subtitle">Vue d'ensemble de toutes les entités métier, leurs attributs et leurs relations entre domaines.</p>
                    <div id="dataModelContainer">
                        <p style="color:var(--text-muted);text-align:center;padding:2rem;">Le modèle de données sera généré à partir des spécifications de chaque domaine.</p>
                    </div>
                </div>

                <!-- SECTION: Interactions cross-module -->
                <div class="section" id="consol-interactions" style="display:none;">
                    <h2 class="section-title">Interactions entre domaines</h2>
                    <p class="section-subtitle">Vue d'ensemble de la façon dont les domaines communiquent et partagent des données.</p>
                    <div id="consolInteractions">
                        <p style="color:var(--text-muted);text-align:center;padding:2rem;">Les interactions seront calculées automatiquement à partir des dépendances et des données partagées entre domaines.</p>
                    </div>
                </div>

                <!-- SECTION: Cohérence des accès -->
                <div class="section" id="consol-permissions" style="display:none;">
                    <h2 class="section-title">Cohérence des droits d'accès</h2>
                    <p class="section-subtitle">Vérification que les profils utilisateurs ont des droits cohérents dans tous les domaines.</p>
                    <div id="consolPermissions">
                        <p style="color:var(--text-muted);text-align:center;padding:2rem;">La cohérence sera vérifiée quand les permissions de chaque domaine seront définies.</p>
                    </div>
                </div>

                <!-- SECTION: Parcours bout en bout -->
                <div class="section" id="consol-flows" style="display:none;">
                    <h2 class="section-title">Parcours bout en bout</h2>
                    <p class="section-subtitle">Les processus métier qui traversent plusieurs domaines, de bout en bout.</p>

                    <div id="e2eFlowsList"></div>

                    <button class="add-btn" onclick="toggleForm('addFlowForm')">+ Ajouter un parcours</button>

                    <div class="inline-form" id="addFlowForm">
                        <div class="inline-form-title">Nouveau parcours bout en bout</div>
                        <div class="form-group">
                            <label class="form-label">Nom du parcours (exemple : De la commande à la facture)</label>
                            <input type="text" class="form-input" id="flow-name" placeholder="Nom descriptif du parcours">
                        </div>
                        <div class="form-group">
                            <label class="form-label">Étapes du parcours (une par ligne : Domaine - Action)</label>
                            <textarea class="form-textarea" id="flow-steps" placeholder="Clients - Le client existe dans le système&#10;Commandes - Créer la commande&#10;Commandes - Valider la commande&#10;Factures - Générer la facture"></textarea>
                        </div>
                        <div class="form-group">
                            <label class="form-label">Qui intervient dans ce parcours ?</label>
                            <input type="text" class="form-input" id="flow-actors" placeholder="Exemple : Contributeur (création), Responsable (validation)">
                        </div>
                        <div class="form-actions">
                            <button class="btn" onclick="toggleForm('addFlowForm')">Annuler</button>
                            <button class="btn btn-primary" onclick="addE2EFlow()">Ajouter ce parcours</button>
                        </div>
                    </div>
                </div>

                <!-- ================================================================
                     PHASE 5 : SYNTHESE
                     ================================================================ -->

                <div class="section" id="handoff-summary" style="display:none;">
                    <h2 class="section-title">Synthèse de l'analyse</h2>
                    <p class="section-subtitle">Vue d'ensemble de toute l'analyse métier, prête pour le développement.</p>

                    <div class="card" style="margin-bottom:1.5rem;" id="progressIndicator">
                        <!-- Populated by renderProgressIndicator() -->
                    </div>

                    <div class="stat-grid" id="handoffStats">
                        <!-- Populated dynamically -->
                    </div>

                    <h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:0.75rem;">Domaines par ordre de traitement</h3>
                    <div id="handoffModuleList"></div>

                    <h3 style="color:var(--text-bright);font-size:1rem;margin:1.5rem 0 0.75rem;">Couverture du besoin initial</h3>
                    <div class="card">
                        <div class="card-label">Matrice de couverture</div>
                        <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:0.75rem;">Chaque besoin du cadrage est couvert par au moins un domaine et un cas d'utilisation.</p>
                        <div id="coverageMatrix"></div>
                    </div>

                    <div style="margin-top:2rem;padding:1.5rem;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;text-align:center;">
                        <p style="color:var(--text-bright);font-size:1.1rem;font-weight:600;margin-bottom:0.5rem;">Analyse prête pour l'extraction</p>
                        <p style="color:var(--text-muted);font-size:0.85rem;margin-bottom:1rem;">Exportez le fichier JSON pour lancer la génération automatique du système.</p>
                        <button class="btn btn-primary" onclick="exportJSON()" style="font-size:0.9rem;padding:0.6rem 1.5rem;">Exporter l'analyse complète en JSON</button>
                    </div>
                </div>

            </main>

            <!-- ============================================
                 REVIEW PANEL (right sidebar)
                 ============================================ -->
            <aside class="review-panel" id="reviewPanel" role="complementary" aria-label="Panneau de review">
                <div class="review-panel-header">
                    <span class="review-panel-title">Review</span>
                    <button class="review-panel-close" onclick="toggleReviewPanel()" title="Fermer" aria-label="Fermer le panneau de review">&times;</button>
                </div>
                <div class="review-filters">
                    <button class="review-filter-btn active" onclick="filterReviewComments('all')" data-filter="all">Tous</button>
                    <button class="review-filter-btn" onclick="filterReviewComments('to-review')" data-filter="to-review">À revoir</button>
                    <button class="review-filter-btn" onclick="filterReviewComments('validated')" data-filter="validated">Validés</button>
                </div>
                <div class="review-comments" id="reviewCommentsList">
                    <div class="review-empty">Aucun commentaire pour le moment.</div>
                </div>
                <div class="review-stats" id="reviewStats">
                    <div class="review-stat">
                        <div class="review-stat-value" id="reviewStatTotal">0</div>
                        <div class="review-stat-label">Total</div>
                    </div>
                    <div class="review-stat">
                        <div class="review-stat-value" id="reviewStatToReview">0</div>
                        <div class="review-stat-label">À revoir</div>
                    </div>
                    <div class="review-stat">
                        <div class="review-stat-value" id="reviewStatValidated">0</div>
                        <div class="review-stat-label">Validés</div>
                    </div>
                </div>
            </aside>
        </div>
    </div>

    <!-- Notification -->
    <div class="notification notification-success" id="notification"></div>

    <script>
/* --- 01-data-init.js --- */
/* ============================================
   DATA STORE
   ============================================ */
const APP_KEY = 'ba-{{APPLICATION_ID}}';
let data = {{FEATURE_DATA}};
const ORIGINAL_DATA = JSON.parse(JSON.stringify(data));
const EMBEDDED_ARTIFACTS = {{EMBEDDED_ARTIFACTS}};

// CRITICAL: Initialize top-level structures FIRST to prevent TypeError crashes
data.cadrage = data.cadrage || {};
data.modules = data.modules || [];
data.dependencies = data.dependencies || [];
data.handoff = data.handoff || {};
data.cadrage.stakeholders = data.cadrage.stakeholders || [];

// Initialize applications array (multi-app support)
data.applications = data.applications || [];

// Initialize optional data structures
data.wireframeComments = data.wireframeComments || {};
data.specComments = data.specComments || {};
data.customRoles = data.customRoles || [];
data.customActions = data.customActions || [];
data.cadrage.criteria = data.cadrage.criteria || [];
data.consolidation = data.consolidation || {};
data.consolidation.e2eFlows = data.consolidation.e2eFlows || [];

// Backward compat: merge old problem/current/vision into context
if (!data.cadrage.context) {
    data.cadrage.context = {
        problem: data.cadrage.problem?.description || data.cadrage.problem || '',
        trigger: data.cadrage.problem?.trigger || '',
        currentSituation: data.cadrage.current?.tools || '',
        desiredSituation: data.cadrage.vision?.changes || '',
        painPoints: data.cadrage.current?.painPoints || (data.cadrage.stakeholders || []).flatMap(s => (s.frustrations || '').split('\n').filter(Boolean)).join('\n'),
        acceptanceCriteria: data.cadrage.vision?.results || (data.cadrage.criteria || []).map(c => c.text).join('\n')
    };
}
data.cadrage.context = data.cadrage.context || { problem: '', trigger: '', currentSituation: '', desiredSituation: '', painPoints: '', acceptanceCriteria: '' };

// Initialize comments array
data.comments = data.comments || [];

// Defensive mapping: globalScope (JSON format) -> scope (HTML format)
// Handles cases where FEATURE_DATA contains raw globalScope instead of pre-mapped scope
if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
    const gs = data.cadrage.globalScope || {};
    // Backward compat: merge old MoSCoW into binary scope
    if (gs.mustHave || gs.shouldHave || gs.couldHave) {
        data.cadrage.scope = {
            inscope: [...(gs.mustHave || []), ...(gs.shouldHave || []), ...(gs.couldHave || [])].map(s => typeof s === 'string' ? { name: s, description: '' } : s),
            outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
        };
    } else {
        function normScopeItem(s) {
            if (typeof s === 'string') return { name: s, description: '' };
            if (s.name) return s;
            var nm = s.feature || s.label || s.title || JSON.stringify(s);
            var parts = [];
            if (s.priority) parts.push(s.priority.toUpperCase());
            if (s.module) parts.push('Module: ' + s.module);
            return { name: nm, description: parts.join(' — ') };
        }
        data.cadrage.scope = {
            inscope: (gs.inScope || []).map(normScopeItem),
            outofscope: (gs.outOfScope || []).map(function(s) {
                if (typeof s === 'string') return { name: s, description: '' };
                if (s.name) return s;
                return { name: s.feature || s.reason || JSON.stringify(s), description: s.reason || '' };
            })
        };
    }
}
data.cadrage.scope = data.cadrage.scope || { inscope: [], outofscope: [] };

// Backward compat: old vital/important/optional/excluded → inscope/outofscope
if (data.cadrage.scope.vital && !data.cadrage.scope.inscope?.length) {
    data.cadrage.scope.inscope = [...(data.cadrage.scope.vital || []), ...(data.cadrage.scope.important || []), ...(data.cadrage.scope.optional || [])];
    data.cadrage.scope.outofscope = data.cadrage.scope.excluded || data.cadrage.scope.outofscope || [];
}

// Defensive init: moduleSpecs (may be missing if LLM didn't follow mapping)
data.moduleSpecs = data.moduleSpecs || {};
// Ensure ALL modules have a moduleSpecs entry (prevents missing schemas)
(data.modules || []).forEach(function(m) {
    if (!data.moduleSpecs[m.code]) {
        data.moduleSpecs[m.code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };
    }
    // Ensure anticipatedSections array exists and normalize strings to objects
    m.anticipatedSections = (m.anticipatedSections || []).map(function(s) {
        return typeof s === 'string' ? { code: s, name: s, description: '', resources: [] } : s;
    });
    m.applicationCode = m.applicationCode || '';
    // Initialize screens array for interface specs
    if (!data.moduleSpecs[m.code].screens) {
        data.moduleSpecs[m.code].screens = [];
    }
    // Ensure sections have initialized arrays for hierarchical data
    m.anticipatedSections.forEach(function(section) {
        section.useCases = section.useCases || [];
        section.businessRules = section.businessRules || [];
        section.resources = section.resources || [];
        section.permission = section.permission || '';
        section.route = section.route || '';
    });
});

// Normalize permissions: convert any object format to "Role|Action" pipe-delimited strings
// Handles 5 formats:
// A: "Role|Action" strings (already correct)
// B: {role, permissions: ["Read:all", ...]} with role-permission pairs
// C: {role, permissions: ["Module.Entity.Read", ...]} with path-based permissions
// D: {code, label, description} permission definitions without role assignment
// E: {role: "", permissions: []} empty entries (skip)
(data.modules || []).forEach(function(m) {
    var spec = data.moduleSpecs[m.code];
    if (!spec || !spec.permissions || spec.permissions.length === 0) return;
    // Skip if already normalized (first element is a pipe-delimited string)
    if (typeof spec.permissions[0] === 'string' && spec.permissions[0].indexOf('|') !== -1) return;
    if (typeof spec.permissions[0] !== 'object') return;

    var actionMap = {
        'read': 'Consulter', 'create': 'Créer', 'update': 'Modifier',
        'delete': 'Supprimer', 'approve': 'Valider', 'validate': 'Valider',
        'export': 'Exporter', 'admin': 'Administrer', 'import': 'Importer',
        'viewsalary': 'Consulter', 'assignteam': 'Modifier', 'cancel': 'Supprimer',
        'viewbalance': 'Consulter', 'invoicetime': 'Valider'
    };
    var normalized = [];
    var first = spec.permissions[0];

    // Detect Format D: {code, label, description} — permission codes without roles
    if (first.code && !first.role && !first.permissions) {
        // Extract actions from permission codes, assign to stakeholder roles
        var roles = (data.cadrage.stakeholders || []).map(function(s) { return s.role; }).filter(Boolean);
        if (roles.length === 0) roles = ['Administrateur', 'Responsable', 'Contributeur', 'Lecteur'];
        spec.permissions.forEach(function(permDef) {
            var code = permDef.code || '';
            var raw = code.split('.').pop(); // "Module.Entity.Read" → "Read"
            var action = actionMap[raw.toLowerCase()] || raw;
            // Assign to first role (admin) by default — better than empty
            if (roles[0]) {
                var key = roles[0] + '|' + action;
                if (normalized.indexOf(key) === -1) normalized.push(key);
            }
        });
    } else {
        // Format B/C: {role, permissions: [...]}
        spec.permissions.forEach(function(entry) {
            var role = entry.role || entry.name || '';
            if (!role) return; // Skip Format E (empty role)
            var perms = entry.permissions || entry.actions || [];
            if (perms.length === 0 && entry.permissionPattern && entry.permissionPattern.endsWith('*')) {
                ['Consulter', 'Créer', 'Modifier', 'Supprimer', 'Valider', 'Exporter'].forEach(function(a) {
                    normalized.push(role + '|' + a);
                });
                return;
            }
            perms.forEach(function(perm) {
                if (typeof perm !== 'string') return;
                var raw = perm.split(':')[0]; // "Read:all" → "Read"
                if (raw.indexOf('.') !== -1) raw = raw.split('.').pop(); // "Module.Entity.Read" → "Read"
                var action = actionMap[raw.toLowerCase()] || raw;
                var key = role + '|' + action;
                if (normalized.indexOf(key) === -1) normalized.push(key);
            });
        });
    }
    spec.permissions = normalized;
});

// Detect if modules use section-level specs (hierarchical mode)
function hasHierarchicalSpecs(mod) {
    return (mod.anticipatedSections || []).some(function(s) {
        return (s.useCases && s.useCases.length > 0) || (s.businessRules && s.businessRules.length > 0);
    });
}

// Defensive: normalize stakeholder tasks (string → array)
(data.cadrage.stakeholders || []).forEach(function(s) {
    if (typeof s.tasks === 'string') {
        s.tasks = s.tasks.split(',').map(t => t.trim()).filter(Boolean);
    }
    s.tasks = s.tasks || [];
});

// Vibe coding mode: hide non-relevant sections
const isVibeCoding = data.metadata?.vibeCoding === true;
if (isVibeCoding) {
    document.querySelectorAll('[data-vibe-hide]').forEach(el => el.style.display = 'none');
}

/* ============================================
   UTILITIES
   ============================================ */
function showNotification(message) {
    const el = document.getElementById('notification');
    el.textContent = message;
    el.classList.add('visible');
    setTimeout(() => el.classList.remove('visible'), 2500);
}

function toggleForm(formId) {
    document.getElementById(formId).classList.toggle('visible');
}

function clearForm(formId) {
    document.querySelectorAll('#' + formId + ' input, #' + formId + ' textarea').forEach(el => el.value = '');
}

function getNestedValue(obj, path) {
    return path.split('.').reduce((o, k) => (o || {})[k], obj);
}

function setNestedValue(obj, path, value) {
    const keys = path.split('.');
    let current = obj;
    for (let i = 0; i < keys.length - 1; i++) {
        if (!current[keys[i]]) current[keys[i]] = {};
        current = current[keys[i]];
    }
    current[keys[keys.length - 1]] = value;
}

function updateCounts() {
    buildNavTree();
    updateDepSelects();
}

function formatFrequency(f) {
    return { daily: 'Quotidien', weekly: 'Hebdomadaire', monthly: 'Mensuel', occasional: 'Occasionnel' }[f] || f;
}

function formatAccess(a) {
    return { admin: 'Administration', manager: 'Supervision', contributor: 'Contribution', viewer: 'Consultation' }[a] || a;
}

function formatPriority(p) {
    return { inscope: 'Dans le périmètre', outofscope: 'Hors périmètre' }[p] || p;
}

function formatLevel(l) {
    return { high: 'Fort', medium: 'Moyen', low: 'Faible' }[l] || l;
}

function formatModuleType(t) {
    return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
}

function escapeHtml(s) {
    if (s == null) return '';
    var d = document.createElement('div');
    d.textContent = String(s);
    return d.innerHTML;
}

function computeProgress() {
    var totalModules = data.modules.length;
    var modulesWithUC = 0, modulesWithBR = 0, modulesWithEntities = 0, modulesWithWireframes = 0;
    var totalUCs = 0, totalBRs = 0, totalEntities = 0;

    data.modules.forEach(function(m) {
        var spec = data.moduleSpecs[m.code] || {};
        var ucs = (spec.useCases || []).length;
        var brs = (spec.businessRules || []).length;
        var ents = (spec.entities || []).length;
        var wfs = (EMBEDDED_ARTIFACTS?.wireframes?.[m.code] || []).length + (spec.screens || []).length;
        totalUCs += ucs; totalBRs += brs; totalEntities += ents;
        if (ucs > 0) modulesWithUC++;
        if (brs > 0) modulesWithBR++;
        if (ents > 0) modulesWithEntities++;
        if (wfs > 0) modulesWithWireframes++;
    });

    var checks = [];
    if (totalModules > 0) checks.push({ done: true, label: 'Modules définis (' + totalModules + ')' });
    checks.push({ done: modulesWithUC === totalModules && totalModules > 0, label: 'Cas d\'utilisation (' + modulesWithUC + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithBR === totalModules && totalModules > 0, label: 'Règles métier (' + modulesWithBR + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithEntities === totalModules && totalModules > 0, label: 'Données (' + modulesWithEntities + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithWireframes === totalModules && totalModules > 0, label: 'Maquettes (' + modulesWithWireframes + '/' + totalModules + ' modules)' });
    checks.push({ done: data.cadrage.stakeholders.length > 0, label: 'Parties prenantes (' + data.cadrage.stakeholders.length + ')' });
    checks.push({ done: (data.cadrage.scope.inscope || []).length > 0, label: 'Périmètre défini' });

    var doneCount = checks.filter(function(c) { return c.done; }).length;
    var pct = checks.length > 0 ? Math.round(doneCount / checks.length * 100) : 0;
    return { checks: checks, doneCount: doneCount, total: checks.length, pct: pct, totalUCs: totalUCs, totalBRs: totalBRs, totalEntities: totalEntities };
}

/* ============================================
   INITIALIZATION
   ============================================ */
document.addEventListener('DOMContentLoaded', function() {
    loadFromLocalStorage();
    initEditableFields();
    // Re-apply vibe hiding after DOM init (in case loadFromLocalStorage changed data)
    if (isVibeCoding) {
        document.querySelectorAll('[data-vibe-hide]').forEach(el => el.style.display = 'none');
    }
    renderStakeholders();
    renderScope();
    renderCriteria();
    renderModules();
    renderDependencies();
    renderAllModuleSpecs();
    renderConsolidation();
    renderHandoff();
    renderE2EFlows();
    buildNavTree();
    updateDepSelects();
    initInlineComments();
    renderReviewPanel();
    showSection(currentSectionId);
});


/* --- 02-navigation.js --- */
/* ============================================
   NAVIGATION - Hierarchical Tree
   ============================================ */
let currentSectionId = 'cadrage-context';
let navCollapseState = {};

/* ---------- Core ---------- */

function showSection(sectionId) {
    currentSectionId = sectionId;
    document.querySelectorAll('.section').forEach(s => s.style.display = 'none');
    const section = document.getElementById(sectionId);
    if (section) section.style.display = 'block';

    // Highlight active nav item
    document.querySelectorAll('#sidebarNav .nav-item').forEach(n => n.classList.remove('active'));
    const navItem = document.querySelector('#sidebarNav [data-section="' + sectionId + '"]');
    if (navItem) {
        navItem.classList.add('active');
        // Auto-expand parent groups to reveal active item
        let parent = navItem.parentElement;
        while (parent && parent.id !== 'sidebarNav') {
            if (parent.classList.contains('nav-children') && parent.style.display === 'none') {
                parent.style.display = '';
                const groupEl = parent.parentElement;
                if (groupEl) {
                    const groupId = groupEl.dataset.groupId;
                    if (groupId) {
                        navCollapseState[groupId] = false;
                        const chevron = groupEl.querySelector(':scope > .nav-group-title .nav-chevron, :scope > .nav-item.nav-module-header .nav-chevron');
                        if (chevron) chevron.classList.add('expanded');
                    }
                }
            }
            parent = parent.parentElement;
        }
        saveNavState();
    }
}

function restoreCurrentSection() {
    if (currentSectionId) {
        const section = document.getElementById(currentSectionId);
        if (section) section.style.display = 'block';
    }
}

/* ---------- Tree Builder ---------- */

function buildNavTree() {
    const nav = document.getElementById('sidebarNav');
    if (!nav) return;

    var html = renderNavGroup('cadrage', 'Cadrage', buildCadrageItems());

    // Multi-app: group modules by application
    if (data.applications && data.applications.length > 1) {
        data.applications.forEach(function(app) {
            var appModules = data.modules.filter(function(m) { return m.applicationCode === app.code; });
            var appModuleItems = '';
            appModules.forEach(function(mod) {
                appModuleItems += renderModuleNavItem(mod);
            });
            // Global views at bottom of each app group
            appModuleItems += renderNavItem('decomp-modules', 'Vue d\'ensemble', data.modules.length);
            html += renderNavGroup('app-' + app.code, app.name || app.code, appModuleItems);
        });
        // Modules without applicationCode
        var orphanModules = data.modules.filter(function(m) { return !m.applicationCode; });
        if (orphanModules.length > 0) {
            var orphanItems = '';
            orphanModules.forEach(function(mod) {
                orphanItems += renderModuleNavItem(mod);
            });
            html += renderNavGroup('modules-other', 'Autres modules (' + orphanModules.length + ')', orphanItems);
        }
        html += renderNavItem('decomp-dependencies', 'Dépendances', data.dependencies.length);
    } else {
        html += renderNavGroup('modules', 'Modules (' + data.modules.length + ')', buildModuleItems());
    }

    html += renderNavGroup('consolidation', 'Consolidation', buildConsolidationItems());
    html += renderNavGroup('synthese', 'Synthèse', buildSyntheseItems());

    nav.innerHTML = html;
    restoreNavState();
    highlightActiveNavItem();
}

function renderNavGroup(id, title, itemsHtml) {
    const collapsed = navCollapseState[id] === true;
    return '<div class="nav-group" data-group-id="' + id + '">' +
        '<div class="nav-group-title" onclick="toggleNavGroup(\'' + id + '\')">' +
            '<span class="nav-chevron ' + (collapsed ? '' : 'expanded') + '">&#9656;</span> ' +
            title +
        '</div>' +
        '<div class="nav-children"' + (collapsed ? ' style="display:none;"' : '') + '>' +
            itemsHtml +
        '</div>' +
    '</div>';
}

function renderNavItem(sectionId, label, badge) {
    return '<a class="nav-item" onclick="showSection(\'' + sectionId + '\')" data-section="' + sectionId + '">' +
        '<span class="nav-icon">&#9679;</span> ' + label +
        (badge !== undefined ? ' <span class="nav-badge">' + badge + '</span>' : '') +
    '</a>';
}

/* ---------- Group Builders ---------- */

function buildCadrageItems() {
    return renderNavItem('cadrage-context', 'Contexte') +
        renderNavItem('cadrage-stakeholders', 'Parties prenantes', data.cadrage.stakeholders.length) +
        renderNavItem('cadrage-scope', 'Périmètre fonctionnel') +
        renderNavItem('cadrage-success', 'Critères de réussite');
}

function buildModuleItems() {
    let html = '';
    data.modules.forEach(function(mod) {
        html += renderModuleNavItem(mod);
    });
    // Global module views at bottom
    html += renderNavItem('decomp-modules', 'Vue d\'ensemble', data.modules.length);
    html += renderNavItem('decomp-dependencies', 'Dépendances', data.dependencies.length);
    return html;
}

function buildConsolidationItems() {
    var totalEntities = data.modules.reduce(function(sum, m) {
        return sum + (data.moduleSpecs[m.code]?.entities || []).length;
    }, 0);
    return renderNavItem('consol-datamodel', 'Modèle de données', totalEntities) +
        renderNavItem('consol-interactions', 'Interactions') +
        renderNavItem('consol-permissions', 'Cohérence des accès') +
        renderNavItem('consol-flows', 'Parcours bout en bout', data.consolidation.e2eFlows.length);
}

function buildSyntheseItems() {
    return renderNavItem('handoff-summary', 'Vue d\'ensemble');
}

/* ---------- Module Sub-Tree ---------- */

function renderModuleNavItem(mod) {
    var code = mod.code;
    var spec = data.moduleSpecs[code] || {};
    var ucCount = (spec.useCases || []).length;
    var brCount = (spec.businessRules || []).length;
    var entCount = (spec.entities || []).length;
    var totalItems = ucCount + brCount + entCount;

    // Flat module link — sections/resources are accessible via tabs (Structure, Maquettes)
    return '<a class="nav-item nav-module-header" onclick="showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">' +
        '<span class="nav-icon">&#9679;</span> ' +
        (mod.name || mod.code) +
        (totalItems > 0 ? ' <span class="nav-badge">' + totalItems + '</span>' : '') +
    '</a>';
}

function renderModuleTabNavItem(code, tabId, label, badge) {
    var sectionId = 'module-spec-' + code;
    return '<a class="nav-item" onclick="showSection(\'' + sectionId + '\');switchTab(\'' + code + '\',\'' + tabId + '\')" data-section="' + sectionId + '-' + tabId + '">' +
        '<span class="nav-icon">&#9679;</span> ' + label +
        (badge !== undefined ? ' <span class="nav-badge">' + badge + '</span>' : '') +
    '</a>';
}

function scrollToMockup(moduleCode, sectionCode) {
    setTimeout(function() {
        var el = document.getElementById('screen-' + moduleCode + '-' + sectionCode);
        if (el) {
            el.scrollIntoView({ behavior: 'smooth', block: 'start' });
            el.style.outline = '2px solid var(--accent)';
            el.style.borderRadius = '10px';
            setTimeout(function() { el.style.outline = ''; el.style.borderRadius = ''; }, 2000);
        }
    }, 150);
}

/* ---------- Collapse/Expand ---------- */

function toggleNavGroup(groupId) {
    navCollapseState[groupId] = !navCollapseState[groupId];
    var groupEl = document.querySelector('[data-group-id="' + groupId + '"]');
    if (groupEl) {
        var children = groupEl.querySelector(':scope > .nav-children');
        var chevron = groupEl.querySelector(':scope > .nav-group-title .nav-chevron, :scope > .nav-item.nav-module-header .nav-chevron');
        if (children) children.style.display = navCollapseState[groupId] ? 'none' : '';
        if (chevron) chevron.classList.toggle('expanded', !navCollapseState[groupId]);
    }
    saveNavState();
}

function saveNavState() {
    try { localStorage.setItem(APP_KEY + '-nav', JSON.stringify(navCollapseState)); } catch(e) {}
}

function restoreNavState() {
    try {
        var saved = localStorage.getItem(APP_KEY + '-nav');
        if (saved) {
            navCollapseState = JSON.parse(saved);
            // Apply collapse state to all groups
            Object.keys(navCollapseState).forEach(function(groupId) {
                if (navCollapseState[groupId]) {
                    var groupEl = document.querySelector('[data-group-id="' + groupId + '"]');
                    if (groupEl) {
                        var children = groupEl.querySelector(':scope > .nav-children');
                        var chevron = groupEl.querySelector(':scope > .nav-group-title .nav-chevron, :scope > .nav-item.nav-module-header .nav-chevron');
                        if (children) children.style.display = 'none';
                        if (chevron) chevron.classList.remove('expanded');
                    }
                }
            });
        }
    } catch(e) {}
}

function highlightActiveNavItem() {
    if (!currentSectionId) return;
    var navItem = document.querySelector('#sidebarNav [data-section="' + currentSectionId + '"]');
    if (navItem) navItem.classList.add('active');
}

/* ---------- Mobile Sidebar ---------- */

function toggleMobileSidebar() {
    var sidebar = document.getElementById('sidebarAside');
    var overlay = document.getElementById('sidebarOverlay');
    if (!sidebar) return;
    var isOpen = sidebar.classList.contains('mobile-open');
    sidebar.classList.toggle('mobile-open', !isOpen);
    if (overlay) overlay.classList.toggle('visible', !isOpen);
}

/* ---------- Search / Filter ---------- */

var _searchTimer;
function filterNavItems(query) {
    clearTimeout(_searchTimer);
    _searchTimer = setTimeout(function() { doFilterNavItems(query); }, 200);
}

function doFilterNavItems(query) {
    var q = (query || '').toLowerCase().trim();
    var nav = document.getElementById('sidebarNav');
    if (!nav) return;

    // Clear previous highlights
    nav.querySelectorAll('.search-highlight').forEach(function(el) {
        el.outerHTML = el.textContent;
    });

    if (!q) {
        // Show all items
        nav.querySelectorAll('.nav-item, .nav-group, .nav-module, .nav-section-item').forEach(function(el) {
            el.classList.remove('search-hidden');
        });
        return;
    }

    // Filter nav items
    var allItems = nav.querySelectorAll('.nav-item');
    var visibleSections = new Set();

    allItems.forEach(function(item) {
        var text = item.textContent.toLowerCase();
        if (text.includes(q)) {
            item.classList.remove('search-hidden');
            // Show parent groups
            var parent = item.parentElement;
            while (parent && parent.id !== 'sidebarNav') {
                parent.classList.remove('search-hidden');
                if (parent.querySelector(':scope > .nav-children')) {
                    var children = parent.querySelector(':scope > .nav-children');
                    if (children) children.style.display = '';
                }
                parent = parent.parentElement;
            }
            // Track section for content search
            var sectionId = item.dataset.section;
            if (sectionId) visibleSections.add(sectionId);
        } else {
            item.classList.add('search-hidden');
        }
    });

    // Hide groups that have no visible children
    nav.querySelectorAll('.nav-group, .nav-module').forEach(function(group) {
        var visibleChildren = group.querySelectorAll('.nav-item:not(.search-hidden)');
        if (visibleChildren.length === 0) {
            group.classList.add('search-hidden');
        } else {
            group.classList.remove('search-hidden');
        }
    });

    // Also search in section content and show matching sections
    document.querySelectorAll('.section').forEach(function(section) {
        var text = section.textContent.toLowerCase();
        if (text.includes(q) && !visibleSections.has(section.id)) {
            // Unhide corresponding nav item
            var navItem = nav.querySelector('[data-section="' + section.id + '"]');
            if (navItem) {
                navItem.classList.remove('search-hidden');
                var parent = navItem.parentElement;
                while (parent && parent.id !== 'sidebarNav') {
                    parent.classList.remove('search-hidden');
                    parent = parent.parentElement;
                }
            }
        }
    });
}


/* --- 03-render-cadrage.js --- */
/* ============================================
   EDITABLE FIELDS
   ============================================ */
function initEditableFields() {
    document.querySelectorAll('.editable[data-field]').forEach(el => {
        const field = el.dataset.field;
        const value = getNestedValue(data, 'cadrage.' + field);
        if (value) el.textContent = value;

        el.addEventListener('blur', function() {
            setNestedValue(data, 'cadrage.' + field, this.textContent.trim());
            autoSave();
        });
    });
}

/* ============================================
   STAKEHOLDERS
   ============================================ */
function addStakeholder() {
    const role = document.getElementById('sh-role').value.trim();
    if (!role) return;

    data.cadrage.stakeholders.push({
        role: role,
        function: document.getElementById('sh-function').value.trim(),
        tasks: document.getElementById('sh-tasks').value.split('\n').filter(t => t.trim()),
        frequency: document.getElementById('sh-frequency').value,
        access: document.getElementById('sh-access').value,
        frustrations: document.getElementById('sh-frustrations').value.trim()
    });

    renderStakeholders();
    toggleForm('addStakeholderForm');
    clearForm('addStakeholderForm');
    updateCounts();
    autoSave();
}

function renderStakeholders() {
    const grid = document.getElementById('stakeholderGrid');
    grid.innerHTML = data.cadrage.stakeholders.map((s, i) => `
        <div class="stakeholder-card">
            <div style="display:flex;justify-content:space-between;align-items:start;">
                <div class="stakeholder-role">${escapeHtml(s.role)}</div>
                <button class="btn btn-sm" onclick="removeStakeholder(${i})" style="opacity:0.5;font-size:0.7rem;">Supprimer</button>
            </div>
            <div class="stakeholder-function">${escapeHtml(s.function || '')}</div>
            <ul class="stakeholder-tasks">
                ${(Array.isArray(s.tasks) ? s.tasks : typeof s.tasks === 'string' ? s.tasks.split(',').map(t => t.trim()).filter(Boolean) : []).map(t => '<li>' + escapeHtml(t) + '</li>').join('')}
            </ul>
            <div class="stakeholder-meta">
                <span>${formatFrequency(s.frequency)}</span>
                <span>${formatAccess(s.access)}</span>
            </div>
            ${s.frustrations ? '<div style="font-size:0.8rem;color:var(--warning);margin-top:0.5rem;font-style:italic;">' + escapeHtml(s.frustrations) + '</div>' : ''}
        </div>
    `).join('');
}

function removeStakeholder(index) {
    if (!confirm('Supprimer ce profil utilisateur ?')) return;
    data.cadrage.stakeholders.splice(index, 1);
    renderStakeholders();
    updateCounts();
    autoSave();
}

/* ============================================
   SCOPE ITEMS
   ============================================ */
function addScopeItem(priority) {
    const name = document.getElementById('scope-name-' + priority).value.trim();
    if (!name) return;
    const description = document.getElementById('scope-desc-' + priority).value.trim();

    data.cadrage.scope[priority].push({ name, description });
    renderScope();
    toggleForm('addScopeForm-' + priority);
    document.getElementById('scope-name-' + priority).value = '';
    document.getElementById('scope-desc-' + priority).value = '';
    autoSave();
}

function renderScope() {
    ['inscope', 'outofscope'].forEach(p => {
        const container = document.getElementById('scope' + (p === 'inscope' ? 'InScope' : 'OutOfScope'));
        if (!container) return;
        container.innerHTML = (data.cadrage.scope[p] || []).map((item, i) => `
            <div class="uc-item">
                <div class="uc-header">
                    <span class="priority priority-${p}">${formatPriority(p)}</span>
                    <span class="uc-title">${escapeHtml(item.name)}</span>
                    <div class="uc-actions">
                        <button class="btn btn-sm" onclick="removeScopeItem('${p}',${i})">Supprimer</button>
                    </div>
                </div>
                ${item.description ? '<div class="uc-detail">' + escapeHtml(item.description) + '</div>' : ''}
            </div>
        `).join('');
    });
}

function removeScopeItem(priority, index) {
    data.cadrage.scope[priority].splice(index, 1);
    renderScope();
    autoSave();
}

/* ============================================
   ACCEPTANCE CRITERIA
   ============================================ */
function addCriterion() {
    const text = document.getElementById('criterion-text').value.trim();
    if (!text) return;
    if (!data.cadrage.criteria) data.cadrage.criteria = [];
    data.cadrage.criteria.push({ text, validated: false });
    renderCriteria();
    toggleForm('addCriterionForm');
    document.getElementById('criterion-text').value = '';
    autoSave();
}

function removeCriterion(index) {
    data.cadrage.criteria.splice(index, 1);
    renderCriteria();
    autoSave();
}

function toggleCriterion(index) {
    data.cadrage.criteria[index].validated = !data.cadrage.criteria[index].validated;
    renderCriteria();
    autoSave();
}

function renderCriteria() {
    const container = document.getElementById('criteriaList');
    if (!container) return;
    const criteria = data.cadrage.criteria || [];
    container.innerHTML = criteria.map((c, i) => `
        <div class="uc-item" style="display:flex;align-items:center;gap:0.75rem;">
            <input type="checkbox" ${c.validated ? 'checked' : ''} onchange="toggleCriterion(${i})" style="cursor:pointer;width:18px;height:18px;flex-shrink:0;">
            <span style="flex:1;${c.validated ? 'text-decoration:line-through;color:var(--text-muted);' : ''}">${escapeHtml(c.text)}</span>
            <button class="btn btn-sm" onclick="removeCriterion(${i})" style="opacity:0.5;flex-shrink:0;">&#10005;</button>
        </div>
    `).join('');
}

/* ============================================
   CONTEXT RENDERING (merged problem/current/vision)
   ============================================ */
function renderContext() {
    // context fields are handled by initEditableFields() via data-field="context.*"
    // This function ensures backward compat data is displayed as strings
    const ctx = data.cadrage.context || {};
    if (Array.isArray(ctx.painPoints)) {
        data.cadrage.context.painPoints = ctx.painPoints.join('\n');
    }
    if (Array.isArray(ctx.acceptanceCriteria)) {
        data.cadrage.context.acceptanceCriteria = ctx.acceptanceCriteria.join('\n');
    }
}


/* --- 04-render-modules.js --- */
/* ============================================
   MODULE MANAGEMENT
   ============================================ */
function addModule() {
    const name = document.getElementById('mod-name').value.trim();
    if (!name) return;
    const code = name.replace(/[^a-zA-Z0-9]/g, '');

    data.modules.push({
        code: code,
        name: name,
        description: document.getElementById('mod-desc').value.trim(),
        featureType: document.getElementById('mod-type').value,
        entities: document.getElementById('mod-entities').value.split('\n').filter(e => e.trim()),
        anticipatedSections: [],
        status: 'pending'
    });

    // Initialize module spec
    if (!data.moduleSpecs[code]) {
        data.moduleSpecs[code] = {
            useCases: [],
            businessRules: [],
            entities: [],
            permissions: [],
            notes: ''
        };
    }

    renderModules();
    renderDependencies();
    renderAllModuleSpecs();
    toggleForm('addModuleForm');
    clearForm('addModuleForm');
    updateCounts();
    autoSave();
}

function removeModule(index) {
    if (!confirm('Supprimer ce domaine fonctionnel ?')) return;
    const code = data.modules[index].code;
    data.modules.splice(index, 1);
    delete data.moduleSpecs[code];
    data.dependencies = data.dependencies.filter(d => d.from !== code && d.to !== code);
    renderModules();
    renderDependencies();
    renderAllModuleSpecs();
    updateCounts();
    autoSave();
}

function renderModules() {
    const grid = document.getElementById('moduleGrid');
    grid.innerHTML = data.modules.map((m, i) => `
        <div class="module-card" onclick="showSection('module-spec-${m.code}')">
            <button class="module-card-remove" onclick="event.stopPropagation();removeModule(${i})">&#10005;</button>
            <div class="module-card-header">
                <span class="module-card-code">${escapeHtml(m.name)}</span>
                <span class="module-card-type">${formatModuleType(m.featureType)}</span>
            </div>
            <div class="module-card-desc">${escapeHtml(m.description || '')}</div>
            <div class="module-card-meta">
                <span>${(m.entities || []).length} données</span>
                <span>${(data.moduleSpecs[m.code]?.useCases || []).length} cas d'utilisation</span>
            </div>
        </div>
    `).join('') || '<p style="color:var(--text-muted);text-align:center;padding:2rem;grid-column:1/-1;">Aucun domaine fonctionnel défini. Cliquez sur le bouton ci-dessous pour commencer.</p>';
}

function updateModulesNav() {
    buildNavTree();
}

/* ============================================
   DEPENDENCY MANAGEMENT
   ============================================ */
function updateDepSelects() {
    const fromSel = document.getElementById('dep-from');
    const toSel = document.getElementById('dep-to');
    if (!fromSel || !toSel) return;
    const opts = data.modules.map(m => `<option value="${m.code}">${m.name}</option>`).join('');
    fromSel.innerHTML = opts;
    toSel.innerHTML = opts;
}

function addDependency() {
    const from = document.getElementById('dep-from').value;
    const to = document.getElementById('dep-to').value;
    if (!from || !to || from === to) return;
    if (data.dependencies.some(d => d.from === from && d.to === to)) return;

    data.dependencies.push({
        from: from,
        to: to,
        description: document.getElementById('dep-desc').value.trim()
    });
    document.getElementById('dep-desc').value = '';

    renderDependencies();
    autoSave();
}

function removeDependency(index) {
    data.dependencies.splice(index, 1);
    renderDependencies();
    autoSave();
}

function renderDependencies() {
    // Render dependency list
    const depList = document.getElementById('depList');
    if (depList) {
        depList.innerHTML = data.dependencies.map((d, i) => {
            const fromName = data.modules.find(m => m.code === d.from)?.name || d.from;
            const toName = data.modules.find(m => m.code === d.to)?.name || d.to;
            return `
                <div class="interaction-item">
                    <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(fromName)}</span>
                    <span class="interaction-arrow">&#8594;</span>
                    <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(toName)}</span>
                    <span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${escapeHtml(d.description || '')}</span>
                    <button class="btn btn-sm" onclick="removeDependency(${i})" style="opacity:0.5;">Supprimer</button>
                </div>
            `;
        }).join('');
    }

    // Render graph
    renderDepGraph();
    // Render processing order
    renderProcessingOrder();
}

function renderDepGraph() {
    const graph = document.getElementById('depGraph');
    if (!graph || data.modules.length === 0) return;

    const layers = computeTopologicalLayers();
    if (!layers) {
        graph.innerHTML = '<p style="color:var(--error);text-align:center;padding:1rem;">Dépendance circulaire détectée ! Corrigez les dépendances.</p>';
        return;
    }

    graph.innerHTML = layers.map((layer, i) => `
        <div class="dep-layer">
            <div class="dep-layer-label">Couche ${i + 1}</div>
            <div class="dep-layer-modules">
                ${layer.map(code => {
                    const m = data.modules.find(mod => mod.code === code);
                    return `<div class="dep-module">${escapeHtml(m ? (m.name || m.code) : code)}</div>`;
                }).join('')}
            </div>
        </div>
        ${i < layers.length - 1 ? '<div class="dep-arrow">&#8595;</div>' : ''}
    `).join('');
}

function computeTopologicalLayers() {
    const codes = data.modules.map(m => m.code);
    const inDeg = {};
    const adj = {};
    codes.forEach(c => { inDeg[c] = 0; adj[c] = []; });
    data.dependencies.forEach(d => {
        if (inDeg[d.from] !== undefined && adj[d.to] !== undefined) {
            adj[d.to].push(d.from);
            inDeg[d.from]++;
        }
    });

    const layers = [];
    let remaining = new Set(codes);
    while (remaining.size > 0) {
        const layer = [];
        remaining.forEach(c => {
            if (inDeg[c] === 0) layer.push(c);
        });
        if (layer.length === 0) return null; // cycle
        layers.push(layer);
        layer.forEach(c => {
            remaining.delete(c);
            (adj[c] || []).forEach(dep => { inDeg[dep]--; });
        });
    }
    return layers;
}

function renderProcessingOrder() {
    const container = document.getElementById('processingOrder');
    if (!container) return;
    const layers = computeTopologicalLayers();
    if (!layers) { container.innerHTML = ''; return; }
    const order = layers.flat();
    container.innerHTML = order.map((code, i) => {
        const m = data.modules.find(mod => mod.code === code);
        return `
            <div class="process-step">
                <div class="process-step-number">Étape ${i + 1}</div>
                <div class="process-step-label">${escapeHtml(m ? (m.name || m.code) : code)}</div>
            </div>
            ${i < order.length - 1 ? '<div class="process-arrow">&#8594;</div>' : ''}
        `;
    }).join('');
}


/* --- 05-render-specs.js --- */
/* ============================================
   MODULE SPECIFICATION (per module)
   ============================================ */
function renderAllModuleSpecs() {
    const container = document.getElementById('moduleSpecContainer');
    container.innerHTML = data.modules.map(m => renderModuleSpecSection(m)).join('');
    // Bind editable fields in module specs
    container.querySelectorAll('.editable[data-module-field]').forEach(el => {
        el.addEventListener('blur', function() {
            const code = this.dataset.moduleCode;
            const field = this.dataset.moduleField;
            if (data.moduleSpecs[code]) {
                data.moduleSpecs[code][field] = this.textContent.trim();
                autoSave();
            }
        });
    });
    // Restore currently visible section after re-render
    restoreCurrentSection();
    // Re-initialize inline comment buttons on module spec cards
    if (typeof initInlineComments === 'function') initInlineComments();
}

function renderModuleSpecSection(mod) {
    const code = mod.code;
    const spec = data.moduleSpecs[code] || { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };

    return `
    <div class="section" id="module-spec-${code}" style="display:none;">
        <h2 class="section-title">${escapeHtml(mod.name)}</h2>
        <p class="section-subtitle">${escapeHtml(mod.description || 'Spécification détaillée de ce domaine fonctionnel.')}</p>

        <div class="tab-bar" role="tablist" aria-label="Spécifications du module ${escapeHtml(mod.name)}">
            <button class="tab-btn active" role="tab" aria-selected="true" aria-controls="tab-${code}-uc" onclick="switchTab('${code}', 'uc')">Cas d'utilisation</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-br" onclick="switchTab('${code}', 'br')">Règles métier</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-ent" onclick="switchTab('${code}', 'ent')">Données</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-perm" onclick="switchTab('${code}', 'perm')">Droits d'accès</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-mock" onclick="switchTab('${code}', 'mock')">Maquettes</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-notes" onclick="switchTab('${code}', 'notes')">Notes</button>
            <button class="tab-btn" role="tab" aria-selected="false" aria-controls="tab-${code}-struct" onclick="switchTab('${code}', 'struct')">Structure</button>
        </div>

        <!-- TAB: Cas d'utilisation -->
        <div class="tab-panel active" id="tab-${code}-uc" role="tabpanel" aria-hidden="false">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Décrivez ce que chaque type d'utilisateur peut faire dans ce domaine. Un cas d'utilisation = une action concrète.</p>
            <div id="ucList-${code}" class="uc-list">
                ${hasHierarchicalSpecs(mod) ? renderSectionGroupedItems(mod, 'useCases', code, renderUseCase) : ''}
                ${spec.useCases.map((uc, i) => renderUseCase(code, uc, i)).join('')}
            </div>
            <button class="add-btn" onclick="toggleForm('addUcForm-${code}')">+ Ajouter un cas d'utilisation</button>
            <div class="inline-form" id="addUcForm-${code}">
                <div class="inline-form-title">Nouveau cas d'utilisation</div>
                <div class="form-group">
                    <label class="form-label">Que fait l'utilisateur ? (exemple : Créer une commande)</label>
                    <input type="text" class="form-input" id="uc-name-${code}" placeholder="Action concrète de l'utilisateur">
                </div>
                <div class="form-group">
                    <label class="form-label">Qui réalise cette action ? (profil utilisateur)</label>
                    <input type="text" class="form-input" id="uc-actor-${code}" placeholder="Exemple : Responsable de production">
                </div>
                <div class="form-group">
                    <label class="form-label">Déroulement normal, étape par étape (une par ligne)</label>
                    <textarea class="form-textarea" id="uc-steps-${code}" placeholder="1. L'utilisateur ouvre la page de création&#10;2. Il remplit les champs obligatoires&#10;3. Il valide le formulaire&#10;4. Le système enregistre et confirme"></textarea>
                </div>
                <div class="form-group">
                    <label class="form-label">Que se passe-t-il si quelque chose ne va pas ? (optionnel)</label>
                    <textarea class="form-textarea" id="uc-alt-${code}" placeholder="Exemple : Si les données sont incorrectes, le système affiche un message d'erreur" style="min-height:50px;"></textarea>
                </div>
                <div class="form-actions">
                    <button class="btn" onclick="toggleForm('addUcForm-${code}')">Annuler</button>
                    <button class="btn btn-primary" onclick="addUseCase('${code}')">Ajouter</button>
                </div>
            </div>
        </div>

        <!-- TAB: Règles métier -->
        <div class="tab-panel" id="tab-${code}-br" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Les règles que le système doit respecter. Formulez-les sous forme de conditions : "Si... alors... sinon..."</p>
            <div id="brList-${code}">
                ${hasHierarchicalSpecs(mod) ? renderSectionGroupedItems(mod, 'businessRules', code, renderBusinessRule) : ''}
                ${spec.businessRules.map((br, i) => renderBusinessRule(code, br, i)).join('')}
            </div>
            <button class="add-btn" onclick="toggleForm('addBrForm-${code}')">+ Ajouter une règle métier</button>
            <div class="inline-form" id="addBrForm-${code}">
                <div class="inline-form-title">Nouvelle règle métier</div>
                <div class="form-group">
                    <label class="form-label">Nom court de la règle</label>
                    <input type="text" class="form-input" id="br-name-${code}" placeholder="Exemple : Vérification du budget disponible">
                </div>
                <div class="form-group">
                    <label class="form-label">Catégorie</label>
                    <select class="form-select" id="br-cat-${code}">
                        <option value="validation">Vérification (le système vérifie que...)</option>
                        <option value="calculation">Calcul (le système calcule...)</option>
                        <option value="workflow">Processus (quand X se produit, alors...)</option>
                        <option value="security">Sécurité (seul... peut...)</option>
                        <option value="data">Données (les données doivent...)</option>
                    </select>
                </div>
                <div class="form-group">
                    <label class="form-label">Formulation de la règle (Si... alors... sinon...)</label>
                    <textarea class="form-textarea" id="br-statement-${code}" placeholder="Si le montant de la commande dépasse le budget du client, alors la commande est refusée et un message d'erreur s'affiche"></textarea>
                </div>
                <div class="form-group">
                    <label class="form-label">Exemple concret (optionnel)</label>
                    <input type="text" class="form-input" id="br-example-${code}" placeholder="Exemple : Commande de 5000 CHF, budget de 2000 CHF -> refusée">
                </div>
                <div class="form-actions">
                    <button class="btn" onclick="toggleForm('addBrForm-${code}')">Annuler</button>
                    <button class="btn btn-primary" onclick="addBusinessRule('${code}')">Ajouter</button>
                </div>
            </div>
        </div>

        <!-- TAB: Données (Entités) -->
        <div class="tab-panel" id="tab-${code}-ent" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Les types de données que ce domaine gère. Décrivez les informations importantes à enregistrer pour chaque type.</p>
            <div id="entList-${code}">
                ${spec.entities.length > 0
                    ? spec.entities.map((ent, i) => renderEntity(code, ent, i)).join('')
                    : (mod.entities || []).length > 0
                        ? '<div class="card" style="color:var(--text-muted);padding:1.5rem;"><p style="margin-bottom:0.75rem;">Les schémas détaillés ne sont pas encore disponibles. Entités identifiées :</p><ul style="list-style:disc;padding-left:1.5rem;">' + mod.entities.map(e => '<li>' + e + '</li>').join('') + '</ul><p style="font-size:0.8rem;margin-top:0.75rem;font-style:italic;">Utilisez le bouton ci-dessous pour ajouter les schémas détaillés.</p></div>'
                        : ''
                }
            </div>
            <button class="add-btn" onclick="toggleForm('addEntForm-${code}')">+ Ajouter un type de données</button>
            <div class="inline-form" id="addEntForm-${code}">
                <div class="inline-form-title">Nouveau type de données</div>
                <div class="form-group">
                    <label class="form-label">Nom (exemple : Commande, Client, Facture)</label>
                    <input type="text" class="form-input" id="ent-name-${code}" placeholder="Nom du type de données">
                </div>
                <div class="form-group">
                    <label class="form-label">Description : à quoi sert cette donnée ?</label>
                    <textarea class="form-textarea" id="ent-desc-${code}" placeholder="En une ou deux phrases, décrivez ce que représente cette donnée dans votre activité" style="min-height:50px;"></textarea>
                </div>
                <div class="form-group">
                    <label class="form-label">Informations à enregistrer (une par ligne : Nom - Description)</label>
                    <textarea class="form-textarea" id="ent-attrs-${code}" placeholder="Numero - Identifiant unique de la commande&#10;Date - Date de création de la commande&#10;Montant total - Somme des lignes&#10;Statut - Brouillon, Envoyée, Validée, Refusée"></textarea>
                </div>
                <div class="form-group">
                    <label class="form-label">Relations avec d'autres données (optionnel, une par ligne)</label>
                    <textarea class="form-textarea" id="ent-rels-${code}" placeholder="Client - Chaque commande appartient a un client&#10;Ligne de commande - Une commande contient plusieurs lignes" style="min-height:50px;"></textarea>
                </div>
                <div class="form-actions">
                    <button class="btn" onclick="toggleForm('addEntForm-${code}')">Annuler</button>
                    <button class="btn btn-primary" onclick="addEntity('${code}')">Ajouter</button>
                </div>
            </div>
        </div>

        <!-- TAB: Droits d'accès -->
        <div class="tab-panel" id="tab-${code}-perm" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Définissez qui peut faire quoi dans ce domaine. Cochez les actions autorisées pour chaque profil.</p>
            <div id="permGrid-${code}">
                ${renderPermissionGrid(code)}
            </div>
            <div style="display:flex;gap:0.75rem;margin-top:1rem;flex-wrap:wrap;">
                <button class="add-btn" onclick="toggleForm('addRoleForm-${code}')" style="flex:1;min-width:200px;">+ Ajouter un rôle</button>
                <button class="add-btn" onclick="toggleForm('addActionForm-${code}')" style="flex:1;min-width:200px;">+ Ajouter une action</button>
            </div>
            <div class="inline-form" id="addRoleForm-${code}">
                <div class="inline-form-title">Nouveau rôle</div>
                <div class="form-group">
                    <label class="form-label">Nom du rôle</label>
                    <input type="text" class="form-input" id="role-name-${code}" placeholder="Exemple : Superviseur, Auditeur...">
                </div>
                <div class="form-actions">
                    <button class="btn" onclick="toggleForm('addRoleForm-${code}')">Annuler</button>
                    <button class="btn btn-primary" onclick="addCustomRole('${code}')">Ajouter</button>
                </div>
            </div>
            <div class="inline-form" id="addActionForm-${code}">
                <div class="inline-form-title">Nouvelle action</div>
                <div class="form-group">
                    <label class="form-label">Nom de l'action</label>
                    <input type="text" class="form-input" id="action-name-${code}" placeholder="Exemple : Archiver, Imprimer, Approuver...">
                </div>
                <div class="form-actions">
                    <button class="btn" onclick="toggleForm('addActionForm-${code}')">Annuler</button>
                    <button class="btn btn-primary" onclick="addCustomAction('${code}')">Ajouter</button>
                </div>
            </div>
        </div>

        <!-- TAB: Maquettes -->
        <div class="tab-panel" id="tab-${code}-mock" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Maquettes validées lors de l'analyse. Ces wireframes montrent la structure exacte des écrans de ce domaine.</p>
            <div id="mockupContainer-${code}">
                ${renderModuleMockups(code)}
            </div>
        </div>

        <!-- TAB: Notes -->
        <div class="tab-panel" id="tab-${code}-notes" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Notes libres, questions en suspens, éléments à clarifier pour ce domaine.</p>
            <div class="card">
                <div class="editable" contenteditable="true" data-module-code="${code}" data-module-field="notes" data-placeholder="Notez ici tout ce qui concerne ce domaine : questions, précisions, contraintes particulières...">${spec.notes || ''}</div>
            </div>
        </div>

        <!-- TAB: Structure (sections/resources) -->
        <div class="tab-panel" id="tab-${code}-struct" role="tabpanel" aria-hidden="true">
            <p style="font-size:0.85rem;color:var(--text-muted);margin-bottom:1rem;">Organisation des écrans et ressources de ce domaine. Structure hiérarchique : sections regroupant des ressources.</p>
            <div id="structContainer-${code}">
                ${renderModuleStructure(code)}
            </div>
        </div>
    </div>`;
}

function renderUseCase(code, uc, index) {
    var preconditions = uc.preconditions || [];
    var postconditions = uc.postconditions || [];
    var errorScenarios = uc.errorScenarios || [];
    var description = uc.description || '';

    return `
        <div class="uc-item">
            <div class="uc-header">
                <span class="uc-id">UC-${String(index + 1).padStart(3, '0')}</span>
                <span class="uc-title">${escapeHtml(uc.name)}</span>
                <div class="uc-actions">
                    <button class="btn btn-sm" onclick="removeUseCase('${code}',${index})">Supprimer</button>
                </div>
            </div>
            <div class="uc-actors"><div class="uc-actor">${escapeHtml(uc.actor)}</div></div>
            ${description ? `<div class="uc-detail-label">Description</div><div class="uc-detail" style="font-style:italic;color:var(--text-muted);">${escapeHtml(description)}</div>` : ''}
            ${preconditions.length > 0 ? `<div class="uc-detail-label">Préconditions</div><div class="uc-detail"><ul style="margin:0;padding-left:1.2rem;">${preconditions.map(p => '<li>' + escapeHtml(typeof p === 'string' ? p : p.description || '') + '</li>').join('')}</ul></div>` : ''}
            ${uc.steps ? `<div class="uc-detail-label">Déroulement principal</div><div class="uc-detail">${escapeHtml(uc.steps).replace(/\n/g, '<br>')}</div>` : ''}
            ${uc.alternative ? `<div class="uc-detail-label">Scénarios alternatifs</div><div class="uc-detail" style="color:var(--warning);">${escapeHtml(uc.alternative)}</div>` : ''}
            ${errorScenarios.length > 0 ? `<div class="uc-detail-label">Scénarios d'erreur</div><div class="uc-detail" style="color:var(--danger);"><ul style="margin:0;padding-left:1.2rem;">${errorScenarios.map(e => '<li><strong>' + escapeHtml(typeof e === 'string' ? e : e.name || '') + '</strong>' + (typeof e === 'object' && e.steps ? ' : ' + escapeHtml(Array.isArray(e.steps) ? e.steps.join(', ') : e.steps) : '') + '</li>').join('')}</ul></div>` : ''}
            ${postconditions.length > 0 ? `<div class="uc-detail-label">Postconditions</div><div class="uc-detail"><ul style="margin:0;padding-left:1.2rem;">${postconditions.map(p => '<li>' + escapeHtml(typeof p === 'string' ? p : p.description || '') + '</li>').join('')}</ul></div>` : ''}
            <div style="padding:0.5rem 0.75rem;border-top:1px solid var(--border);background:var(--bg-input);border-radius:0 0 8px 8px;">
                <label style="font-size:0.75rem;color:var(--text-muted);display:block;margin-bottom:0.25rem;">Commentaire / Feedback :</label>
                <textarea class="form-textarea" placeholder="Ajouter un commentaire sur ce cas d'utilisation..."
                    onblur="updateSpecComment('${code}','uc',${index},this.value)"
                    style="min-height:45px;font-size:0.8rem;resize:vertical;">${escapeHtml(getSpecComment(code, 'uc', index))}</textarea>
            </div>
        </div>`;
}

function addUseCase(code) {
    const name = document.getElementById('uc-name-' + code).value.trim();
    if (!name) return;
    if (!data.moduleSpecs[code]) data.moduleSpecs[code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };

    data.moduleSpecs[code].useCases.push({
        name: name,
        actor: document.getElementById('uc-actor-' + code).value.trim(),
        steps: document.getElementById('uc-steps-' + code).value.trim(),
        alternative: document.getElementById('uc-alt-' + code).value.trim()
    });

    renderAllModuleSpecs();
    updateCounts();
    autoSave();
}

function removeUseCase(code, index) {
    if (!confirm('Supprimer ce cas d\'utilisation ?')) return;
    data.moduleSpecs[code].useCases.splice(index, 1);
    renderAllModuleSpecs();
    updateCounts();
    autoSave();
}

function renderBusinessRule(code, br, index) {
    const catColors = { validation: 'br-cat-validation', calculation: 'br-cat-calculation', workflow: 'br-cat-workflow', security: 'br-cat-security', data: 'br-cat-data' };
    const catLabels = { validation: 'Vérification', calculation: 'Calcul', workflow: 'Processus', security: 'Sécurité', data: 'Données' };
    return `
        <div style="margin-bottom:0.5rem;">
            <div class="br-item" style="margin-bottom:0;border-radius:8px 8px 0 0;">
                <span class="br-category ${catColors[br.category] || 'br-cat-validation'}">${escapeHtml(catLabels[br.category] || br.category)}</span>
                <div class="br-text" style="flex:1;">
                    <div style="font-weight:600;color:var(--text-bright);margin-bottom:0.2rem;">${escapeHtml(br.name)}</div>
                    <div>${escapeHtml(br.statement)}</div>
                    ${br.example ? `<div style="font-size:0.8rem;color:var(--text-muted);margin-top:0.25rem;font-style:italic;">Exemple : ${escapeHtml(br.example)}</div>` : ''}
                </div>
                <button class="btn btn-sm" onclick="removeBusinessRule('${code}',${index})" style="opacity:0.5;flex-shrink:0;">&#10005;</button>
            </div>
            <div style="padding:0.4rem 0.75rem 0.6rem;background:var(--bg-input);border:1px solid var(--border);border-top:0;border-radius:0 0 8px 8px;">
                <textarea class="form-textarea" placeholder="Commentaire sur cette règle..."
                    onblur="updateSpecComment('${code}','br',${index},this.value)"
                    style="min-height:35px;font-size:0.8rem;resize:vertical;">${escapeHtml(getSpecComment(code, 'br', index))}</textarea>
            </div>
        </div>`;
}

function addBusinessRule(code) {
    const name = document.getElementById('br-name-' + code).value.trim();
    if (!name) return;
    if (!data.moduleSpecs[code]) data.moduleSpecs[code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };

    data.moduleSpecs[code].businessRules.push({
        name: name,
        category: document.getElementById('br-cat-' + code).value,
        statement: document.getElementById('br-statement-' + code).value.trim(),
        example: document.getElementById('br-example-' + code).value.trim()
    });

    renderAllModuleSpecs();
    autoSave();
}

function removeBusinessRule(code, index) {
    if (!confirm('Supprimer cette règle métier ?')) return;
    data.moduleSpecs[code].businessRules.splice(index, 1);
    renderAllModuleSpecs();
    autoSave();
}

function renderEntity(code, ent, index) {
    var attrFormId = 'addAttrForm-' + code + '-' + index;
    return `
        <div class="entity-block">
            <div class="entity-header">
                <div>
                    <div class="entity-name">${escapeHtml(ent.name)}</div>
                    <div class="entity-desc">${escapeHtml(ent.description || '')}</div>
                </div>
                <button class="btn btn-sm" onclick="removeEntity('${code}',${index})" style="opacity:0.5;">Supprimer</button>
            </div>
            ${(ent.attributes || []).length > 0 ? `
            <table class="attr-table">
                <thead><tr><th>Information</th><th style="width:100px;">Type</th><th>Description</th></tr></thead>
                <tbody>
                    ${ent.attributes.map(a => `<tr><td style="font-weight:500;color:var(--text-bright);">${escapeHtml(a.name)}</td><td style="font-family:monospace;font-size:0.8rem;color:var(--accent);">${escapeHtml(a.type || 'string')}</td><td>${escapeHtml(a.description || '')}</td></tr>`).join('')}
                </tbody>
            </table>` : ''}
            <div style="padding:0.3rem 0.75rem;">
                <button class="add-btn" style="font-size:0.75rem;padding:0.4rem;" onclick="toggleForm('${attrFormId}')">+ Ajouter un attribut</button>
                <div class="inline-form" id="${attrFormId}">
                    <div class="form-group"><label class="form-label">Nom de l'attribut</label><input type="text" class="form-input" id="attr-name-${code}-${index}" placeholder="Nom de l'attribut"></div>
                    <div class="form-group"><label class="form-label">Type</label><input type="text" class="form-input" id="attr-type-${code}-${index}" placeholder="string, guid, int, decimal, date, enum, boolean" value="string"></div>
                    <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="attr-desc-${code}-${index}" placeholder="Description"></div>
                    <div class="form-actions"><button class="btn" onclick="toggleForm('${attrFormId}')">Annuler</button><button class="btn btn-primary" onclick="addEntityAttribute('${code}',${index})">Ajouter</button></div>
                </div>
            </div>
            ${(ent.relationships || []).length > 0 ? `
            <div style="padding:0.5rem 0.75rem;font-size:0.8rem;color:var(--text-muted);border-top:1px solid var(--border);">
                Relations : ${ent.relationships.map(r => `<span style="color:var(--accent);">${escapeHtml(typeof r === 'string' ? r : (r.target || ''))}</span>`).join(', ')}
            </div>` : ''}
            <div style="padding:0.4rem 0.75rem 0.6rem;background:var(--bg-input);border-top:1px solid var(--border);border-radius:0 0 8px 8px;">
                <label style="font-size:0.75rem;color:var(--text-muted);display:block;margin-bottom:0.25rem;">Commentaire :</label>
                <textarea class="form-textarea" placeholder="Commentaire sur cette entité..."
                    onblur="updateSpecComment('${code}','ent',${index},this.value)"
                    style="min-height:35px;font-size:0.8rem;resize:vertical;">${escapeHtml(getSpecComment(code, 'ent', index))}</textarea>
            </div>
        </div>`;
}

function addEntity(code) {
    const name = document.getElementById('ent-name-' + code).value.trim();
    if (!name) return;
    if (!data.moduleSpecs[code]) data.moduleSpecs[code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };

    const attrs = document.getElementById('ent-attrs-' + code).value.split('\n').filter(l => l.trim()).map(l => {
        const parts = l.split(' - ');
        return { name: parts[0]?.trim() || l.trim(), type: parts[1]?.trim() || 'string', description: parts.slice(2).join(' - ').trim() || parts.slice(1).join(' - ').trim() };
    });
    const rels = document.getElementById('ent-rels-' + code).value.split('\n').filter(l => l.trim());

    data.moduleSpecs[code].entities.push({
        name: name,
        description: document.getElementById('ent-desc-' + code).value.trim(),
        attributes: attrs,
        relationships: rels
    });

    renderAllModuleSpecs();
    autoSave();
}

function removeEntity(code, index) {
    if (!confirm('Supprimer ce type de données ?')) return;
    data.moduleSpecs[code].entities.splice(index, 1);
    renderAllModuleSpecs();
    autoSave();
}

function addEntityAttribute(code, entityIndex) {
    var attrName = document.getElementById('attr-name-' + code + '-' + entityIndex);
    var attrType = document.getElementById('attr-type-' + code + '-' + entityIndex);
    var attrDesc = document.getElementById('attr-desc-' + code + '-' + entityIndex);
    if (!attrName || !attrName.value.trim()) return;
    if (!data.moduleSpecs[code]?.entities?.[entityIndex]) return;
    if (!data.moduleSpecs[code].entities[entityIndex].attributes) {
        data.moduleSpecs[code].entities[entityIndex].attributes = [];
    }
    data.moduleSpecs[code].entities[entityIndex].attributes.push({ name: attrName.value.trim(), type: (attrType?.value || 'string').trim(), description: (attrDesc?.value || '').trim() });
    renderAllModuleSpecs();
    autoSave();
}

function getSpecComment(code, type, index) {
    const key = code + '.' + type + '.' + index;
    return data.specComments[key] || '';
}

function updateSpecComment(code, type, index, value) {
    const key = code + '.' + type + '.' + index;
    data.specComments[key] = value.trim();
    autoSave();
}

function getWireframeComment(code, screen) {
    return (data.wireframeComments[code] || {})[screen] || '';
}

function updateWireframeComment(code, screen, value) {
    if (!data.wireframeComments[code]) data.wireframeComments[code] = {};
    data.wireframeComments[code][screen] = value.trim();
    autoSave();
}

function renderWireframeMockup(code, wf, i) {
    const hasSvg = !!wf.svgContent;
    const wireframeId = `wf-${code}-${i}`;

    return `
    <div class="mockup-frame" style="${i > 0 ? 'margin-top:1.5rem;' : ''}">
        <div class="mockup-toolbar">
            <div class="mockup-dot mockup-dot-red"></div>
            <div class="mockup-dot mockup-dot-yellow"></div>
            <div class="mockup-dot mockup-dot-green"></div>
            <span class="mockup-title">${escapeHtml(wf.screen || wf.section)}</span>
            ${hasSvg ? `
            <div class="wireframe-toggle">
                <button class="wireframe-toggle-btn active" data-target="${wireframeId}" data-view="svg" onclick="toggleWireframeView('${wireframeId}', 'svg')">SVG</button>
                <button class="wireframe-toggle-btn" data-target="${wireframeId}" data-view="ascii" onclick="toggleWireframeView('${wireframeId}', 'ascii')">ASCII</button>
            </div>` : ''}
        </div>
        <div class="mockup-content" id="${wireframeId}">
            ${hasSvg
                ? `<div class="svg-wireframe wireframe-view active" data-view="svg">${wf.svgContent}</div>
                   <pre class="ascii-wireframe wireframe-view" data-view="ascii" style="display:none;">${wf.content || ''}</pre>`
                : (wf.format === 'ascii'
                    ? `<pre class="ascii-wireframe">${wf.content || ''}</pre>`
                    : `<div class="svg-wireframe">${wf.content || ''}</div>`)}
        </div>
        ${wf.description ? `
        <div class="wireframe-description">
            <strong>Description:</strong> ${escapeHtml(wf.description)}
        </div>` : ''}
        ${(wf.elements || []).length > 0 ? `
        <div class="wireframe-metadata">
            <div><strong>Elements:</strong> ${wf.elements.map(e => escapeHtml(typeof e === 'string' ? e : (e.type || e.label || e.id || ''))).filter(Boolean).join(', ')}</div>
        </div>` : ''}
        ${(() => {
            const cm = wf.componentMapping;
            const mappings = Array.isArray(cm) ? cm
                : (typeof cm === 'object' && cm !== null) ? Object.entries(cm).map(([k,v]) => ({wireframeElement: k, reactComponent: v}))
                : [];
            return mappings.length > 0 ? `
        <details class="wireframe-details">
            <summary>Mapping composants SmartStack</summary>
            <table class="mapping-table">
                <thead><tr><th>Élément maquette</th><th>Composant React</th></tr></thead>
                <tbody>
                    ${mappings.map(m =>
                        '<tr><td>' + escapeHtml(m.wireframeElement || '') + '</td><td><code>' + escapeHtml(m.reactComponent || '') + '</code></td></tr>'
                    ).join('')}
                </tbody>
            </table>
        </details>` : '';
        })()}
        <div class="wireframe-comment">
            <label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire / Feedback :</label>
            <textarea class="form-textarea"
                data-module="${code}"
                data-screen="${wf.screen}"
                placeholder="Ajouter un commentaire sur cette maquette (ex: déplacer ce bouton, ajouter une colonne...)"
                onblur="updateWireframeComment('${code}', '${wf.screen}', this.value)"
                style="min-height:60px;font-size:0.85rem;resize:vertical;"
            >${getWireframeComment(code, wf.screen)}</textarea>
        </div>
    </div>
    `;
}

function toggleWireframeView(wireframeId, view) {
    const container = document.getElementById(wireframeId);
    if (!container) return;

    // Toggle visibility of wireframe views
    container.querySelectorAll('.wireframe-view').forEach(el => {
        const isTarget = el.dataset.view === view;
        el.style.display = isTarget ? '' : 'none';
        el.classList.toggle('active', isTarget);
    });

    // Toggle button active states
    const toolbar = container.closest('.mockup-frame').querySelector('.wireframe-toggle');
    if (toolbar) {
        toolbar.querySelectorAll('.wireframe-toggle-btn').forEach(btn => {
            btn.classList.toggle('active', btn.dataset.view === view);
        });
    }
}

// Normalize permissions array: handles 3 formats:
// Format 1 (string): "Role|Action" → already correct
// Format 2 (object): {role, permissions: ["Read:all", "Create:all", ...]}
// Format 3 (object): {role, permissions: ["Module.Entity.Read", ...]}
function normalizePermissions(permsArray) {
    if (!permsArray || permsArray.length === 0) return [];
    // If first element is a string with '|', already normalized
    if (typeof permsArray[0] === 'string' && permsArray[0].includes('|')) return permsArray;
    // If first element is a string without '|', return as-is (unknown format)
    if (typeof permsArray[0] === 'string') return permsArray;
    // Format 2/3: objects with {role, permissions[]}
    const actionMap = {
        'read': 'Consulter', 'create': 'Créer', 'update': 'Modifier',
        'delete': 'Supprimer', 'approve': 'Valider', 'validate': 'Valider',
        'export': 'Exporter', 'admin': 'Administrer', 'import': 'Importer',
        'viewsalary': 'Consulter', 'assignteam': 'Modifier', 'cancel': 'Supprimer'
    };
    const normalized = [];
    permsArray.forEach(function(entry) {
        if (typeof entry !== 'object' || !entry) return;
        var role = entry.role || entry.name || '';
        if (!role) return;
        var perms = entry.permissions || entry.actions || [];
        if (perms.length === 0 && entry.permissionPattern && entry.permissionPattern.endsWith('*')) {
            // Wildcard: expand to all standard actions
            ['Consulter', 'Créer', 'Modifier', 'Supprimer', 'Valider', 'Exporter'].forEach(function(a) {
                normalized.push(role + '|' + a);
            });
            return;
        }
        perms.forEach(function(perm) {
            var action = '';
            if (typeof perm === 'string') {
                // "Read:all" → extract "Read"
                var raw = perm.split(':')[0];
                // "Module.Entity.Read" → extract "Read"
                if (raw.includes('.')) raw = raw.split('.').pop();
                action = actionMap[raw.toLowerCase()] || raw;
            }
            if (action) {
                var key = role + '|' + action;
                if (normalized.indexOf(key) === -1) normalized.push(key);
            }
        });
    });
    return normalized;
}

function getPermRoles() {
    // Extract roles from actual permission data (handles multiple formats)
    const rolesFromPerms = [];
    const seen = new Set();
    data.modules.forEach(m => {
        var perms = data.moduleSpecs[m.code]?.permissions || [];
        // Handle object format directly for role extraction
        perms.forEach(p => {
            var role = '';
            if (typeof p === 'string') {
                role = p.split('|')[0];
            } else if (typeof p === 'object' && p) {
                role = p.role || p.name || '';
            }
            if (role && !seen.has(role)) { seen.add(role); rolesFromPerms.push(role); }
        });
    });
    if (rolesFromPerms.length > 0) return [...rolesFromPerms, ...(data.customRoles || [])];
    // Fallback: use stakeholder names if no permission data exists
    const baseRoles = data.cadrage.stakeholders.length > 0
        ? data.cadrage.stakeholders.map(s => s.role)
        : ['Administrateur', 'Responsable', 'Contributeur', 'Lecteur'];
    return [...baseRoles, ...(data.customRoles || [])];
}

function getPermActions() {
    const baseActions = ['Consulter', 'Créer', 'Modifier', 'Supprimer', 'Valider', 'Exporter'];
    return [...baseActions, ...(data.customActions || [])];
}

function renderPermissionGrid(code) {
    const roles = getPermRoles();
    const actions = getPermActions();
    const baseRolesCount = roles.length - (data.customRoles || []).length;
    const baseActionsCount = 6;

    // Normalize permissions to "Role|Action" format (handles object and string formats)
    const rawPerms = data.moduleSpecs[code]?.permissions || [];
    const perms = normalizePermissions(rawPerms);

    return `
        <table class="mock-table" style="background:var(--bg-card);border-radius:8px;overflow:hidden;">
            <thead><tr>
                <th>Profil</th>
                ${actions.map((a, i) => `<th style="text-align:center;">${escapeHtml(a)}${i >= baseActionsCount ? ' <span onclick="removeCustomAction('+`'${code}','${a}'`+')" style="cursor:pointer;color:var(--danger);font-size:0.7rem;" title="Supprimer cette action">&#10005;</span>' : ''}</th>`).join('')}
            </tr></thead>
            <tbody>
                ${roles.map((role, ri) => `
                    <tr>
                        <td style="font-weight:500;color:var(--text-bright);">${escapeHtml(role)}${ri >= baseRolesCount ? ' <span onclick="removeCustomRole('+`'${code}','${role}'`+')" style="cursor:pointer;color:var(--danger);font-size:0.7rem;" title="Supprimer ce rôle">&#10005;</span>' : ''}</td>
                        ${actions.map(action => {
                            const key = role + '|' + action;
                            const wildcardKey = role + '|*';
                            const checked = perms.includes(key) || perms.includes(wildcardKey);
                            return `<td style="text-align:center;"><input type="checkbox" ${checked ? 'checked' : ''} onchange="togglePermission('${code}','${key}',this.checked)" style="cursor:pointer;width:16px;height:16px;"></td>`;
                        }).join('')}
                    </tr>
                `).join('')}
            </tbody>
        </table>`;
}

function togglePermission(code, key, checked) {
    if (!data.moduleSpecs[code]) data.moduleSpecs[code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };
    if (!data.moduleSpecs[code].permissions) data.moduleSpecs[code].permissions = [];
    if (checked) {
        if (!data.moduleSpecs[code].permissions.includes(key)) data.moduleSpecs[code].permissions.push(key);
    } else {
        data.moduleSpecs[code].permissions = data.moduleSpecs[code].permissions.filter(p => p !== key);
    }
    autoSave();
}

function addCustomRole(code) {
    const input = document.getElementById('role-name-' + code);
    const name = input.value.trim();
    if (!name) return;
    if (!data.customRoles) data.customRoles = [];
    if (!data.customRoles.includes(name) && !getPermRoles().includes(name)) {
        data.customRoles.push(name);
    }
    input.value = '';
    toggleForm('addRoleForm-' + code);
    refreshAllPermGrids();
    autoSave();
}

function addCustomAction(code) {
    const input = document.getElementById('action-name-' + code);
    const name = input.value.trim();
    if (!name) return;
    if (!data.customActions) data.customActions = [];
    if (!data.customActions.includes(name) && !getPermActions().includes(name)) {
        data.customActions.push(name);
    }
    input.value = '';
    toggleForm('addActionForm-' + code);
    refreshAllPermGrids();
    autoSave();
}

function removeCustomRole(code, role) {
    data.customRoles = (data.customRoles || []).filter(r => r !== role);
    data.modules.forEach(m => {
        if (data.moduleSpecs[m.code]?.permissions) {
            data.moduleSpecs[m.code].permissions = data.moduleSpecs[m.code].permissions.filter(p => !p.startsWith(role + '|'));
        }
    });
    refreshAllPermGrids();
    autoSave();
}

function removeCustomAction(code, action) {
    data.customActions = (data.customActions || []).filter(a => a !== action);
    data.modules.forEach(m => {
        if (data.moduleSpecs[m.code]?.permissions) {
            data.moduleSpecs[m.code].permissions = data.moduleSpecs[m.code].permissions.filter(p => !p.endsWith('|' + action));
        }
    });
    refreshAllPermGrids();
    autoSave();
}

function refreshAllPermGrids() {
    data.modules.forEach(m => {
        const container = document.getElementById('permGrid-' + m.code);
        if (container) container.innerHTML = renderPermissionGrid(m.code);
    });
}

function renderModuleStructure(code) {
    const mod = data.modules.find(m => m.code === code);
    const sections = mod ? (mod.anticipatedSections || []).map(function(s) {
        return typeof s === 'string' ? { code: s, name: s, description: '', resources: [] } : s;
    }) : [];

    if (sections.length === 0) {
        return '<div class="card" style="text-align:center;padding:2rem;color:var(--text-muted);">' +
            '<p>Aucune section définie pour ce module.</p>' +
            '<p style="font-size:0.85rem;margin-top:0.5rem;">Les sections et ressources seront identifiées lors de l\'analyse approfondie.</p>' +
            '</div>';
    }

    var legend = '<div class="struct-legend">' +
        '<div class="struct-legend-title">&#9432; Types de sections</div>' +
        '<div class="struct-legend-grid">' +
        '<div class="struct-legend-item"><span class="struct-legend-code">list</span> Page principale — grille de données avec filtres, tri et actions (créer, exporter)</div>' +
        '<div class="struct-legend-item"><span class="struct-legend-code">detail</span> Fiche détaillée — affichée au clic sur une ligne, avec onglets (infos, relations, historique)</div>' +
        '<div class="struct-legend-item"><span class="struct-legend-code">dashboard</span> Tableau de bord — KPIs, graphiques et métriques du module</div>' +
        '<div class="struct-legend-item"><span class="struct-legend-code">approve</span> Workflow — file de validation avec actions (approuver, rejeter, mettre en attente)</div>' +
        '</div></div>';

    return legend + sections.map(function(section) {
        var resources = section.resources || [];
        var sectionUCs = section.useCases || [];
        var sectionBRs = section.businessRules || [];
        var html = '<div class="struct-section">';
        html += '<div class="struct-section-header">';
        html += '<span class="struct-section-code">' + escapeHtml(section.code || section.name || '') + '</span>';
        if (section.description) {
            html += '<span class="struct-section-desc">' + escapeHtml(section.description) + '</span>';
        }
        html += '<span class="struct-section-badge">' + resources.length + ' ressource' + (resources.length !== 1 ? 's' : '') + '</span>';
        html += '</div>';

        // Section metadata (route, permission)
        if (section.route || section.permission) {
            html += '<div style="padding:0.4rem 1rem;font-size:0.75rem;color:var(--text-muted);display:flex;gap:1rem;border-bottom:1px solid var(--border);">';
            if (section.route) html += '<span>Route: <code style="color:var(--accent);background:var(--bg-input);padding:0.1rem 0.3rem;border-radius:3px;">' + escapeHtml(section.route) + '</code></span>';
            if (section.permission) html += '<span>Permission: <code style="color:var(--accent);background:var(--bg-input);padding:0.1rem 0.3rem;border-radius:3px;">' + escapeHtml(section.permission) + '</code></span>';
            html += '</div>';
        }

        // Section-level UC summary
        if (sectionUCs.length > 0) {
            html += '<div style="padding:0.4rem 1rem;font-size:0.8rem;border-bottom:1px solid var(--border);">';
            html += '<span style="color:var(--text-muted);font-weight:500;">' + sectionUCs.length + ' cas d\'utilisation :</span> ';
            html += sectionUCs.map(function(uc) { return '<span style="color:var(--text-bright);">' + escapeHtml(uc.name || '') + '</span>'; }).join(', ');
            html += '</div>';
        }

        // Section-level BR summary
        if (sectionBRs.length > 0) {
            html += '<div style="padding:0.4rem 1rem;font-size:0.8rem;border-bottom:1px solid var(--border);">';
            html += '<span style="color:var(--text-muted);font-weight:500;">' + sectionBRs.length + ' règle' + (sectionBRs.length > 1 ? 's' : '') + ' métier :</span> ';
            html += sectionBRs.map(function(br) { return '<span style="color:var(--text-bright);">' + escapeHtml(br.name || '') + '</span>'; }).join(', ');
            html += '</div>';
        }

        if (resources.length > 0) {
            html += '<div class="struct-resources">';
            resources.forEach(function(res) {
                var resName = typeof res === 'string' ? res : (res.code || res.name || '');
                var resType = typeof res === 'object' ? (res.type || '') : '';
                var resDesc = typeof res === 'object' ? (res.description || '') : '';
                html += '<div class="struct-resource">';
                html += '<span class="struct-resource-icon">&#8226;</span>';
                html += '<span class="struct-resource-name">' + escapeHtml(resName) + '</span>';
                if (resType) html += '<span style="font-size:0.7rem;color:var(--accent);background:rgba(6,182,212,0.1);padding:0.1rem 0.3rem;border-radius:3px;">' + escapeHtml(resType) + '</span>';
                if (resDesc) html += '<span class="struct-resource-desc">' + escapeHtml(resDesc) + '</span>';
                html += '</div>';
            });
            html += '</div>';
        }

        html += '</div>';
        return html;
    }).join('');
}

/* ---------- Section-Grouped Rendering (Hierarchical Mode) ---------- */

function renderSectionGroupedItems(mod, itemsKey, code, renderFn) {
    var sections = (mod.anticipatedSections || []).map(function(s) {
        return typeof s === 'string' ? { code: s, name: s, resources: [] } : s;
    });
    var html = '';
    sections.forEach(function(section) {
        var items = section[itemsKey] || [];
        if (items.length === 0) return;
        html += '<div class="section-group">';
        html += '<div class="section-group-header">';
        html += '<span class="section-group-icon">&#9655;</span> ';
        html += '<span class="section-group-label">' + escapeHtml(section.code || section.name || '') + '</span>';
        if (section.route) html += '<span class="section-group-route">' + escapeHtml(section.route) + '</span>';
        html += '<span class="nav-badge">' + items.length + '</span>';
        html += '</div>';
        html += items.map(function(item, i) { return renderFn(code, item, i); }).join('');
        html += '</div>';
    });
    return html;
}

function renderModuleMockups(code) {
    var spec = data.moduleSpecs[code] || {};
    var screens = spec.screens || [];
    var wireframes = EMBEDDED_ARTIFACTS?.wireframes?.[code] || [];
    var mod = data.modules.find(function(m) { return m.code === code; });
    var sections = mod ? (mod.anticipatedSections || []).map(function(s) {
        return typeof s === 'string' ? { code: s, name: s, resources: [] } : s;
    }) : [];

    // Priority 1: HTML mockups from screens[] specs (wireframes NOT shown when screens exist)
    var hasResources = screens.some(function(s) { return (s.resources || []).length > 0; });
    if (screens.length > 0 && hasResources) {
        var html = '';
        if (typeof renderScreenMockups === 'function') {
            html = renderScreenMockups(code);
        }
        return html;
    }

    // Priority 2: Wireframes grouped by section (if sections exist)
    if (wireframes.length > 0 && sections.length > 1) {
        var grouped = {};
        var ungrouped = [];
        wireframes.forEach(function(wf, i) {
            var sectionCode = wf.section || wf.sectionCode || '';
            var matchingSection = sections.find(function(s) { return s.code === sectionCode; });
            if (matchingSection) {
                if (!grouped[sectionCode]) grouped[sectionCode] = { section: matchingSection, items: [] };
                grouped[sectionCode].items.push({ wf: wf, index: i });
            } else {
                ungrouped.push({ wf: wf, index: i });
            }
        });

        var html = '';
        Object.keys(grouped).forEach(function(sectionCode) {
            var group = grouped[sectionCode];
            html += '<div class="section-group">';
            html += '<div class="section-group-header">';
            html += '<span class="section-group-icon">&#9655;</span> ';
            html += '<span class="section-group-label">' + escapeHtml(group.section.code || '') + '</span>';
            html += '<span class="nav-badge">' + group.items.length + '</span>';
            html += '</div>';
            group.items.forEach(function(item) {
                html += renderWireframeMockup(code, item.wf, item.index);
            });
            html += '</div>';
        });
        ungrouped.forEach(function(item) {
            html += renderWireframeMockup(code, item.wf, item.index);
        });
        return html;
    }

    // Priority 3: Flat wireframe list
    if (wireframes.length === 0) {
        return '<div class="card" style="text-align:center;padding:2rem;color:var(--text-muted);"><p>Aucune maquette disponible pour ce module.</p><p style="font-size:0.85rem;margin-top:0.5rem;">Les maquettes seront générées lors de la spécification détaillée.</p></div>';
    }
    return wireframes.map(function(wf, i) { return renderWireframeMockup(code, wf, i); }).join('');
}

function switchTab(code, tabId) {
    const section = document.getElementById('module-spec-' + code);
    if (!section) return;
    section.querySelectorAll('.tab-btn').forEach(function(btn) {
        btn.classList.remove('active');
        btn.setAttribute('aria-selected', 'false');
    });
    section.querySelectorAll('.tab-panel').forEach(function(panel) {
        panel.classList.remove('active');
        panel.setAttribute('aria-hidden', 'true');
    });
    const targetPanel = document.getElementById('tab-' + code + '-' + tabId);
    if (targetPanel) {
        targetPanel.classList.add('active');
        targetPanel.setAttribute('aria-hidden', 'false');
    }
    const buttons = section.querySelectorAll('.tab-btn');
    const tabIndex = { uc: 0, br: 1, ent: 2, perm: 3, mock: 4, notes: 5, struct: 6 }[tabId];
    if (buttons[tabIndex]) {
        buttons[tabIndex].classList.add('active');
        buttons[tabIndex].setAttribute('aria-selected', 'true');
    }
}


/* --- 06-render-consolidation.js --- */
/* ============================================
   CONSOLIDATION
   ============================================ */
function renderConsolidation() {
    renderDataModel();
    renderConsolInteractions();
    renderConsolPermissions();
}

/* ============================================
   DATA MODEL (cross-module entity overview)
   ============================================ */
function renderDataModel() {
    const container = document.getElementById('dataModelContainer');
    if (!container) return;

    // Collect all entities from all modules
    const allEntities = [];
    data.modules.forEach(m => {
        const spec = data.moduleSpecs[m.code] || {};
        (spec.entities || []).forEach(ent => {
            allEntities.push({ ...ent, moduleCode: m.code, moduleName: m.name || m.code });
        });
    });

    if (allEntities.length === 0) {
        container.innerHTML = '<p style="color:var(--text-muted);text-align:center;padding:2rem;">Aucune entité définie. Spécifiez les données dans chaque domaine (Phase 3 > onglet Données).</p>';
        return;
    }

    // Build relationship index for cross-module links
    const entityModuleMap = {};
    allEntities.forEach(e => { entityModuleMap[e.name] = e.moduleName; });

    // Render grouped by module
    let html = '';

    // Summary bar
    const moduleCount = data.modules.filter(m => (data.moduleSpecs[m.code]?.entities || []).length > 0).length;
    const relCount = allEntities.reduce((sum, e) => sum + (e.relationships || []).length, 0);
    html += `
        <div class="dm-summary">
            <div class="dm-summary-item"><span class="dm-summary-value">${allEntities.length}</span><span class="dm-summary-label">Entités</span></div>
            <div class="dm-summary-item"><span class="dm-summary-value">${moduleCount}</span><span class="dm-summary-label">Domaines</span></div>
            <div class="dm-summary-item"><span class="dm-summary-value">${relCount}</span><span class="dm-summary-label">Relations</span></div>
        </div>`;

    // Entity cards grouped by module
    data.modules.forEach(m => {
        const spec = data.moduleSpecs[m.code] || {};
        const entities = spec.entities || [];
        if (entities.length === 0) return;

        html += `<div class="dm-module-group">`;
        html += `<div class="dm-module-header">
            <span class="dm-module-name">${escapeHtml(m.name || m.code)}</span>
            <span class="dm-module-count">${entities.length} entité${entities.length > 1 ? 's' : ''}</span>
        </div>`;

        html += `<div class="dm-entity-grid">`;
        entities.forEach(ent => {
            const attrs = ent.attributes || [];
            const rels = ent.relationships || [];
            html += `
                <div class="dm-entity-card">
                    <div class="dm-entity-header">
                        <span class="dm-entity-name">${escapeHtml(ent.name)}</span>
                        <span class="dm-entity-attr-count">${attrs.length} champ${attrs.length > 1 ? 's' : ''}</span>
                    </div>
                    ${ent.description ? `<div class="dm-entity-desc">${escapeHtml(ent.description)}</div>` : ''}
                    ${attrs.length > 0 ? `
                    <table class="dm-attr-table">
                        <thead><tr><th>Champ</th><th style="width:100px;">Type</th><th>Description</th></tr></thead>
                        <tbody>
                            ${attrs.map(a => `<tr><td class="dm-attr-name">${escapeHtml(a.name)}</td><td style="font-family:monospace;font-size:0.8rem;color:var(--accent);">${escapeHtml(a.type || 'string')}</td><td class="dm-attr-desc">${escapeHtml(a.description || '')}</td></tr>`).join('')}
                        </tbody>
                    </table>` : ''}
                    ${rels.length > 0 ? `
                    <div class="dm-relations">
                        <div class="dm-relations-title">Relations</div>
                        ${rels.map(r => {
                            const relText = typeof r === 'string' ? r : (r.target + ' (' + r.type + ') - ' + (r.description || ''));
                            return `<div class="dm-relation-item">${escapeHtml(relText)}</div>`;
                        }).join('')}
                    </div>` : ''}
                </div>`;
        });
        html += `</div></div>`;
    });

    container.innerHTML = html;
}

function renderConsolInteractions() {
    const container = document.getElementById('consolInteractions');
    if (!container || data.dependencies.length === 0) return;

    container.innerHTML = data.dependencies.map(d => {
        const fromName = data.modules.find(m => m.code === d.from)?.name || d.from;
        const toName = data.modules.find(m => m.code === d.to)?.name || d.to;
        return `
            <div class="interaction-item">
                <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(fromName)}</span>
                <span class="interaction-arrow">&#8594;</span>
                <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(toName)}</span>
                <span class="interaction-type">Dépendance</span>
                <span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${escapeHtml(d.description || '')}</span>
            </div>`;
    }).join('');
}

function renderConsolPermissions() {
    const container = document.getElementById('consolPermissions');
    if (!container || data.modules.length === 0) return;

    const roles = getPermRoles();

    let html = '<table class="mock-table" style="background:var(--bg-card);border-radius:8px;overflow:hidden;">';
    html += '<thead><tr><th>Profil</th>';
    data.modules.forEach(m => { html += `<th style="text-align:center;">${escapeHtml(m.name || m.code)}</th>`; });
    html += '</tr></thead><tbody>';

    roles.forEach(role => {
        html += `<tr><td style="font-weight:500;color:var(--text-bright);">${escapeHtml(role)}</td>`;
        data.modules.forEach(m => {
            const allPerms = data.moduleSpecs[m.code]?.permissions || [];
            const hasWildcard = allPerms.includes(role + '|*');
            const perms = hasWildcard
                ? getPermActions()
                : allPerms.filter(p => p.startsWith(role + '|'));
            const count = perms.length;
            const color = count > 4 ? 'var(--success)' : count > 2 ? 'var(--warning)' : count > 0 ? 'var(--text-muted)' : 'var(--border)';
            const label = hasWildcard ? 'Tous' : (count > 0 ? count + ' droits' : 'Aucun');
            html += `<td style="text-align:center;color:${color};font-weight:600;">${label}</td>`;
        });
        html += '</tr>';
    });

    html += '</tbody></table>';
    container.innerHTML = html;
}

/* ============================================
   E2E FLOWS
   ============================================ */
function addE2EFlow() {
    const name = document.getElementById('flow-name').value.trim();
    if (!name) return;

    const steps = document.getElementById('flow-steps').value.split('\n').filter(l => l.trim()).map(l => {
        const parts = l.split(' - ');
        return { module: parts[0]?.trim() || '', action: parts.slice(1).join(' - ').trim() || l.trim() };
    });

    data.consolidation.e2eFlows.push({
        name: name,
        steps: steps,
        actors: document.getElementById('flow-actors').value.trim()
    });

    renderE2EFlows();
    toggleForm('addFlowForm');
    clearForm('addFlowForm');
    autoSave();
}

function removeE2EFlow(index) {
    if (!confirm('Supprimer ce parcours bout en bout ?')) return;
    data.consolidation.e2eFlows.splice(index, 1);
    renderE2EFlows();
    autoSave();
}

function renderE2EFlows() {
    const container = document.getElementById('e2eFlowsList');
    if (!container) return;

    container.innerHTML = data.consolidation.e2eFlows.map((flow, fi) => `
        <div class="card" style="margin-bottom:1rem;">
            <div class="card-header">
                <span class="card-title">${escapeHtml(flow.name)}</span>
                <button class="btn btn-sm" onclick="removeE2EFlow(${fi})" style="opacity:0.5;">Supprimer</button>
            </div>
            ${flow.actors ? `<div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.5rem;">Intervenants : ${escapeHtml(flow.actors)}</div>` : ''}
            <div class="e2e-flow">
                ${flow.steps.map((s, i) => `
                    <div class="e2e-step">
                        <div class="e2e-step-module">${escapeHtml(s.module)}</div>
                        <div class="e2e-step-action">${escapeHtml(s.action)}</div>
                    </div>
                    ${i < flow.steps.length - 1 ? '<div class="process-arrow">&#8594;</div>' : ''}
                `).join('')}
            </div>
        </div>
    `).join('');
}


/* --- 06-render-mockups.js --- */
/* ============================================
   HTML MOCKUP RENDERER
   Generates realistic HTML mockups from screens[] specs
   ============================================ */

var _formTabCounter = 0;

function renderScreenMockups(code) {
    var spec = data.moduleSpecs[code] || {};
    var screens = spec.screens || [];

    if (screens.length === 0) return '';

    return screens.map(function(screen, si) {
        var resources = screen.resources || [];
        var content = resources.length > 0
            ? resources.map(function(res, ri) {
                return renderResourceMockup(code, screen.sectionCode, res, ri);
            }).join('')
            : '<div class="card" style="padding:1.5rem;color:var(--text-muted);text-align:center;"><p>Maquette en attente de spécification pour cette section.</p></div>';
        return '<div class="screen-section" id="screen-' + code + '-' + screen.sectionCode + '" style="margin-bottom:2rem;">' +
            '<h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:1rem;">' +
            '<span style="color:var(--accent);">&#9656;</span> ' + escapeHtml(screen.sectionLabel || screen.sectionCode) +
            '</h3>' +
            content +
        '</div>';
    }).join('');
}

function renderResourceMockup(code, sectionCode, res, index) {
    var mockupId = 'mockup-' + code + '-' + sectionCode + '-' + index;
    var html = '<div class="mockup-frame" style="margin-bottom:1.5rem;">';

    // Browser chrome
    html += '<div class="mockup-toolbar">';
    html += '<div class="mockup-dot mockup-dot-red"></div>';
    html += '<div class="mockup-dot mockup-dot-yellow"></div>';
    html += '<div class="mockup-dot mockup-dot-green"></div>';
    html += '<span class="mockup-title">' + escapeHtml(res.label || res.code) + ' (' + res.type + ')</span>';
    if (res.permission) {
        html += '<span style="margin-left:auto;font-size:0.65rem;color:var(--text-muted);background:var(--bg-dark);padding:0.15rem 0.5rem;border-radius:4px;">' + escapeHtml(res.permission) + '</span>';
    }
    html += '</div>';

    // Mockup content
    html += '<div class="mockup-content" id="' + mockupId + '">';
    switch (res.type) {
        case 'SmartTable':
            html += renderSmartTableMockup(res);
            break;
        case 'SmartForm':
            html += renderSmartFormMockup(res);
            break;
        case 'SmartCard':
            html += renderSmartCardMockup(res);
            break;
        case 'SmartKanban':
            html += renderSmartKanbanMockup(res);
            break;
        case 'SmartDashboard':
            html += renderSmartDashboardMockup(res);
            break;
        case 'SmartFilter':
            html += renderSmartFilterMockup(res);
            break;
        default:
            html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Composant ' + res.type + ' - maquette non disponible</div>';
    }
    html += '</div>';

    // Notes
    if (res.notes) {
        html += '<div style="padding:0.5rem 1rem;font-size:0.8rem;color:var(--text-muted);border-top:1px solid var(--border);background:var(--bg-input);">';
        html += '<strong>Notes:</strong> ' + escapeHtml(res.notes);
        html += '</div>';
    }

    // Comment area
    html += '<div class="wireframe-comment">';
    html += '<label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire :</label>';
    html += '<textarea class="form-textarea" placeholder="Commentaire sur cette maquette..."';
    html += ' onblur="updateWireframeComment(\'' + code + '\', \'' + (res.code || sectionCode + '-' + index) + '\', this.value)"';
    html += ' style="min-height:50px;font-size:0.85rem;resize:vertical;">';
    html += getWireframeComment(code, res.code || sectionCode + '-' + index);
    html += '</textarea>';
    html += '</div>';

    html += '</div>';
    return html;
}

/* ---------- SmartTable ---------- */
function renderSmartTableMockup(res) {
    var columns = res.columns || [];
    if (columns.length === 0) return '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Table sans colonnes définies</div>';

    var html = '';

    // Header with actions
    html += '<div class="mock-header">';
    html += '<span class="mock-title">' + escapeHtml(res.label || 'Liste') + '</span>';
    html += '<div style="display:flex;gap:0.4rem;">';
    (res.actions || []).forEach(function(action) {
        var isPrimary = action === 'create' || action === 'export';
        html += '<span class="mock-btn' + (isPrimary ? '' : '" style="background:var(--bg-hover);color:var(--text)') + '">' + formatActionLabel(action) + '</span>';
    });
    html += '</div></div>';

    // Filters
    if (res.filters && res.filters.length > 0) {
        html += '<div style="display:flex;gap:0.5rem;margin-bottom:1rem;">';
        res.filters.forEach(function(f) {
            html += '<span class="mock-input" style="width:auto;min-width:120px;font-size:0.8rem;color:var(--text-muted);">' + f + ' &#9662;</span>';
        });
        html += '<span class="mock-input" style="width:auto;min-width:200px;font-size:0.8rem;color:var(--text-muted);">Rechercher...</span>';
        html += '</div>';
    }

    // Table
    html += '<table class="mock-table">';
    html += '<thead><tr>';
    columns.forEach(function(col) {
        html += '<th>' + escapeHtml(col.label || col.field);
        if (col.sortable) html += ' <span style="font-size:0.6rem;color:var(--text-muted);">&#9650;&#9660;</span>';
        html += '</th>';
    });
    html += '<th style="width:80px;">Actions</th>';
    html += '</tr></thead>';

    // Sample rows
    html += '<tbody>';
    var sampleData = generateSampleRows(columns, 4);
    sampleData.forEach(function(row) {
        html += '<tr>';
        columns.forEach(function(col) {
            var val = row[col.field] || '';
            if (col.type === 'badge') {
                html += '<td><span class="mock-status mock-status-active">' + val + '</span></td>';
            } else if (col.type === 'lookup') {
                html += '<td style="color:var(--accent);">' + val + '</td>';
            } else {
                html += '<td>' + val + '</td>';
            }
        });
        html += '<td style="text-align:center;"><span style="cursor:pointer;color:var(--text-muted);">&#9998; &#128465;</span></td>';
        html += '</tr>';
    });
    html += '</tbody></table>';

    // Pagination
    html += '<div style="display:flex;justify-content:space-between;align-items:center;padding:0.75rem 0;font-size:0.8rem;color:var(--text-muted);">';
    html += '<span>1-4 sur 24 résultats</span>';
    html += '<div style="display:flex;gap:0.3rem;">';
    html += '<span class="mock-btn" style="background:var(--primary);font-size:0.75rem;padding:0.2rem 0.5rem;">1</span>';
    html += '<span class="mock-btn" style="background:var(--bg-hover);font-size:0.75rem;padding:0.2rem 0.5rem;">2</span>';
    html += '<span class="mock-btn" style="background:var(--bg-hover);font-size:0.75rem;padding:0.2rem 0.5rem;">3</span>';
    html += '</div></div>';

    return html;
}

/* ---------- SmartForm ---------- */
function renderSmartFormMockup(res) {
    var tabs = res.tabs || [];
    if (tabs.length === 0 && res.fields) {
        tabs = [{ label: 'Informations', fields: res.fields }];
    }
    if (tabs.length === 0) return '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Formulaire sans champs définis</div>';

    var mockupId = 'form-tabs-' + (++_formTabCounter);
    var html = '';

    // Header
    html += '<div class="mock-header">';
    html += '<span class="mock-title">' + escapeHtml(res.label || 'Formulaire') + '</span>';
    html += '<div style="display:flex;gap:0.4rem;">';
    (res.actions || ['save', 'cancel']).forEach(function(action) {
        var isPrimary = action === 'save';
        html += '<span class="mock-btn' + (isPrimary ? '' : '" style="background:var(--bg-hover);color:var(--text)') + '">' + formatActionLabel(action) + '</span>';
    });
    html += '</div></div>';

    // Tabs (clickable when more than 1)
    if (tabs.length > 1) {
        html += '<div class="mock-form-tab-bar" data-mockup="' + mockupId + '">';
        tabs.forEach(function(tab, i) {
            html += '<span class="mock-form-tab' + (i === 0 ? ' active' : '') + '"';
            html += ' onclick="switchFormTab(\'' + mockupId + '\', ' + i + ')"';
            html += '>' + escapeHtml(tab.label) + '</span>';
        });
        html += '</div>';
    }

    // Tab contents (all rendered, only first visible)
    tabs.forEach(function(tab, ti) {
        var isOnly = tabs.length <= 1;
        html += '<div class="mock-form-tab-content' + (ti === 0 || isOnly ? ' active' : '') + '"';
        html += ' data-mockup="' + mockupId + '" data-tab="' + ti + '">';

        // Tab-level subtable: the entire tab is a subtable (type: "subtable", entity, columns)
        if (tab.type === 'subtable') {
            html += renderSubtableMockup(tab);
        } else {
            var fields = tab.fields || [];
            var rows = [];
            for (var i = 0; i < fields.length; i += 2) {
                rows.push(fields.slice(i, i + 2));
            }

            rows.forEach(function(row) {
                if (row.length === 1 && row[0].type === 'subtable') {
                    html += renderSubtableMockup(row[0]);
                } else {
                    html += '<div class="mock-form-row">';
                    row.forEach(function(field) {
                        html += '<div class="mock-form-group">';
                        html += '<label class="mock-label">' + escapeHtml(field.label || field.field);
                        if (field.required) html += ' <span style="color:var(--error);">*</span>';
                        html += '</label>';
                        html += renderFormFieldMockup(field);
                        html += '</div>';
                    });
                    html += '</div>';
                }
            });

            if (fields.length === 0) {
                html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);font-style:italic;">Contenu de l\'onglet &laquo; ' + escapeHtml(tab.label) + ' &raquo;</div>';
            }
        }

        html += '</div>';
    });

    return html;
}

function renderFormFieldMockup(field) {
    var val = generateSampleValue(field);
    switch (field.type) {
        case 'select':
            return '<span class="mock-input" style="display:block;">' + val + ' &#9662;</span>';
        case 'lookup':
            return '<span class="mock-input" style="display:block;color:var(--accent);">' + val + ' &#128269;</span>';
        case 'date':
            return '<span class="mock-input" style="display:block;">' + val + ' &#128197;</span>';
        case 'textarea':
            return '<span class="mock-input" style="display:block;min-height:60px;">' + val + '</span>';
        case 'checkbox':
            return '<div style="display:flex;align-items:center;gap:0.5rem;"><input type="checkbox" checked disabled style="width:16px;height:16px;"><span style="font-size:0.85rem;color:var(--text);">' + val + '</span></div>';
        default:
            return '<span class="mock-input" style="display:block;' + (field.readonly ? 'opacity:0.6;' : '') + '">' + val + '</span>';
    }
}

function renderSubtableMockup(field) {
    var cols = field.columns || [];
    var entity = field.entity || 'Element';
    var html = '<div style="margin:1rem 0;border:1px solid var(--border);border-radius:8px;overflow:hidden;">';
    html += '<div style="display:flex;justify-content:space-between;align-items:center;padding:0.5rem 0.75rem;background:var(--bg-hover);">';
    html += '<span style="font-weight:500;color:var(--text-bright);font-size:0.85rem;">' + escapeHtml(entity) + '</span>';
    html += '<span class="mock-btn" style="font-size:0.75rem;padding:0.2rem 0.5rem;">+ Ajouter</span>';
    html += '</div>';
    html += '<table class="mock-table"><thead><tr>';
    cols.forEach(function(c) { html += '<th>' + escapeHtml(c) + '</th>'; });
    html += '</tr></thead><tbody>';
    html += '<tr>' + cols.map(function() { return '<td style="color:var(--text-muted);font-style:italic;">...</td>'; }).join('') + '</tr>';
    html += '</tbody></table></div>';
    return html;
}

/* ---------- SmartCard ---------- */
function renderSmartCardMockup(res) {
    var fields = res.fields || res.columns || [];
    var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Cartes') + '</span></div>';
    html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1rem;">';

    for (var i = 0; i < 4; i++) {
        html += '<div style="background:var(--bg-hover);border:1px solid var(--border);border-radius:8px;padding:1rem;">';
        // Title/Subtitle pattern (SmartCard with title + subtitle + fields + actions)
        if (res.title) {
            html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.25rem;">' + escapeHtml(res.title) + ' #' + (i + 1) + '</div>';
        }
        if (res.subtitle) {
            html += '<div style="font-size:0.8rem;color:var(--accent);margin-bottom:0.5rem;">' + escapeHtml(res.subtitle) + '</div>';
        }
        // Fields
        fields.forEach(function(col, ci) {
            var label = col.label || col.field || (typeof col === 'string' ? col : '');
            var iconMap = { calendar: '&#128197; ', 'dollar-sign': '&#128176; ', 'alert-circle': '&#9888; ', mail: '&#9993; ', building: '&#127970; ', user: '&#128100; ' };
            var icon = col.icon ? (iconMap[col.icon] || '&#9679; ') : '';
            if (!res.title && ci === 0) {
                html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.5rem;">' + escapeHtml(label) + ' #' + (i + 1) + '</div>';
            } else {
                html += '<div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.25rem;">' + icon + escapeHtml(label) + ': <span style="color:var(--text);">valeur</span></div>';
            }
        });
        // Actions
        if (res.actions && res.actions.length > 0) {
            html += '<div style="margin-top:0.75rem;display:flex;gap:0.4rem;">';
            res.actions.forEach(function(a) {
                var actionLabel = typeof a === 'string' ? a.replace(/-/g, ' ') : (a.label || a.action || '');
                html += '<span class="mock-btn" style="font-size:0.75rem;">' + escapeHtml(actionLabel) + '</span>';
            });
            html += '</div>';
        }
        html += '</div>';
    }
    html += '</div>';
    return html;
}

/* ---------- SmartKanban ---------- */
function renderSmartKanbanMockup(res) {
    var options = (res.options && res.options.length > 0) ? res.options : (res.columns && res.columns.length > 0) ? res.columns : ['À faire', 'En cours', 'Terminé'];
    var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Kanban') + '</span></div>';
    html += '<div style="display:flex;gap:1rem;overflow-x:auto;padding-bottom:0.5rem;">';

    options.forEach(function(col, ci) {
        var colLabel = typeof col === 'string' ? col : (col.label || col.field || 'Colonne');
        html += '<div style="min-width:200px;flex:1;background:var(--bg-hover);border-radius:8px;padding:0.75rem;">';
        html += '<div style="font-weight:600;font-size:0.85rem;color:var(--text-bright);margin-bottom:0.75rem;display:flex;justify-content:space-between;">';
        html += escapeHtml(colLabel) + ' <span style="font-size:0.7rem;background:var(--bg-card);padding:0.1rem 0.4rem;border-radius:4px;color:var(--text-muted);">' + (3 - ci) + '</span>';
        html += '</div>';
        for (var j = 0; j < Math.max(1, 3 - ci); j++) {
            html += '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:6px;padding:0.5rem;margin-bottom:0.5rem;font-size:0.8rem;">';
            html += '<div style="color:var(--text-bright);font-weight:500;">Élément ' + (j + 1) + '</div>';
            html += '<div style="color:var(--text-muted);font-size:0.7rem;margin-top:0.25rem;">Description...</div>';
            html += '</div>';
        }
        html += '</div>';
    });
    html += '</div>';
    return html;
}

/* ---------- SmartDashboard ---------- */
function renderSmartDashboardMockup(res) {
    var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Tableau de bord') + '</span></div>';

    // KPI cards
    html += '<div class="mock-kpi-grid">';
    var kpis = res.kpis || [
        { label: 'Total', value: '1,234' },
        { label: 'Actifs', value: '987' },
        { label: 'En attente', value: '156' },
        { label: 'Taux', value: '80%' }
    ];
    kpis.forEach(function(kpi) {
        var displayValue = kpiDisplayValue(kpi);
        html += '<div class="mock-kpi"><div class="mock-kpi-value">' + escapeHtml(displayValue) + '</div><div class="mock-kpi-label">' + escapeHtml(kpi.label || '') + '</div></div>';
    });
    html += '</div>';

    // Charts (SVG mock previews)
    var charts = res.charts || [{ label: 'Graphique', type: 'bar' }];
    charts.forEach(function(chart) {
        html += renderMockChart(chart);
    });

    return html;
}

function kpiDisplayValue(kpi) {
    var v = kpi.value || '0';
    // If value is already a simple display value (number, percentage), use it
    if (/^\d[\d,.\s]*%?$/.test(v)) return v;
    // Detect formula patterns and generate realistic sample values
    if (v.indexOf('(') !== -1) {
        var label = (kpi.label || '').toLowerCase();
        var color = (kpi.color || '').toLowerCase();
        // Percentage indicators
        if (v.indexOf('ratio') !== -1 || v.indexOf('%') !== -1 || label.indexOf('taux') !== -1 || label.indexOf('rate') !== -1)
            return '87.5%';
        // Average
        if (v.indexOf('avg') !== -1 || label.indexOf('moyen') !== -1 || label.indexOf('average') !== -1)
            return '12.4';
        // Sum (monetary or hours)
        if (v.indexOf('sum') !== -1)
            return label.indexOf('jour') !== -1 || label.indexOf('day') !== -1 ? '156' : '45,678';
        // Count (default)
        return '1,234';
    }
    return v;
}

/* ---------- SmartFilter ---------- */
function renderSmartFilterMockup(res) {
    var filters = res.filters || [];
    if (filters.length === 0) {
        // Fallback: legacy options[] format (tag pills)
        var options = res.options || [];
        if (options.length === 0) return '<div style="padding:1rem;text-align:center;color:var(--text-muted);">Aucun filtre défini</div>';
        var html = '<div style="display:flex;gap:0.4rem;flex-wrap:wrap;padding:0.5rem 0;">';
        html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--primary);color:#fff;cursor:pointer;">Tous</span>';
        options.forEach(function(opt) {
            html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--bg-hover);color:var(--text);border:1px solid var(--border);cursor:pointer;">' + escapeHtml(typeof opt === 'string' ? opt : opt.label || '') + '</span>';
        });
        html += '</div>';
        return html;
    }

    // Rich filter bar: render each filter based on its type
    var html = '<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:flex-end;padding:0.5rem 0;">';
    filters.forEach(function(f) {
        var label = typeof f === 'string' ? f : (f.label || f.field || '');
        var type = typeof f === 'string' ? 'text' : (f.type || 'text');
        html += '<div style="display:flex;flex-direction:column;gap:0.2rem;">';
        html += '<span style="font-size:0.7rem;color:var(--text-muted);">' + escapeHtml(label) + '</span>';
        switch (type) {
            case 'select':
                var opts = f.options || ['Option 1', 'Option 2'];
                html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--text-muted);">' + escapeHtml(opts[0]) + ' &#9662;</span>';
                break;
            case 'lookup':
                html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--accent);">' + escapeHtml(f.entity || label) + ' &#128269;</span>';
                break;
            case 'daterange':
                html += '<span class="mock-input" style="width:auto;min-width:180px;font-size:0.8rem;color:var(--text-muted);">01/01/2025 — 31/12/2025 &#128197;</span>';
                break;
            default:
                html += '<span class="mock-input" style="width:auto;min-width:160px;font-size:0.8rem;color:var(--text-muted);">Rechercher... &#128269;</span>';
        }
        html += '</div>';
    });
    html += '</div>';
    return html;
}

/* ---------- Mock Charts ---------- */
function renderMockChart(chart) {
    var type = (chart.type || '').toLowerCase();
    var label = chart.label || chart.type || 'Graphique';
    var html = '<div class="mock-chart-container">';
    html += '<div class="mock-chart-header">' + escapeHtml(label) + '</div>';
    html += '<div class="mock-chart-body">';
    if (type === 'pie' || type === 'donut') {
        html += renderMockPieChart();
    } else if (type === 'line' || type === 'area') {
        html += renderMockLineChart();
    } else {
        html += renderMockBarChart();
    }
    html += '</div></div>';
    return html;
}

function renderMockPieChart() {
    var html = '<div style="display:flex;align-items:center;gap:1.5rem;">';
    html += '<svg viewBox="0 0 42 42" class="mock-pie-svg">';
    html += '<circle cx="21" cy="21" r="15.9" fill="transparent" stroke="var(--primary)" stroke-width="8" stroke-dasharray="35 65" stroke-dashoffset="25"/>';
    html += '<circle cx="21" cy="21" r="15.9" fill="transparent" stroke="var(--success)" stroke-width="8" stroke-dasharray="25 75" stroke-dashoffset="-10"/>';
    html += '<circle cx="21" cy="21" r="15.9" fill="transparent" stroke="var(--warning)" stroke-width="8" stroke-dasharray="22 78" stroke-dashoffset="-35"/>';
    html += '<circle cx="21" cy="21" r="15.9" fill="transparent" stroke="var(--error)" stroke-width="8" stroke-dasharray="18 82" stroke-dashoffset="-57"/>';
    html += '</svg>';
    html += '<div class="mock-chart-legend">';
    html += '<div><span class="mock-legend-dot" style="background:var(--primary);"></span> Cat\u00e9gorie A (35%)</div>';
    html += '<div><span class="mock-legend-dot" style="background:var(--success);"></span> Cat\u00e9gorie B (25%)</div>';
    html += '<div><span class="mock-legend-dot" style="background:var(--warning);"></span> Cat\u00e9gorie C (22%)</div>';
    html += '<div><span class="mock-legend-dot" style="background:var(--error);"></span> Cat\u00e9gorie D (18%)</div>';
    html += '</div></div>';
    return html;
}

function renderMockBarChart() {
    var bars = [85, 60, 45, 70, 55, 90];
    var labels = ['Jan', 'F\u00e9v', 'Mar', 'Avr', 'Mai', 'Jun'];
    var html = '<svg viewBox="0 0 300 140" class="mock-bar-svg">';
    html += '<line x1="30" y1="10" x2="30" y2="120" stroke="var(--border)" stroke-width="1"/>';
    html += '<line x1="30" y1="120" x2="290" y2="120" stroke="var(--border)" stroke-width="1"/>';
    html += '<line x1="30" y1="40" x2="290" y2="40" stroke="var(--border)" stroke-width="0.5" stroke-dasharray="4"/>';
    html += '<line x1="30" y1="80" x2="290" y2="80" stroke="var(--border)" stroke-width="0.5" stroke-dasharray="4"/>';
    var bw = 30, gap = 13;
    bars.forEach(function(h, i) {
        var x = 35 + i * (bw + gap);
        var y = 120 - h * 1.1;
        html += '<rect x="' + x + '" y="' + y + '" width="' + bw + '" height="' + (h * 1.1) + '" fill="var(--primary)" rx="3" opacity="' + (0.6 + i * 0.08) + '"/>';
        html += '<text x="' + (x + bw / 2) + '" y="134" text-anchor="middle" fill="var(--text-muted)" font-size="9">' + labels[i] + '</text>';
    });
    html += '</svg>';
    return html;
}

function renderMockLineChart() {
    var points = '40,90 90,65 140,75 190,40 240,50 280,25';
    var labels = ['Jan', 'F\u00e9v', 'Mar', 'Avr', 'Mai', 'Jun'];
    var xs = [40, 90, 140, 190, 240, 280];
    var html = '<svg viewBox="0 0 300 140" class="mock-line-svg">';
    html += '<line x1="30" y1="10" x2="30" y2="120" stroke="var(--border)" stroke-width="1"/>';
    html += '<line x1="30" y1="120" x2="290" y2="120" stroke="var(--border)" stroke-width="1"/>';
    html += '<line x1="30" y1="40" x2="290" y2="40" stroke="var(--border)" stroke-width="0.5" stroke-dasharray="4"/>';
    html += '<line x1="30" y1="80" x2="290" y2="80" stroke="var(--border)" stroke-width="0.5" stroke-dasharray="4"/>';
    html += '<polygon fill="var(--primary)" opacity="0.1" points="' + points + ' 280,120 40,120"/>';
    html += '<polyline fill="none" stroke="var(--primary)" stroke-width="2.5" points="' + points + '" stroke-linecap="round" stroke-linejoin="round"/>';
    points.split(' ').forEach(function(p) {
        var xy = p.split(',');
        html += '<circle cx="' + xy[0] + '" cy="' + xy[1] + '" r="3" fill="var(--primary)" stroke="var(--bg-card)" stroke-width="1.5"/>';
    });
    xs.forEach(function(x, i) {
        html += '<text x="' + x + '" y="134" text-anchor="middle" fill="var(--text-muted)" font-size="9">' + labels[i] + '</text>';
    });
    html += '</svg>';
    return html;
}

/* ---------- Form Tab Switching ---------- */
function switchFormTab(mockupId, tabIndex) {
    document.querySelectorAll('.mock-form-tab-bar[data-mockup="' + mockupId + '"] .mock-form-tab').forEach(function(t) {
        t.classList.remove('active');
    });
    var allTabs = document.querySelectorAll('.mock-form-tab-bar[data-mockup="' + mockupId + '"] .mock-form-tab');
    if (allTabs[tabIndex]) allTabs[tabIndex].classList.add('active');
    document.querySelectorAll('.mock-form-tab-content[data-mockup="' + mockupId + '"]').forEach(function(el) {
        el.classList.remove('active');
    });
    var target = document.querySelector('.mock-form-tab-content[data-mockup="' + mockupId + '"][data-tab="' + tabIndex + '"]');
    if (target) target.classList.add('active');
}

/* ---------- Helpers ---------- */
function formatActionLabel(action) {
    var labels = {
        create: 'Nouveau', edit: 'Modifier', delete: 'Supprimer',
        export: 'Exporter', save: 'Enregistrer', cancel: 'Annuler',
        validate: 'Valider', archive: 'Archiver', print: 'Imprimer'
    };
    return labels[action] || action;
}

function generateSampleRows(columns, count) {
    var rows = [];
    for (var i = 0; i < count; i++) {
        var row = {};
        columns.forEach(function(col) {
            row[col.field] = generateSampleValue(col, i);
        });
        rows.push(row);
    }
    return rows;
}

function generateSampleValue(field, index) {
    var idx = (index || 0) + 1;
    var t = field.type || 'text';
    var f = field.field || '';

    if (field.options && field.options.length > 0) {
        return field.options[idx % field.options.length];
    }

    if (t === 'date') return '0' + idx + '/03/2026';
    if (t === 'badge' || t === 'select') return 'Actif';
    if (t === 'lookup') return f.replace(/Id$/, '') + ' #' + idx;
    if (t === 'number') return String(idx * 100);
    if (t === 'checkbox') return idx % 2 === 0 ? 'Oui' : 'Non';

    if (f.toLowerCase().includes('code')) return 'CODE-' + String(idx).padStart(3, '0');
    if (f.toLowerCase().includes('name') || f.toLowerCase().includes('nom')) return 'Nom ' + idx;
    if (f.toLowerCase().includes('email')) return 'user' + idx + '@example.com';
    if (f.toLowerCase().includes('date')) return '0' + idx + '/03/2026';
    if (f.toLowerCase().includes('status') || f.toLowerCase().includes('statut')) return 'Actif';

    return f + ' ' + idx;
}


/* --- 07-render-handoff.js --- */
/* ============================================
   HANDOFF / SYNTHESE
   ============================================ */
function renderHandoff() {
    renderHandoffStats();
    renderHandoffModules();
    renderCoverageMatrix();
    renderProgressIndicator();
}

function renderHandoffStats() {
    const container = document.getElementById('handoffStats');
    if (!container) return;

    const totalUCs = data.modules.reduce((sum, m) => sum + (data.moduleSpecs[m.code]?.useCases || []).length, 0);
    const totalBRs = data.modules.reduce((sum, m) => sum + (data.moduleSpecs[m.code]?.businessRules || []).length, 0);
    const totalEnts = data.modules.reduce((sum, m) => sum + (data.moduleSpecs[m.code]?.entities || []).length, 0);
    const totalStakeholders = data.cadrage.stakeholders.length;

    container.innerHTML = `
        <div class="stat-card"><div class="stat-value">${data.modules.length}</div><div class="stat-label">Domaines fonctionnels</div></div>
        <div class="stat-card"><div class="stat-value">${totalUCs}</div><div class="stat-label">Cas d'utilisation</div></div>
        <div class="stat-card"><div class="stat-value">${totalBRs}</div><div class="stat-label">Règles métier</div></div>
        <div class="stat-card"><div class="stat-value">${totalEnts}</div><div class="stat-label">Types de données</div></div>
        <div class="stat-card"><div class="stat-value">${totalStakeholders}</div><div class="stat-label">Profils utilisateurs</div></div>
        <div class="stat-card"><div class="stat-value">${data.dependencies.length}</div><div class="stat-label">Dépendances</div></div>
        <div class="stat-card"><div class="stat-value">${data.consolidation.e2eFlows.length}</div><div class="stat-label">Parcours bout en bout</div></div>
    `;
}

function renderHandoffModules() {
    const container = document.getElementById('handoffModuleList');
    if (!container) return;

    const layers = computeTopologicalLayers();
    const order = layers ? layers.flat() : data.modules.map(m => m.code);

    container.innerHTML = order.map((code, i) => {
        const m = data.modules.find(mod => mod.code === code);
        if (!m) return '';
        const spec = data.moduleSpecs[code] || {};
        return `
            <div class="card" style="margin-bottom:0.75rem;">
                <div style="display:flex;align-items:center;gap:0.75rem;">
                    <div style="width:28px;height:28px;border-radius:50%;background:var(--primary);display:flex;align-items:center;justify-content:center;color:#fff;font-size:0.75rem;font-weight:700;flex-shrink:0;">${i + 1}</div>
                    <div style="flex:1;">
                        <div style="font-weight:600;color:var(--text-bright);">${escapeHtml(m.name)}</div>
                        <div style="font-size:0.8rem;color:var(--text-muted);">${escapeHtml(m.description || '')}</div>
                    </div>
                    <div style="display:flex;gap:1rem;font-size:0.75rem;color:var(--text-muted);">
                        <span>${(spec.useCases || []).length} cas d'utilisation</span>
                        <span>${(spec.businessRules || []).length} règles</span>
                        <span>${(spec.entities || []).length} données</span>
                    </div>
                </div>
            </div>`;
    }).join('');
}

function renderCoverageMatrix() {
    const container = document.getElementById('coverageMatrix');
    if (!container) return;

    const allScope = (data.cadrage.scope.inscope || []).map(item => ({ ...item, priority: 'inscope' }));

    if (allScope.length === 0) {
        container.innerHTML = '<p style="color:var(--text-muted);font-style:italic;">Aucun élément de périmètre défini dans le cadrage.</p>';
        return;
    }

    container.innerHTML = `
        <table class="mock-table" style="background:var(--bg-card);border-radius:8px;overflow:hidden;">
            <thead><tr><th>Besoin</th><th>Périmètre</th><th>Domaine</th><th>Couvert</th></tr></thead>
            <tbody>
                ${allScope.map(item => {
                    const moduleName = item.module
                        ? (data.modules.find(m => m.code === item.module)?.name || item.module)
                        : (data.modules.length > 0 ? data.modules.map(m => m.name).join(', ') : 'À définir');
                    return `
                        <tr>
                            <td>${escapeHtml(item.name)}</td>
                            <td><span class="priority priority-${item.priority}">${formatPriority(item.priority)}</span></td>
                            <td style="color:var(--text-muted);">${escapeHtml(moduleName)}</td>
                            <td style="text-align:center;color:var(--success);">&#10003;</td>
                        </tr>`;
                }).join('')}
            </tbody>
        </table>`;
}

function renderProgressIndicator() {
    var container = document.getElementById('progressIndicator');
    if (!container) return;
    var p = computeProgress();
    var html = '<div class="progress-bar-container">';
    html += '<div class="progress-bar-fill" style="width:' + p.pct + '%;"></div>';
    html += '</div>';
    html += '<div class="progress-label">' + p.pct + '% complet — ' + p.doneCount + '/' + p.total + ' critères</div>';
    html += '<div class="progress-checks">';
    p.checks.forEach(function(c) {
        html += '<div class="progress-check ' + (c.done ? 'done' : '') + '">';
        html += '<span class="progress-check-icon">' + (c.done ? '&#10003;' : '&#9675;') + '</span> ';
        html += escapeHtml(c.label);
        html += '</div>';
    });
    html += '</div>';
    container.innerHTML = html;
}


/* --- 08-editing.js --- */
/* ============================================
   PERSISTENCE
   ============================================ */
let _saveTimer;
function autoSave() {
    clearTimeout(_saveTimer);
    _saveTimer = setTimeout(function() {
        data.metadata.lastModified = new Date().toISOString();
        localStorage.setItem(APP_KEY, JSON.stringify(data));
    }, 500);
}

function saveToLocalStorage() {
    autoSave();
    showNotification('Modifications sauvegardées');
}

function resetToEmbedded() {
    if (!confirm('Réinitialiser toutes les données depuis la version d\'origine ? Vos modifications locales (commentaires, notes) seront perdues.')) return;
    localStorage.removeItem(APP_KEY);
    // Restore data from ORIGINAL_DATA
    Object.keys(data).forEach(k => delete data[k]);
    Object.assign(data, JSON.parse(JSON.stringify(ORIGINAL_DATA)));
    // Re-render everything
    initEditableFields();
    renderStakeholders();
    renderScope();
    renderCriteria();
    renderModules();
    renderDependencies();
    renderAllModuleSpecs();
    renderConsolidation();
    renderHandoff();
    renderE2EFlows();
    updateCounts();
    renderReviewPanel();
    showNotification('Données réinitialisées depuis la version d\'origine');
}

function loadFromLocalStorage() {
    const saved = localStorage.getItem(APP_KEY);
    if (!saved) return;

    try {
        const parsed = JSON.parse(saved);

        // Build fingerprint of embedded structural data to detect HTML regeneration
        const embeddedFingerprint = ORIGINAL_DATA.modules.map(m => m.code).sort().join(',')
            + '|' + (ORIGINAL_DATA.metadata?.createdAt || '')
            + '|' + ORIGINAL_DATA.modules.length;
        const cachedFingerprint = parsed._structureFingerprint || '';

        const structureChanged = embeddedFingerprint !== cachedFingerprint;
        const embeddedModuleCount = ORIGINAL_DATA.modules?.length || 0;
        const cachedModuleCount = (parsed.modules || []).length;
        const hasNewModules = embeddedModuleCount > cachedModuleCount;
        const embeddedModuleCodes = new Set(ORIGINAL_DATA.modules.map(m => m.code));
        const cachedModuleCodes = new Set((parsed.modules || []).map(m => m.code));
        const missingModules = [...embeddedModuleCodes].filter(c => !cachedModuleCodes.has(c));

        if (structureChanged || hasNewModules || missingModules.length > 0) {
            // HTML was regenerated or has new modules — keep embedded structural data
            // Only restore user-specific edits (comments, custom roles, notes)
            data.wireframeComments = parsed.wireframeComments || {};
            data.specComments = parsed.specComments || {};
            data.customRoles = parsed.customRoles || [];
            data.customActions = parsed.customActions || [];
            data.comments = parsed.comments || [];

            // Merge user-added notes per module (preserve existing module notes)
            for (const code of Object.keys(parsed.moduleSpecs || {})) {
                if (data.moduleSpecs[code] && parsed.moduleSpecs[code]?.notes) {
                    data.moduleSpecs[code].notes = parsed.moduleSpecs[code].notes;
                }
            }

            // Save fresh embedded data with fingerprint
            data._structureFingerprint = embeddedFingerprint;
            autoSave();
        } else {
            // Cache matches current structure — safe to restore user edits on cadrage/notes
            // IMPORTANT: Always keep embedded modules and moduleSpecs as structural source of truth
            // Only merge cadrage user-editable fields and notes
            if (parsed.cadrage) {
                // Merge cadrage context (user may have edited text fields)
                if (parsed.cadrage.context) {
                    data.cadrage.context = { ...data.cadrage.context, ...parsed.cadrage.context };
                }
                // Merge scope only if user added items interactively
                if (parsed.cadrage.scope) {
                    data.cadrage.scope = { ...data.cadrage.scope, ...parsed.cadrage.scope };
                }
                // Merge stakeholders if user edited them
                if (parsed.cadrage.stakeholders) data.cadrage.stakeholders = parsed.cadrage.stakeholders;
            }
            data.dependencies = parsed.dependencies || data.dependencies;
            data.consolidation = { ...data.consolidation, ...(parsed.consolidation || {}) };

            // Merge moduleSpecs: keep embedded structure, overlay user-editable fields (notes, custom permissions)
            for (const code of Object.keys(data.moduleSpecs)) {
                const cached = parsed.moduleSpecs?.[code];
                if (cached) {
                    // Preserve user notes
                    if (cached.notes) data.moduleSpecs[code].notes = cached.notes;
                    // Preserve user-added use cases/rules/entities (merged with embedded)
                    // Only add items that don't exist in embedded (by name match)
                    const embeddedUcNames = new Set((data.moduleSpecs[code].useCases || []).map(uc => uc.name));
                    (cached.useCases || []).forEach(uc => {
                        if (!embeddedUcNames.has(uc.name)) data.moduleSpecs[code].useCases.push(uc);
                    });
                    const embeddedBrNames = new Set((data.moduleSpecs[code].businessRules || []).map(br => br.name));
                    (cached.businessRules || []).forEach(br => {
                        if (!embeddedBrNames.has(br.name)) data.moduleSpecs[code].businessRules.push(br);
                    });
                    // Preserve user permissions edits
                    if (cached.permissions) data.moduleSpecs[code].permissions = cached.permissions;
                }
            }

            data.wireframeComments = parsed.wireframeComments || {};
            data.specComments = parsed.specComments || {};
            data.customRoles = parsed.customRoles || [];
            data.customActions = parsed.customActions || [];
            data.comments = parsed.comments || [];

            // Update fingerprint
            data._structureFingerprint = embeddedFingerprint;
            autoSave();
        }

        // Restore editable fields
        document.querySelectorAll('.editable[data-field]').forEach(el => {
            const value = getNestedValue(data, 'cadrage.' + el.dataset.field);
            if (value) el.textContent = value;
        });
    } catch (e) { console.error('Error loading saved data:', e); }
}


/* --- 09-export.js --- */
/* ============================================
   EXPORT JSON
   ============================================ */
function collectEditableFields() {
    document.querySelectorAll('.editable[data-field]').forEach(el => {
        setNestedValue(data, 'cadrage.' + el.dataset.field, el.textContent.trim());
    });
    document.querySelectorAll('.editable[data-module-field]').forEach(el => {
        const code = el.dataset.moduleCode;
        const field = el.dataset.moduleField;
        if (data.moduleSpecs[code]) {
            data.moduleSpecs[code][field] = el.textContent.trim();
        }
    });
}

function buildModuleSpecsExport() {
    var result = {};
    data.modules.forEach(function(m) {
        var spec = data.moduleSpecs[m.code] || {};
        result[m.code] = {
            module: m,
            useCases: (spec.useCases || []).map(function(uc, i) {
                return Object.assign({ id: 'UC-' + String(i + 1).padStart(3, '0') }, uc);
            }),
            businessRules: (spec.businessRules || []).map(function(br, i) {
                return Object.assign({ id: 'BR-' + (br.category || 'GEN').toUpperCase().substring(0, 4) + '-' + String(i + 1).padStart(3, '0') }, br);
            }),
            entities: spec.entities || [],
            permissions: spec.permissions || [],
            notes: spec.notes || ''
        };
    });
    return result;
}

function exportJSON() {
    collectEditableFields();
    data.metadata.lastModified = new Date().toISOString();
    data.metadata.exportedAt = new Date().toISOString();

    const exportData = {
        metadata: data.metadata,
        cadrage: data.cadrage,
        modules: data.modules,
        dependencies: data.dependencies,
        moduleSpecifications: buildModuleSpecsExport(),
        consolidation: data.consolidation,
        artifacts: EMBEDDED_ARTIFACTS,
        wireframeComments: data.wireframeComments,
        specComments: data.specComments,
        customRoles: data.customRoles,
        customActions: data.customActions,
        comments: data.comments
    };

    const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = (data.metadata.applicationId || 'analyse') + '-export.json';
    a.click();
    URL.revokeObjectURL(url);
    showNotification('Export JSON téléchargé');
}

/* ============================================
   SAVE REVIEW JSON (corrections for new version)
   ============================================ */
function detectChanges(original, current) {
    const changes = { cadrage: false, modulesAdded: [], modulesRemoved: [], modulesModified: [], commentsCount: 0 };

    // Cadrage changes
    if (JSON.stringify(original.cadrage) !== JSON.stringify(current.cadrage)) {
        changes.cadrage = true;
    }

    // Module changes
    const origCodes = (original.modules || []).map(m => m.code);
    const currCodes = (current.modules || []).map(m => m.code);
    changes.modulesAdded = currCodes.filter(c => !origCodes.includes(c));
    changes.modulesRemoved = origCodes.filter(c => !currCodes.includes(c));
    currCodes.filter(c => origCodes.includes(c)).forEach(code => {
        const origSpec = JSON.stringify(original.moduleSpecs?.[code] || {});
        const currSpec = JSON.stringify(current.moduleSpecs?.[code] || {});
        if (origSpec !== currSpec) changes.modulesModified.push(code);
    });

    // Comments count
    changes.commentsCount = (current.comments || []).length;

    return changes;
}

function saveReviewJSON() {
    collectEditableFields();

    const changes = detectChanges(ORIGINAL_DATA, data);
    const hasChanges = changes.cadrage || changes.modulesAdded.length > 0
        || changes.modulesRemoved.length > 0 || changes.modulesModified.length > 0
        || changes.commentsCount > 0;

    const reviewData = {
        _reviewMeta: {
            sourceVersion: data.metadata.version || '1.0',
            sourceApplicationId: data.metadata.applicationId || '',
            exportedAt: new Date().toISOString(),
            hasChanges: hasChanges,
            changeSummary: {
                cadrageModified: changes.cadrage,
                modulesAdded: changes.modulesAdded,
                modulesRemoved: changes.modulesRemoved,
                modulesModified: changes.modulesModified,
                commentsCount: changes.commentsCount
            }
        },
        metadata: data.metadata,
        cadrage: data.cadrage,
        modules: data.modules,
        dependencies: data.dependencies,
        moduleSpecifications: buildModuleSpecsExport(),
        consolidation: data.consolidation,
        wireframeComments: data.wireframeComments,
        specComments: data.specComments,
        customRoles: data.customRoles,
        customActions: data.customActions,
        comments: data.comments
    };

    const blob = new Blob([JSON.stringify(reviewData, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'ba-review.json';
    a.click();
    URL.revokeObjectURL(url);
    showNotification('ba-review.json téléchargé — sauvegardez-le à côté du HTML');
}


/* --- 10-comments.js --- */
/* ============================================
   INLINE COMMENTS SYSTEM
   ============================================ */

/**
 * Comments are stored in data.comments[] with structure:
 * { id, sectionId, elementId, author, timestamp, content, status, category }
 *
 * - sectionId: matches the section div id (e.g. "cadrage-context", "module-spec-Clients")
 * - elementId: stable identifier for the element (name, role, or generated id)
 * - cardIndex: (deprecated, kept for backward compat) positional index
 * - status: "to-review" | "validated"
 * - category: "clarification" | "correction" | "suggestion"
 */

function getElementId(item, sectionId, index) {
    // Extract a stable ID from the element's data
    var title = item.querySelector('.uc-title, .entity-name, .stakeholder-role, .card-title');
    if (title) return title.textContent.trim();
    var nameEl = item.querySelector('[data-field]');
    if (nameEl) return nameEl.dataset.field;
    return sectionId + '-' + index;
}

function initInlineComments() {
    // Cadrage sections: direct card children
    document.querySelectorAll('.section > .card, .section > .stakeholder-card, .section > .uc-item').forEach(function(card) {
        if (card.dataset.commentInitialized) return;
        card.dataset.commentInitialized = 'true';
        var section = card.closest('.section');
        var sectionId = section ? section.id : 'unknown';
        var siblings = Array.from(section.querySelectorAll(':scope > .card, :scope > .stakeholder-card, :scope > .uc-item'));
        var index = siblings.indexOf(card);
        var elementId = getElementId(card, sectionId, index);
        card.appendChild(createCommentUI(sectionId, elementId));
    });

    // Module spec lists: nested items in ucList, brList, entList containers
    document.querySelectorAll('[id^="ucList-"] > .uc-item, [id^="brList-"] > div, [id^="entList-"] > .entity-block').forEach(function(item) {
        if (item.dataset.commentInitialized) return;
        item.dataset.commentInitialized = 'true';
        var list = item.parentElement;
        var listId = list.id;
        var siblings = Array.from(list.children);
        var index = siblings.indexOf(item);
        var elementId = getElementId(item, listId, index);
        item.appendChild(createCommentUI(listId, elementId));
    });

    // Stakeholder cards in grid
    document.querySelectorAll('.stakeholder-grid > .stakeholder-card').forEach(function(card) {
        if (card.dataset.commentInitialized) return;
        card.dataset.commentInitialized = 'true';
        var grid = card.parentElement;
        var section = card.closest('.section');
        var sectionId = section ? section.id : 'stakeholders';
        var siblings = Array.from(grid.children);
        var index = siblings.indexOf(card);
        var elementId = getElementId(card, sectionId, index);
        card.appendChild(createCommentUI(sectionId, elementId));
    });

    // Scope items
    ['scopeInScope', 'scopeOutOfScope'].forEach(function(containerId) {
        var container = document.getElementById(containerId);
        if (!container) return;
        container.querySelectorAll('.uc-item').forEach(function(item, index) {
            if (item.dataset.commentInitialized) return;
            item.dataset.commentInitialized = 'true';
            var elementId = getElementId(item, containerId, index);
            item.appendChild(createCommentUI(containerId, elementId));
        });
    });
}

function createCommentUI(sectionId, elementId) {
    const comments = getCommentsForCard(sectionId, elementId);
    const count = comments.length;
    const safeElId = String(elementId).replace(/[^a-zA-Z0-9_-]/g, '_');
    const threadId = 'comment-thread-' + sectionId + '-' + safeElId;

    const container = document.createElement('div');
    container.className = 'comment-btn-container';
    container.dataset.sectionId = sectionId;
    container.dataset.elementId = elementId;

    container.innerHTML = `
        <button class="comment-toggle-btn" onclick="toggleCommentThread('${sectionId}', '${safeElId}')">
            Commentaires <span class="comment-count ${count === 0 ? 'empty' : ''}">${count}</span>
        </button>
        <div class="comment-thread" id="${threadId}">
            <div class="comment-items" id="comment-items-${sectionId}-${safeElId}">
                ${renderCommentItems(sectionId, elementId)}
            </div>
            <div class="comment-add-form">
                <textarea id="comment-text-${sectionId}-${safeElId}" placeholder="Ajouter un commentaire..."></textarea>
                <select id="comment-cat-${sectionId}-${safeElId}">
                    <option value="clarification">Clarification</option>
                    <option value="correction">Correction</option>
                    <option value="suggestion">Suggestion</option>
                </select>
                <button onclick="addInlineComment('${sectionId}', '${elementId.replace(/'/g, "\\'")}')">Ajouter</button>
            </div>
        </div>
    `;

    return container;
}

function getCommentsForCard(sectionId, elementId) {
    return (data.comments || []).filter(function(c) {
        if (c.elementId) return c.sectionId === sectionId && c.elementId === elementId;
        // Backward compat: match by cardIndex if elementId not set
        return c.sectionId === sectionId && c.cardIndex === elementId;
    });
}

function toggleCommentThread(sectionId, safeElId) {
    const thread = document.getElementById('comment-thread-' + sectionId + '-' + safeElId);
    if (thread) thread.classList.toggle('visible');
}

function renderCommentItems(sectionId, elementId) {
    const comments = getCommentsForCard(sectionId, elementId);
    if (comments.length === 0) {
        return '<div style="font-size:0.8rem;color:var(--text-muted);padding:0.5rem 0;font-style:italic;">Aucun commentaire</div>';
    }

    return comments.map(function(c, i) {
        const initials = escapeHtml((c.author || 'U').substring(0, 2).toUpperCase());
        const date = c.timestamp ? new Date(c.timestamp).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : '';
        const globalIndex = data.comments.indexOf(c);

        return `
            <div class="comment-item">
                <div class="comment-avatar">${initials}</div>
                <div class="comment-body">
                    <div class="comment-meta">
                        <span class="comment-author">${escapeHtml(c.author || 'Utilisateur')}</span>
                        <span class="comment-date">${escapeHtml(date)}</span>
                        <span class="comment-category comment-category-${escapeHtml(c.category)}">${escapeHtml(c.category)}</span>
                        <span class="comment-status comment-status-${c.status}">${c.status === 'validated' ? 'Validé' : 'À revoir'}</span>
                    </div>
                    <div class="comment-text">${escapeHtml(c.content)}</div>
                    <div class="comment-actions">
                        <button class="comment-action-btn" onclick="toggleCommentStatus(${globalIndex})">${c.status === 'validated' ? 'Remettre à revoir' : 'Valider'}</button>
                        <button class="comment-action-btn" onclick="deleteComment(${globalIndex})" style="color:var(--error);">Supprimer</button>
                    </div>
                </div>
            </div>
        `;
    }).join('');
}

function addInlineComment(sectionId, elementId) {
    var safeElId = String(elementId).replace(/[^a-zA-Z0-9_-]/g, '_');
    const textEl = document.getElementById('comment-text-' + sectionId + '-' + safeElId);
    const catEl = document.getElementById('comment-cat-' + sectionId + '-' + safeElId);
    const content = textEl.value.trim();
    if (!content) return;

    const comment = {
        id: 'comment-' + Date.now(),
        sectionId: sectionId,
        elementId: elementId,
        author: 'Utilisateur',
        timestamp: new Date().toISOString(),
        content: content,
        status: 'to-review',
        category: catEl.value
    };

    data.comments.push(comment);
    textEl.value = '';

    refreshCommentUI(sectionId, elementId);
    renderReviewPanel();
    autoSave();
}

function toggleCommentStatus(globalIndex) {
    const comment = data.comments[globalIndex];
    if (!comment) return;
    comment.status = comment.status === 'validated' ? 'to-review' : 'validated';
    var elId = comment.elementId || comment.cardIndex;
    refreshCommentUI(comment.sectionId, elId);
    renderReviewPanel();
    autoSave();
}

function deleteComment(globalIndex) {
    if (!confirm('Supprimer ce commentaire ?')) return;
    const comment = data.comments[globalIndex];
    if (!comment) return;
    var sectionId = comment.sectionId;
    var elId = comment.elementId || comment.cardIndex;
    data.comments.splice(globalIndex, 1);
    refreshCommentUI(sectionId, elId);
    renderReviewPanel();
    autoSave();
}

function refreshCommentUI(sectionId, elementId) {
    var safeElId = String(elementId).replace(/[^a-zA-Z0-9_-]/g, '_');
    // Update comment items
    const itemsContainer = document.getElementById('comment-items-' + sectionId + '-' + safeElId);
    if (itemsContainer) {
        itemsContainer.innerHTML = renderCommentItems(sectionId, elementId);
    }

    // Update count badge
    const count = getCommentsForCard(sectionId, elementId).length;
    const container = document.querySelector('.comment-btn-container[data-section-id="' + sectionId + '"][data-element-id="' + elementId + '"]');
    if (container) {
        const badge = container.querySelector('.comment-count');
        if (badge) {
            badge.textContent = count;
            badge.className = 'comment-count' + (count === 0 ? ' empty' : '');
        }
    }
}


/* --- 11-review-panel.js --- */
/* ============================================
   REVIEW PANEL
   ============================================ */
let reviewPanelOpen = false;
let reviewFilter = 'all';

function toggleReviewPanel() {
    reviewPanelOpen = !reviewPanelOpen;
    const panel = document.getElementById('reviewPanel');
    const body = document.getElementById('appBody');
    const btn = document.getElementById('reviewToggleBtn');

    if (reviewPanelOpen) {
        panel.classList.add('visible');
        body.classList.add('review-open');
        btn.classList.add('active');
    } else {
        panel.classList.remove('visible');
        body.classList.remove('review-open');
        btn.classList.remove('active');
    }

    renderReviewPanel();
}

function filterReviewComments(filter) {
    reviewFilter = filter;
    // Update active filter button
    document.querySelectorAll('.review-filter-btn').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.filter === filter);
    });
    renderReviewPanel();
}

function renderReviewPanel() {
    const comments = data.comments || [];

    // Update header badge
    const toReviewCount = comments.filter(c => c.status === 'to-review').length;
    const badge = document.getElementById('reviewBadge');
    if (badge) {
        badge.textContent = toReviewCount;
        badge.classList.toggle('hidden', toReviewCount === 0);
    }

    // Update stats
    const totalEl = document.getElementById('reviewStatTotal');
    const toReviewEl = document.getElementById('reviewStatToReview');
    const validatedEl = document.getElementById('reviewStatValidated');
    if (totalEl) totalEl.textContent = comments.length;
    if (toReviewEl) toReviewEl.textContent = toReviewCount;
    if (validatedEl) validatedEl.textContent = comments.filter(c => c.status === 'validated').length;

    // Filter comments
    let filtered = comments;
    if (reviewFilter === 'to-review') {
        filtered = comments.filter(c => c.status === 'to-review');
    } else if (reviewFilter === 'validated') {
        filtered = comments.filter(c => c.status === 'validated');
    }

    // Render comment list
    const container = document.getElementById('reviewCommentsList');
    if (!container) return;

    if (filtered.length === 0) {
        container.innerHTML = '<div class="review-empty">Aucun commentaire' +
            (reviewFilter !== 'all' ? ' avec ce filtre' : '') + '.</div>';
        return;
    }

    container.innerHTML = filtered.map(function(c, i) {
        const globalIndex = data.comments.indexOf(c);
        const sectionLabel = getSectionLabel(c.sectionId);
        const date = c.timestamp ? new Date(c.timestamp).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' }) : '';
        var elId = c.elementId || c.cardIndex;
        var safeElId = String(elId).replace(/[^a-zA-Z0-9_-]/g, '_');

        return `
            <div class="review-comment-item" onclick="navigateToComment('${c.sectionId}', '${safeElId}')">
                <div class="review-comment-section">${escapeHtml(sectionLabel)}</div>
                <div class="review-comment-text">${escapeHtml(c.content)}</div>
                <div class="review-comment-footer">
                    <span class="review-comment-author">${escapeHtml(c.author || 'Utilisateur')} - ${escapeHtml(date)}</span>
                    <div class="review-comment-actions">
                        <button class="review-action-btn ${c.status === 'validated' ? 'reject' : 'validate'}"
                            onclick="event.stopPropagation();toggleCommentStatus(${globalIndex})"
                            title="${c.status === 'validated' ? 'Remettre à revoir' : 'Valider'}">
                            ${c.status === 'validated' ? 'À revoir' : 'Valider'}
                        </button>
                        <button class="review-action-btn delete"
                            onclick="event.stopPropagation();deleteComment(${globalIndex})"
                            title="Supprimer">
                            &#10005;
                        </button>
                    </div>
                </div>
            </div>
        `;
    }).join('');
}

function getSectionLabel(sectionId) {
    const labels = {
        'cadrage-context': 'Contexte',
        'cadrage-stakeholders': 'Parties prenantes',
        'cadrage-scope': 'Périmètre',
        'cadrage-success': 'Critères',
        'decomp-modules': 'Domaines',
        'decomp-dependencies': 'Dépendances',
        'consol-interactions': 'Interactions',
        'consol-permissions': 'Accès',
        'consol-flows': 'Parcours',
        'handoff-summary': 'Synthèse'
    };
    if (labels[sectionId]) return labels[sectionId];
    if (sectionId.startsWith('module-spec-')) {
        const code = sectionId.replace('module-spec-', '');
        const mod = data.modules.find(m => m.code === code);
        return mod ? mod.name : code;
    }
    // Handle module structure sections (module-struct-{code}-{section})
    const structMatch = sectionId.match(/^module-struct-(.+?)-(.+)$/);
    if (structMatch) {
        const mod = data.modules.find(m => m.code === structMatch[1]);
        const modName = mod ? mod.name : structMatch[1];
        return modName + ' > Structure > ' + structMatch[2];
    }
    // Handle list-based sectionIds (ucList-*, brList-*, entList-*)
    const listMatch = sectionId.match(/^(uc|br|ent)List-(.+)$/);
    if (listMatch) {
        const tabLabels = { uc: 'Cas d\'utilisation', br: 'Règles métier', ent: 'Données' };
        const mod = data.modules.find(m => m.code === listMatch[2]);
        const modName = mod ? mod.name : listMatch[2];
        return modName + ' > ' + (tabLabels[listMatch[1]] || listMatch[1]);
    }
    return sectionId;
}

function navigateToComment(sectionId, safeElId) {
    // Handle list-based sectionIds (ucList-*, brList-*, entList-*) → navigate to module + tab
    const listMatch = sectionId.match(/^(uc|br|ent)List-(.+)$/);
    if (listMatch) {
        const [, tabType, moduleCode] = listMatch;
        showSection('module-spec-' + moduleCode);
        setTimeout(function() {
            switchTab(moduleCode, tabType);
            scrollToCommentThread(sectionId, safeElId);
        }, 150);
    } else {
        showSection(sectionId);
        scrollToCommentThread(sectionId, safeElId);
    }
}

function scrollToCommentThread(sectionId, safeElId) {
    setTimeout(function() {
        const thread = document.getElementById('comment-thread-' + sectionId + '-' + safeElId);
        if (thread && !thread.classList.contains('visible')) {
            thread.classList.add('visible');
        }
        const container = document.querySelector('.comment-btn-container[data-section-id="' + sectionId + '"][data-element-id]');
        if (container) {
            container.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
    }, 100);
}


/* --- 12-render-diagrams.js --- */
/* ==========================================
   MERMAID DIAGRAM RENDERING
   Renders ERD, state machines, and sequence diagrams
   from consolidation.mermaidDiagrams data.
   ========================================== */

function renderMermaidDiagrams() {
    const data = window.FEATURE_DATA;
    if (!data) return;

    const diagrams = data.consolidation?.mermaidDiagrams;
    if (!diagrams) return;

    // 1. ERD in consol-datamodel (prepend before entity cards)
    if (diagrams.erd) {
        const erdContainer = document.getElementById('dataModelContainer');
        if (erdContainer) {
            const erdDiv = document.createElement('div');
            erdDiv.className = 'diagram-container diagram-erd';
            erdDiv.innerHTML =
                '<div class="diagram-section-header">Diagramme Entit\u00e9-Relation (ERD)</div>' +
                '<div class="mermaid">' + escapeHtml(diagrams.erd) + '</div>';
            erdContainer.insertBefore(erdDiv, erdContainer.firstChild);
        }
    }

    // 1b. MCD (Modèle Conceptuel de Données) — after ERD
    if (diagrams.mcd) {
        var erdContainer = document.getElementById('dataModelContainer');
        if (erdContainer) {
            var mcdDiv = document.createElement('div');
            mcdDiv.className = 'diagram-container diagram-mcd';
            mcdDiv.innerHTML =
                '<div class="diagram-section-header" style="font-size:0.95rem;font-weight:600;color:var(--text-bright);margin-bottom:0.75rem;">Mod\u00e8le Conceptuel de Donn\u00e9es (MCD)</div>' +
                '<div class="mermaid">' + escapeHtml(diagrams.mcd) + '</div>';
            var erdDiv = erdContainer.querySelector('.diagram-erd');
            if (erdDiv && erdDiv.nextSibling) {
                erdContainer.insertBefore(mcdDiv, erdDiv.nextSibling);
            } else {
                erdContainer.appendChild(mcdDiv);
            }
        }
    }

    // 2. State machine diagrams — inject in module spec sections or consol-datamodel
    if (diagrams.stateMachines && Object.keys(diagrams.stateMachines).length > 0) {
        const smContainer = document.getElementById('dataModelContainer');
        if (smContainer) {
            const smSection = document.createElement('div');
            smSection.innerHTML = '<div class="diagram-section-header">Cycles de vie (State Machines)</div>';

            Object.entries(diagrams.stateMachines).forEach(function(entry) {
                var entity = entry[0];
                var def = entry[1];
                var smDiv = document.createElement('div');
                smDiv.className = 'diagram-container diagram-state-machine';
                smDiv.innerHTML =
                    '<h4>' + escapeHtml(entity) + '</h4>' +
                    '<div class="mermaid">' + escapeHtml(def) + '</div>';
                smSection.appendChild(smDiv);
            });

            smContainer.appendChild(smSection);
        }
    }

    // 2b. Use Case diagrams — inject in each module's UC tab
    if (diagrams.useCases && Object.keys(diagrams.useCases).length > 0) {
        Object.entries(diagrams.useCases).forEach(function(entry) {
            var moduleCode = entry[0];
            var def = entry[1];
            var ucTab = document.getElementById('tab-' + moduleCode + '-uc');
            if (!ucTab) {
                // Try kebab-case version
                var kebab = moduleCode.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
                ucTab = document.getElementById('tab-' + kebab + '-uc');
            }
            if (ucTab) {
                var ucDiagramDiv = document.createElement('div');
                ucDiagramDiv.className = 'diagram-container diagram-usecase';
                ucDiagramDiv.innerHTML =
                    '<div class="diagram-section-header" style="font-size:0.95rem;font-weight:600;color:var(--text-bright);margin-bottom:0.75rem;">Diagramme de cas d\'utilisation</div>' +
                    '<div class="mermaid">' + escapeHtml(def) + '</div>';
                // Insert after the first paragraph (description text)
                var firstP = ucTab.querySelector('p');
                if (firstP && firstP.nextSibling) {
                    ucTab.insertBefore(ucDiagramDiv, firstP.nextSibling);
                } else {
                    ucTab.insertBefore(ucDiagramDiv, ucTab.firstChild);
                }
            }
        });
    }

    // 3. Sequence diagrams in consol-flows
    if (diagrams.sequences && Object.keys(diagrams.sequences).length > 0) {
        var flowsContainer = document.getElementById('consolFlowsContainer');
        // Fallback: try the consol-flows section
        if (!flowsContainer) {
            var consolFlows = document.getElementById('consol-flows');
            if (consolFlows) {
                flowsContainer = consolFlows.querySelector('.section-body') || consolFlows;
            }
        }

        if (flowsContainer) {
            var seqSection = document.createElement('div');
            seqSection.innerHTML = '<div class="diagram-section-header">Diagrammes de s\u00e9quence</div>';

            Object.entries(diagrams.sequences).forEach(function(entry) {
                var flowName = entry[0];
                var def = entry[1];
                var seqDiv = document.createElement('div');
                seqDiv.className = 'diagram-container diagram-sequence';
                seqDiv.innerHTML =
                    '<h4>' + escapeHtml(flowName) + '</h4>' +
                    '<div class="mermaid">' + escapeHtml(def) + '</div>';
                seqSection.appendChild(seqDiv);
            });

            flowsContainer.appendChild(seqSection);
        }
    }

    // 4. Render all mermaid elements
    try {
        if (typeof mermaid !== 'undefined' && mermaid.run) {
            mermaid.run({ querySelector: '.mermaid' });
        }
    } catch (e) {
        console.warn('Mermaid rendering failed:', e);
        // Fallback: show raw text
        document.querySelectorAll('.mermaid').forEach(function(el) {
            if (!el.querySelector('svg')) {
                el.style.whiteSpace = 'pre-wrap';
                el.style.fontFamily = 'monospace';
                el.style.fontSize = '0.85rem';
                el.style.color = 'var(--text-muted)';
            }
        });
    }
}

// Escape HTML for safe injection
function escapeHtml(text) {
    if (!text) return '';
    // For mermaid content, we need to preserve the syntax
    // Only escape actual HTML tags, not mermaid arrows
    return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

// Auto-run after consolidation rendering
(function() {
    // Wait for DOM and other render functions to complete
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            setTimeout(renderMermaidDiagrams, 500);
        });
    } else {
        setTimeout(renderMermaidDiagrams, 500);
    }
})();

    </script>
</body>
</html>
