=== CAI FACILE PROJECT BACKUP ===

=== pubspec.yaml ===
name: cid_app
description: "Applicazione per la compilazione assistita del modulo CAI/CID digitale."
publish_to: 'none'

version: 1.0.5+3

environment:
  sdk: '>=3.10.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter

  # --- MOTORE PDF E STAMPA ---
  syncfusion_flutter_core: ^32.2.3
  syncfusion_flutter_pdf: ^32.2.3
  pdf: ^3.10.7
  printing: ^5.14.2

  path_provider: ^2.1.5
  share_plus: ^7.2.1

  # Per aprire il PDF appena generato
  open_file: ^3.3.2

  # --- FIREBASE E SICUREZZA ---
  firebase_core: ^3.10.1
  cloud_firestore: ^5.6.2
  firebase_database: ^11.3.0
  firebase_auth: ^5.7.0
  encrypt: ^5.0.3

  # --- RETE E SERVIZI ---
  http: ^1.1.0
  webview_flutter: ^4.4.0
  flutter_inappwebview: ^6.0.0
  intl: ^0.20.2
  url_launcher: ^6.3.2
  flutter_email_sender: ^6.0.3

  # --- GEOLOCALIZZAZIONE ---
  geolocator: ^14.0.2
  geocoding: ^4.0.0

  # --- QR CODE E SCANSIONE ---
  qr_flutter: ^4.1.0
  mobile_scanner: ^6.0.0

  # --- CAMERA E OCR ---
  camera: ^0.11.0
  google_mlkit_text_recognition: ^0.14.0
  google_mlkit_barcode_scanning: ^0.13.0
  google_mlkit_commons: ^0.9.0
  permission_handler: ^11.3.1

  # --- GRAFICA E INPUT ---
  image: ^4.2.0
  signature: ^6.3.0
  html: ^0.15.4

  # LIBRERIE SYNCFUSION
  syncfusion_flutter_pdfviewer: ^32.2.3
  syncfusion_flutter_signaturepad: ^32.2.3

  device_info_plus: ^12.3.0
  flutter_localizations:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0
  flutter_launcher_icons: ^0.13.1

flutter:
  uses-material-design: true

  assets:
    - assets/CAI_p1.pdf
    - assets/punti_danni_A.png
    - assets/punti_danni_B.png
    - assets/ospedali_completo.json
    - assets/sfondo_mappa.jpg
    - assets/fonts/Roboto-Bold.ttf
    - assets/sfondo_cid.jpg
    - assets/icona.png

  fonts:
    - family: Roboto
      fonts:
        - asset: assets/fonts/Roboto-Bold.ttf
          weight: 700

flutter_launcher_icons:
  android: "launcher_icon"
  ios: true
  image_path: "assets/icona.png"
  remove_alpha_ios: true
=== MAC OS CONFIG: Info.plist ===
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIconFile</key>
	<string></string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>$(FLUTTER_BUILD_NAME)</string>
	<key>CFBundleVersion</key>
	<string>$(FLUTTER_BUILD_NUMBER)</string>
	<key>LSMinimumSystemVersion</key>
	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
	<key>NSHumanReadableCopyright</key>
	<string>$(PRODUCT_COPYRIGHT)</string>
	<key>NSMainNibFile</key>
	<string>MainMenu</string>
	<key>NSPrincipalClass</key>
	<string>NSApplication</string>
</dict>
</plist>

=== MAC OS CONFIG: Entitlements ===
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.cs.allow-jit</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
</dict>
</plist>

=== MAC OS CONFIG: Podfile ===
platform :osx, '10.15'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_macos_podfile_setup

target 'Runner' do
  use_frameworks!

  flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_macos_build_settings(target)
  end
end

=== IOS CONFIG: Info.plist ===
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CADisableMinimumFrameDurationOnPhone</key>
	<true/>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>CAI App</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>cid_app</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>$(FLUTTER_BUILD_NAME)</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>$(FLUTTER_BUILD_NUMBER)</string>
	<key>ITSAppUsesNonExemptEncryption</key>
	<false/>
	<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>mailto</string>
	</array>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>LSSupportsOpeningDocumentsInPlace</key>
	<true/>
	<key>NSCameraUsageDescription</key>
	<string>La fotocamera è necessaria per scansionare il QR Code e importare i dati del sinistro.</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>La tua posizione serve per compilare automaticamente il luogo dell'incidente nel modulo.</string>
	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>La tua posizione serve per compilare il luogo dell'incidente anche se l'app è in background.</string>
	<key>NSPhotoLibraryAddUsageDescription</key>
	<string>Serve per salvare il modulo PDF o i disegni dei danni nel rullino.</string>
	<key>NSPhotoLibraryUsageDescription</key>
	<string>Serve per allegare le foto dei danni al veicolo.</string>
	<key>UIApplicationSupportsIndirectInputEvents</key>
	<true/>
	<key>UIFileSharingEnabled</key>
	<true/>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>

=== IOS CONFIG: Podfile ===
# Uncomment this line to define a global platform for your project
 platform :ios, '15.5'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    # --- AGGIUNGI QUESTE 3 RIGHE QUI SOTTO ---
    target.build_configurations.each do |config|
      config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
    end
    # ----------------------------------------

  end
end

=== ANDROID CONFIG: AndroidManifest.xml ===
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.amastra.cid_app">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.CAMERA" />


    <queries>
        <intent>
            <action android:name="android.intent.action.DIAL" />
            <data android:scheme="tel" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="https" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="http" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="geo" />
        </intent>
        <intent>
            <action android:name="android.intent.action.SENDTO" />
            <data android:scheme="mailto" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:mimeType="application/pdf" />
        </intent>
        <intent>
            <action android:name="android.intent.action.SEND" />
            <data android:mimeType="*/*" />
        </intent>
    </queries>

    <application
        android:label="CAI Facile"
        android:name="${applicationName}"
        android:icon="@mipmap/launcher_icon"
        android:requestLegacyExternalStorage="true"
        android:usesCleartextTraffic="true">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="io.flutter.embedding.android.NormalTheme"
                android:resource="@style/NormalTheme" />

            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    </application>
</manifest>
=== ANDROID CONFIG: build.gradle ===
plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

// 1. CARICAMENTO PASSWORD KEYSTORE (NUOVO)
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

// --- FIX PER LE DIPENDENZE TROPPO RECENTI ---
configurations.all {
    resolutionStrategy {
        force 'androidx.browser:browser:1.8.0'
        force 'androidx.core:core:1.13.1'
        force 'androidx.core:core-ktx:1.13.1'
    }
}

android {
    namespace "com.amastra.cid_app"
    compileSdk 36
    ndkVersion "27.0.12077973"

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = '17'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        applicationId "com.amastra.cid_app"
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion 35
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        multiDexEnabled true
    }

    // 2. CONFIGURAZIONE FIRMA (NUOVO)
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }

    buildTypes {
        release {
            // 3. USA LA FIRMA DI RILASCIO (CORRETTO)
            signingConfig signingConfigs.release
            minifyEnabled false
            shrinkResources false
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0"
    implementation 'androidx.multidex:multidex:2.0.1'
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        jvmTarget = "17"
    }
}
=== ANDROID CONFIG: build.gradle.kts ===

=== SOURCE CODE ===

=== FILE: lib/comp_1-5.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:geolocator/geolocator.dart';
import 'package:geocoding/geocoding.dart';
import 'comp_6-7.dart';
import 'global_data.dart';

// Formattatore per inserire automaticamente gli slash nella data
class DateInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var text = newValue.text.replaceAll('/', '');
    if (text.length > 8) text = text.substring(0, 8);
    var result = "";
    for (int i = 0; i < text.length; i++) {
      if (i == 2 || i == 4) result += "/";
      result += text[i];
    }
    return newValue.copyWith(text: result, selection: TextSelection.collapsed(offset: result.length));
  }
}

class Comp1_5Screen extends StatefulWidget {
  const Comp1_5Screen({super.key});

  @override
  _Comp1_5ScreenState createState() => _Comp1_5ScreenState();
}

class _Comp1_5ScreenState extends State<Comp1_5Screen> {
  late TextEditingController _data, _ora, _luogo, _testimoni;
  late bool _feriti, _danniVeicoli, _danniCose;

  final bool isB = GlobalData.latoCorrente == 'B';

  bool _isReady = false;     // Per l'orientamento
  bool _gpsLoading = false;  // Per mostrare lo spinner

  @override
  void initState() {
    super.initState();
    _forzaVerticaleEInizializza();
  }

  Future<void> _forzaVerticaleEInizializza() async {
    await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    await Future.delayed(const Duration(milliseconds: 150));

    _initControllers();

    if (mounted) {
      setState(() => _isReady = true);

      // MOSTRA IL POPUP INFORMATIVO APPENA LA SCHERMATA È CARICATA
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _mostraInfoPopup(context);
      });

      // Se il luogo è vuoto, provo il GPS automatico in background
      if (_luogo.text.isEmpty) {
        _trovaPosizione(silenzioso: true);
      }
    }
  }

  void _initControllers() {
    _data = TextEditingController(text: GlobalData.data_incidente);
    if (_data.text.isEmpty) {
      _data.text = DateFormat('dd/MM/yyyy').format(DateTime.now());
    }

    _ora = TextEditingController(text: GlobalData.ora);
    if (_ora.text.isEmpty) {
      _ora.text = DateFormat('HH:mm').format(DateTime.now());
    }

    _luogo = TextEditingController(text: GlobalData.luogo);
    _testimoni = TextEditingController(text: GlobalData.testimoni);

    _feriti = GlobalData.feriti;
    _danniVeicoli = GlobalData.Veicoli_danni_materiali_oltre;
    _danniCose = GlobalData.Oggetti_diversi_danni_materiali;
  }

  // --- POPUP INFORMATIVO ---
  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false, // Obbliga l'utente a premere "Ho capito"
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5), // Sfondo scuro
      transitionDuration: const Duration(milliseconds: 400), // Durata della dissolvenza (300 millisecondi)
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.info_outline, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Dati Generali", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text("In questa prima pagina dovrai inserire i dati condivisi dell'incidente (Sezioni 1-5 del modulo).", style: TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.place, "Luogo", "Usa il mirino GPS per trovare automaticamente l'indirizzo esatto."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.local_hospital, "Feriti", "Indica se ci sono persone che hanno subito lesioni."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.people, "Testimoni", "Se qualcuno ha visto l'incidente, segna i suoi contatti (nome, cognome, telefono)."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      // QUI GESTIAMO L'ANIMAZIONE DI DISSOLVENZA
      // NUOVA ANIMAZIONE COMBINATA (FADE + ZOOM)
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOutBack, // Quando entra, fa un piccolo "rimbalzo" frenato
          reverseCurve: Curves.easeInBack, // Quando esce, "prende la rincorsa" e cade giù
        );

        var curveOpacita = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
          reverseCurve: Curves.easeIn,
        );

        return SlideTransition(
          // Muove il popup sull'asse Y (verticale)
          position: Tween<Offset>(
            begin: const Offset(0.0, 0.4), // Parte dal basso (o cade verso il basso)
            end: Offset.zero, // Centro esatto
          ).animate(curvePosizione),
          child: FadeTransition(
            opacity: curveOpacita,
            child: child,
          ),
        );
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  // --- GEOLOCALIZZAZIONE ---
  Future<void> _trovaPosizione({bool silenzioso = false}) async {
    if (!silenzioso) setState(() => _gpsLoading = true);

    try {
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          if (!silenzioso) throw Exception("Permesso negato");
          return;
        }
      }

      if (permission == LocationPermission.deniedForever) {
        if (!silenzioso) throw Exception("Permessi GPS bloccati.");
        return;
      }

      Position position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.high
      ).timeout(const Duration(seconds: 5));

      List<Placemark> placemarks = await placemarkFromCoordinates(position.latitude, position.longitude);

      if (placemarks.isNotEmpty) {
        Placemark place = placemarks[0];

        String via = place.thoroughfare ?? place.street ?? "";
        String numero = place.subThoroughfare ?? "";
        String citta = place.locality ?? place.subLocality ?? "";
        String prov = place.administrativeArea ?? "";

        String indirizzoCompleto = "$via $numero, $citta ($prov)".trim();
        if (indirizzoCompleto.startsWith(",")) indirizzoCompleto = indirizzoCompleto.substring(1).trim();

        if (indirizzoCompleto.isEmpty) {
          indirizzoCompleto = "${position.latitude}, ${position.longitude}";
        }

        if (mounted) {
          setState(() {
            _luogo.text = indirizzoCompleto.toUpperCase();
          });
        }
      }
    } catch (e) {
      if (!silenzioso && mounted) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text("Errore GPS: ${e.toString().replaceAll('Exception:', '')}"),
          backgroundColor: Colors.orange,
        ));
      }
    } finally {
      if (mounted) setState(() => _gpsLoading = false);
    }
  }

  Future<void> _selezionaData(BuildContext context) async {
    DateTime initialDate = DateTime.now();

    if (_data.text.length == 10) {
      try {
        List<String> parti = _data.text.split('/');
        initialDate = DateTime(int.parse(parti[2]), int.parse(parti[1]), int.parse(parti[0]));
      } catch (_) {}
    }

    final DateTime? picked = await showDatePicker(
      context: context,
      initialDate: initialDate,
      firstDate: DateTime(1990),
      lastDate: DateTime.now(), // Non si può fare un incidente nel futuro!
      locale: const Locale('it', 'IT'),
    );

    if (picked != null) {
      String dataFormattata = "${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}";
      setState(() {
        _data.text = dataFormattata;
      });
    }
  }

  void _salvaEProsegui() {
    if (_data.text.isEmpty || _ora.text.isEmpty || _luogo.text.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Compila data, ora e luogo!"), backgroundColor: Colors.red));
      return;
    }

    GlobalData.data_incidente = _data.text;
    GlobalData.ora = _ora.text;
    GlobalData.luogo = _luogo.text.toUpperCase();
    GlobalData.feriti = _feriti;
    GlobalData.Veicoli_danni_materiali_oltre = _danniVeicoli;
    GlobalData.Oggetti_diversi_danni_materiali = _danniCose;
    GlobalData.testimoni = _testimoni.text.toUpperCase();

    Navigator.push(context, MaterialPageRoute(builder: (context) => const Comp6_7Screen()));
  }

  @override
  Widget build(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgColor = isB ? const Color(0xFFFFF9C4) : const Color(0xFFE3F2FD);

    if (!_isReady) {
      return Scaffold(backgroundColor: bgColor, body: Container());
    }

    return Scaffold(
      backgroundColor: bgColor,
      appBar: AppBar(
        title: const Text("Sez. 1-5: Dati Generali"),
        backgroundColor: activeColor,
        foregroundColor: Colors.white,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // CARD 1: DATA E ORA
            _buildCard(
              titolo: "1. DATA E ORA",
              accentColor: activeColor,
              child: Row(children: [
                Expanded(
                  child: _buildField(_data, "Data (GG/MM/AAAA)", Icons.calendar_today, activeColor,
                    isDate: true,
                    customPrefix: InkWell(
                      onTap: () => _selezionaData(context),
                      borderRadius: BorderRadius.circular(20),
                      child: Container(
                        width: 38,
                        alignment: Alignment.center,
                        child: Icon(Icons.calendar_today, size: 20, color: activeColor),
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 15),
                Expanded(child: _buildField(_ora, "Ora (HH:MM)", Icons.access_time, activeColor)),
              ]),
            ),

            // CARD 2: LUOGO
            _buildCard(
              titolo: "2. LUOGO",
              accentColor: activeColor,
              child: Row(children: [
                Expanded(child: _buildField(_luogo, "Indirizzo / Luogo", Icons.map, activeColor, maxLines: 2)),
                _gpsLoading
                    ? const Padding(padding: EdgeInsets.all(12), child: SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2)))
                    : IconButton(
                  icon: const Icon(Icons.my_location, color: Colors.red),
                  onPressed: () => _trovaPosizione(silenzioso: false),
                  tooltip: "Usa GPS",
                )
              ]),
            ),

            // CARD 3: FERITI
            _buildCard(
              titolo: "3. FERITI",
              accentColor: activeColor,
              child: _buildSwitch("Ci sono feriti?", _feriti, (v) => setState(() => _feriti = v), activeColor),
            ),

            // CARD 4: DANNI MATERIALI
            _buildCard(
              titolo: "4. ALTRI DANNI",
              accentColor: activeColor,
              child: Column(children: [
                _buildSwitch("A veicoli oltre A e B?", _danniVeicoli, (v) => setState(() => _danniVeicoli = v), activeColor),
                const Divider(),
                _buildSwitch("A oggetti diversi dai veicoli?", _danniCose, (v) => setState(() => _danniCose = v), activeColor),
              ]),
            ),

            // CARD 5: TESTIMONI
            _buildCard(
              titolo: "5. TESTIMONI",
              accentColor: activeColor,
              child: _buildField(_testimoni, "Nomi, Indirizzi, Telefoni...", Icons.people, activeColor, maxLines: 3),
            ),

            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _salvaEProsegui,
              style: ElevatedButton.styleFrom(
                backgroundColor: activeColor,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 18),
                textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
              ),
              child: const Text("SALVA E PROSEGUI"),
            ),
            const SizedBox(height: 30),
          ],
        ),
      ),
    );
  }

  // --- WIDGET PERSONALIZZATO NO / SÌ ---
  Widget _buildSwitch(String label, bool value, Function(bool) onChanged, Color activeColor) {
    return InkWell(
      onTap: () => onChanged(!value), // Permette di cliccare su tutta la riga
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 8.0),
        child: Row(
          children: [
            // Etichetta Domanda
            Expanded(
              child: Text(
                label,
                style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
              ),
            ),
            const SizedBox(width: 8),

            // Testo NO
            Text(
              "NO",
              style: TextStyle(
                fontWeight: !value ? FontWeight.bold : FontWeight.normal,
                color: !value ? Colors.red.shade700 : Colors.grey.shade400,
                fontSize: 14,
              ),
            ),

            // Switch Fisico
            Switch(
              value: value,
              onChanged: onChanged,
              activeColor: activeColor,
              activeTrackColor: activeColor.withOpacity(0.4),
              inactiveThumbColor: Colors.grey,
              inactiveTrackColor: Colors.grey.shade300,
            ),

            // Testo SÌ
            Text(
              "SÌ",
              style: TextStyle(
                fontWeight: value ? FontWeight.bold : FontWeight.normal,
                color: value ? activeColor : Colors.grey.shade400,
                fontSize: 14,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildField(TextEditingController c, String label, IconData i, Color iconColor, {String? hint, int maxLines = 1, bool isDate = false, Widget? customPrefix}) {
    return TextField(
      controller: c, maxLines: maxLines,
      textCapitalization: TextCapitalization.sentences,
      keyboardType: isDate ? TextInputType.number : TextInputType.text,
      inputFormatters: isDate ? [DateInputFormatter(), LengthLimitingTextInputFormatter(10)] : [],
      style: TextStyle(fontSize: isDate ? 14 : 16), // Rimpicciolisce un po' il font se è una data
      decoration: InputDecoration(
        labelText: label, hintText: hint,
        prefixIcon: customPrefix ?? Icon(i, size: 20, color: iconColor),
        prefixIconConstraints: isDate ? const BoxConstraints(minWidth: 38, minHeight: 38) : null, // Stringe l'icona
        border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
        contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 15),
      ),
    );
  }

  Widget _buildCard({required String titolo, required Widget child, required Color accentColor}) {
    return Container(
      width: double.infinity, margin: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.08), blurRadius: 10, offset: const Offset(0, 4))]),
      child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
        Text(titolo, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: accentColor)),
        const Divider(height: 25, thickness: 1.2),
        child
      ]),
    );
  }

  @override
  void dispose() {
    _data.dispose(); _ora.dispose(); _luogo.dispose(); _testimoni.dispose();
    super.dispose();
  }
}
=== FILE: lib/comp_15.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'global_data.dart';
import 'comp_16.dart';

class Comp15Screen extends StatefulWidget {
  const Comp15Screen({super.key});
  @override
  State<Comp15Screen> createState() => _Comp15ScreenState();
}

class _Comp15ScreenState extends State<Comp15Screen> {
  late List<Offset?> _puntiFirma;
  late bool isB;
  bool _isNavigating = false;

  @override
  void initState() {
    super.initState();
    isB = GlobalData.latoCorrente == 'B';
    _puntiFirma = isB
        ? List<Offset?>.from(GlobalData.puntiFirmaB)
        : List<Offset?>.from(GlobalData.puntiFirmaA);

    // Appena entro, ruoto in orizzontale
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);
  }

  // --- PUNTO CHIAVE: LA PULIZIA AUTOMATICA ---
  @override
  void dispose() {
    // Quando questa pagina viene distrutta (in qualsiasi modo),
    // FORZO immediatamente il ritorno al verticale.
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    super.dispose();
  }

  Future<void> _tornaIndietro() async {
    _salvaInMemoria();
    if (mounted) Navigator.pop(context);
  }

  void _salvaInMemoria() {
    if (isB) {
      GlobalData.puntiFirmaB = List.from(_puntiFirma);
    } else {
      GlobalData.puntiFirmaA = List.from(_puntiFirma);
    }
  }

  Future<void> _confermaEProsegui() async {
    _salvaInMemoria();

    if (_puntiFirma.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("La firma è obbligatoria!"), backgroundColor: Colors.red),
      );
      return;
    }

    setState(() => _isNavigating = true);

    if (mounted) {
      // Prima di andare alla 16, forzo GIA' il verticale qui.
      await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

      // Piccola pausa per dare tempo all'animazione di rotazione
      await Future.delayed(const Duration(milliseconds: 100));

      if (!mounted) return;

      // Navigo verso la 16. Uso pushReplacement per distruggere la 15 (e chiamare dispose)
      // oppure push normale, ma avendo già forzato il portrait sopra siamo sicuri.
      await Navigator.push(
          context,
          MaterialPageRoute(builder: (c) => const Comp16Screen())
      );

      // --- AGGIUNTA FONDAMENTALE ---
      // Aspettiamo un attimo. Se stiamo facendo "Cancella tutto",
      // in questo lasso di tempo la pagina verrà smontata (mounted diventerà false)
      // e il codice sotto NON verrà eseguito, evitando la trottola.
      await Future.delayed(const Duration(milliseconds: 300));
      // -----------------------------

      if (mounted && ModalRoute.of(context)?.isCurrent == true) {
        await SystemChrome.setPreferredOrientations([
          DeviceOrientation.landscapeLeft,
          DeviceOrientation.landscapeRight,
        ]);
        setState(() => _isNavigating = false);
      }
      // ---------------------------
    }
  }

  @override
  Widget build(BuildContext context) {
    // Ribadisco orizzontale nel build per sicurezza
    // SystemChrome.setPreferredOrientations([
    //  DeviceOrientation.landscapeLeft,
    //  DeviceOrientation.landscapeRight,
    // ]);

    return PopScope(
      canPop: false,
      onPopInvokedWithResult: (didPop, result) async {
        if (!didPop) await _tornaIndietro();
      },
      child: Scaffold(
        backgroundColor: Colors.white,
        resizeToAvoidBottomInset: false,
        body: OrientationBuilder(
          builder: (context, orientation) {
            double shortestSide = MediaQuery.of(context).size.shortestSide;
            bool isTablet = shortestSide > 600;

            // Fix per iPad che potrebbe rimanere verticale
            if (orientation == Orientation.portrait) {
              return Center(
                child: RotatedBox(
                  quarterTurns: 1,
                  child: SizedBox(
                    width: MediaQuery.of(context).size.height,
                    height: MediaQuery.of(context).size.width,
                    child: SafeArea(child: _buildBody(context, isTablet)),
                  ),
                ),
              );
            }
            return SafeArea(child: _buildBody(context, isTablet));
          },
        ),
      ),
    );
  }

  Widget _buildBody(BuildContext context, bool isTablet) {
    Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    double shortestSide = MediaQuery.of(context).size.shortestSide;
    double spessoreFirma = (shortestSide * 0.01).clamp(3.0, 8.0);
    double verticalPadding = isTablet ? MediaQuery.of(context).size.height * 0.12 : 2.0;
    double horizontalPadding = isTablet ? 80.0 : 5.0;

    return _isNavigating
        ? const Center(child: CircularProgressIndicator())
        : Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Container(
          height: 50, color: mainCol, padding: const EdgeInsets.symmetric(horizontal: 10),
          child: Row(children: [
            IconButton(icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: _tornaIndietro),
            Expanded(child: Text("15. Firma (${GlobalData.latoCorrente})", textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18))),
            const SizedBox(width: 48),
          ]),
        ),
        Expanded(
          child: Padding(
            padding: EdgeInsets.symmetric(vertical: verticalPadding, horizontal: horizontalPadding),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (isTablet) ...[const Text("Firma nello spazio sottostante:", style: TextStyle(fontSize: 16)), const SizedBox(height: 8)],
                Expanded(
                  child: Container(
                    width: double.infinity,
                    decoration: BoxDecoration(border: Border.all(color: Colors.grey, width: 2), borderRadius: BorderRadius.circular(10), color: Colors.grey.shade50),
                    child: ClipRRect(
                      borderRadius: BorderRadius.circular(8),
                      child: GestureDetector(
                        onPanUpdate: (d) => setState(() => _puntiFirma.add(d.localPosition)),
                        onPanEnd: (d) => setState(() => _puntiFirma.add(null)),
                        child: RepaintBoundary(child: CustomPaint(painter: FirmaPainter(_puntiFirma, spessoreFirma), size: Size.infinite)),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.fromLTRB(20, 5, 20, isTablet ? 15 : 5),
          child: Row(children: [
            Expanded(flex: 1, child: SizedBox(height: 45, child: OutlinedButton.icon(onPressed: () => setState(() => _puntiFirma.clear()), icon: const Icon(Icons.delete, color: Colors.red), label: const Text("CANCELLA", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)), style: OutlinedButton.styleFrom(side: const BorderSide(color: Colors.red))))),
            const SizedBox(width: 20),
            Expanded(flex: 2, child: SizedBox(height: 45, child: ElevatedButton.icon(onPressed: _confermaEProsegui, style: ElevatedButton.styleFrom(backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 5), icon: const Icon(Icons.check_circle_outline), label: const Text("CONFERMA FIRMA", style: TextStyle(fontWeight: FontWeight.bold))))),
          ]),
        ),
      ],
    );
  }
}

class FirmaPainter extends CustomPainter {
  final List<Offset?> punti;
  final double spessore;
  FirmaPainter(this.punti, this.spessore);
  @override
  void paint(Canvas canvas, Size size) {
    Paint p = Paint()..color = Colors.black..strokeWidth = spessore..strokeCap = StrokeCap.round..strokeJoin = StrokeJoin.round..style = PaintingStyle.stroke..isAntiAlias = true;
    for (int i = 0; i < punti.length - 1; i++) { if (punti[i] != null && punti[i + 1] != null) canvas.drawLine(punti[i]!, punti[i + 1]!, p); }
  }
  @override
  bool shouldRepaint(FirmaPainter old) => true;
}
=== FILE: lib/comp_6-7.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'comp_8.dart';
import 'global_data.dart';

// Formattatore per forzare il maiuscolo mentre si scrive (Versione sicura per iOS/Android)
class UpperCaseTextFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    return TextEditingValue(
      text: newValue.text.toUpperCase(),
      selection: newValue.selection,
      composing: newValue.composing, // Mantiene intatta la memoria della tastiera!
    );
  }
}

class Comp6_7Screen extends StatefulWidget {
  const Comp6_7Screen({super.key});

  @override
  _Comp6_7ScreenState createState() => _Comp6_7ScreenState();
}

class _Comp6_7ScreenState extends State<Comp6_7Screen> {
  late TextEditingController _cognome, _nome, _cf, _indirizzo, _cap, _stato, _tel;
  late TextEditingController _marca, _rimorchio, _targa, _statoImm, _statoImm2;

  // Il tuo FocusNode originale
  late FocusNode _cfFocusNode;

  final bool isB = GlobalData.latoCorrente == 'B';

  bool _isReady = false;

  @override
  void initState() {
    super.initState();

    // Ripristino del tuo listener originale sull'uscita dal campo
    _cfFocusNode = FocusNode();
    _cfFocusNode.addListener(_onCfFocusChange);

    _forzaVerticaleEInizializza();
  }

  // La tua funzione originale per l'uscita dal campo
  void _onCfFocusChange() {
    if (!_cfFocusNode.hasFocus) {
      String cfInserito = _cf.text.trim().toUpperCase();
      if (cfInserito.isNotEmpty) {
        if (!_isCodiceFiscaleValido(cfInserito)) {
          ScaffoldMessenger.of(context).hideCurrentSnackBar();
          ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text("Codice Fiscale NON VALIDO (controlla i caratteri inseriti!)."),
                backgroundColor: Colors.orange,
                duration: Duration(seconds: 3),
              )
          );
        }
      }
    }
  }

  // La tua funzione originale per il controllo in tempo reale
  void _controllaCfInTempoReale(String value) {
    String cfScritto = value.trim().toUpperCase();
    if (cfScritto.length == 16) {
      if (!_isCodiceFiscaleValido(cfScritto)) {
        // NON TOGLIAMO IL FOCUS QUI! Così l'incolla e l'autofill non si rompono.
        ScaffoldMessenger.of(context).hideCurrentSnackBar();
        ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text("⚠️ Codice Fiscale NON VALIDO (controlla i caratteri inseriti!)."),
              backgroundColor: Colors.orange,
              duration: Duration(seconds: 3),
            )
        );
      }
    }
  }

  Future<void> _forzaVerticaleEInizializza() async {
    await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    await Future.delayed(const Duration(milliseconds: 200));
    _initControllers();
    if (mounted) {
      setState(() => _isReady = true);
      WidgetsBinding.instance.addPostFrameCallback((_) => _mostraInfoPopup(context));
    }
  }

  void _initControllers() {
    String pulisciBarre(String valore, String patternBarre) {
      if (valore.contains("/")) return "";
      return valore;
    }

    if (isB) {
      _cognome = TextEditingController(text: GlobalData.Cognome_contraente_B);
      _nome = TextEditingController(text: GlobalData.Nome_contraente_B);
      _cf = TextEditingController(text: GlobalData.Codice_Fiscale_contraente_B);
      _indirizzo = TextEditingController(text: GlobalData.Indirizzo_contraente_B);
      _cap = TextEditingController(text: GlobalData.CAP_contraente_B);
      _stato = TextEditingController(text: GlobalData.Stato_contraente_B.isEmpty ? "ITALIA" : GlobalData.Stato_contraente_B);
      _tel = TextEditingController(text: GlobalData.N_telefono_mail_contraente_B);

      _marca = TextEditingController(text: GlobalData.Marca_e_Tipo_B);
      _targa = TextEditingController(text: GlobalData.Targa_B);
      _statoImm = TextEditingController(text: GlobalData.Stato_immatricolazione_B.isEmpty ? "ITALIA" : GlobalData.Stato_immatricolazione_B);

      _rimorchio = TextEditingController(text: pulisciBarre(GlobalData.Rimorchio_B, "/"));
      _statoImm2 = TextEditingController(text: pulisciBarre(GlobalData.Stato_immatricolazione2_B, "/"));
    } else {
      _cognome = TextEditingController(text: GlobalData.Cognome_contraente_A);
      _nome = TextEditingController(text: GlobalData.Nome_contraente_A);
      _cf = TextEditingController(text: GlobalData.Codice_Fiscale_contraente_A);
      _indirizzo = TextEditingController(text: GlobalData.Indirizzo_contraente_A);
      _cap = TextEditingController(text: GlobalData.CAP_contraente_A);
      _stato = TextEditingController(text: GlobalData.Stato_contraente_A.isEmpty ? "ITALIA" : GlobalData.Stato_contraente_A);
      _tel = TextEditingController(text: GlobalData.N_telefono_mail_contraente_A);

      _marca = TextEditingController(text: GlobalData.Marca_e_Tipo_A);
      _targa = TextEditingController(text: GlobalData.Targa_A);
      _statoImm = TextEditingController(text: GlobalData.Stato_immatricolazione_A.isEmpty ? "ITALIA" : GlobalData.Stato_immatricolazione_A);

      _rimorchio = TextEditingController(text: pulisciBarre(GlobalData.Rimorchio_A, "/"));
      _statoImm2 = TextEditingController(text: pulisciBarre(GlobalData.Stato_immatricolazione2_A, "/"));
    }
  }

  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.directions_car, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Assicurato e Veicolo", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("In questa sezione compilerai i dati relativi al Veicolo ${GlobalData.latoCorrente}.", style: const TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.person, "Dati Anagrafici", "Attenzione al Codice Fiscale: il sistema verificherà in automatico se è scritto correttamente!"),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.numbers, "Targa e Mezzo", "Inserisci la targa esatta (senza spazi) e la marca del veicolo."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.rv_hookup, "Rimorchio", "Compila questa parte SOLO se il veicolo trainava un rimorchio al momento dell'incidente."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(parent: animation, curve: Curves.easeOutBack, reverseCurve: Curves.easeInBack);
        var curveOpacita = CurvedAnimation(parent: animation, curve: Curves.easeOut, reverseCurve: Curves.easeIn);
        return SlideTransition(position: Tween<Offset>(begin: const Offset(0.0, 0.4), end: Offset.zero).animate(curvePosizione), child: FadeTransition(opacity: curveOpacita, child: child));
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(child: RichText(text: TextSpan(style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4), children: [TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: desc)]))),
      ],
    );
  }

  String _calcolaCodiceCognome(String cognome) {
    cognome = cognome.toUpperCase().replaceAll(RegExp(r'[^A-Z]'), '');
    if (cognome.isEmpty) return "XXX";
    String consonanti = cognome.replaceAll(RegExp(r'[AEIOU]'), '');
    String vocali = cognome.replaceAll(RegExp(r'[^AEIOU]'), '');
    return (consonanti + vocali + "XXX").substring(0, 3);
  }

  String _calcolaCodiceNome(String nome) {
    nome = nome.toUpperCase().replaceAll(RegExp(r'[^A-Z]'), '');
    if (nome.isEmpty) return "XXX";
    String consonanti = nome.replaceAll(RegExp(r'[AEIOU]'), '');
    String vocali = nome.replaceAll(RegExp(r'[^AEIOU]'), '');
    if (consonanti.length >= 4) {
      return consonanti[0] + consonanti[2] + consonanti[3];
    } else {
      return (consonanti + vocali + "XXX").substring(0, 3);
    }
  }

  bool _isCodiceFiscaleValido(String cf) {
    cf = cf.toUpperCase().trim();
    if (cf.isEmpty) return false;
    if (!RegExp(r"^[A-Z0-9]{16}$").hasMatch(cf)) return false;

    final String setDispari = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    final String setPari = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    final List<int> valoriDispari = [1, 0, 5, 7, 9, 13, 15, 17, 19, 21, 1, 0, 5, 7, 9, 13, 15, 17, 19, 21, 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, 16, 10, 22, 25, 24, 23];
    final List<int> valoriPari = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25];

    int somma = 0;
    for (int i = 0; i < 15; i++) {
      String char = cf[i];
      int val;
      if ((i + 1) % 2 != 0) {
        int index = setDispari.indexOf(char);
        if (index == -1) return false;
        val = valoriDispari[index];
      } else {
        int index = setPari.indexOf(char);
        if (index == -1) return false;
        val = valoriPari[index];
      }
      somma += val;
    }

    int resto = somma % 26;
    String carattereControlloCalcolato = String.fromCharCode(65 + resto);

    return carattereControlloCalcolato == cf[15];
  }

  void _salvaTutto() {
    FocusScope.of(context).unfocus();

    if (_cognome.text.trim().isEmpty || _nome.text.trim().isEmpty || _cf.text.trim().isEmpty ||
        _indirizzo.text.trim().isEmpty || _cap.text.trim().isEmpty || _stato.text.trim().isEmpty ||
        _tel.text.trim().isEmpty || _marca.text.trim().isEmpty || _targa.text.trim().isEmpty ||
        _statoImm.text.trim().isEmpty) {

      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Compila tutti i campi obbligatori!"), backgroundColor: Colors.red));
      return;
    }

    String cfInserito = _cf.text.trim().toUpperCase();

    if (!_isCodiceFiscaleValido(cfInserito)) {
      ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text("Codice Fiscale NON VALIDO (Errato calcolo finale)."),
            backgroundColor: Colors.orange,
            duration: Duration(seconds: 3),
          )
      );
      return;
    }

    String cfCognome = cfInserito.substring(0, 3);
    String calcolatoCognome = _calcolaCodiceCognome(_cognome.text);
    if (cfCognome != calcolatoCognome) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text("Il CF non corrisponde al COGNOME inserito.\nAtteso: $calcolatoCognome, Trovato: $cfCognome"),
        backgroundColor: Colors.red,
        duration: const Duration(seconds: 4),
      ));
      return;
    }

    String cfNome = cfInserito.substring(3, 6);
    String calcolatoNome = _calcolaCodiceNome(_nome.text);
    if (cfNome != calcolatoNome) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text("Il CF non corrisponde al NOME inserito.\nAtteso: $calcolatoNome, Trovato: $cfNome"),
        backgroundColor: Colors.red,
        duration: const Duration(seconds: 4),
      ));
      return;
    }

    bool currentIsB = GlobalData.latoCorrente == 'B';
    String rimorchioFinale = _rimorchio.text.trim();
    String statoImm2Finale = _statoImm2.text.trim();

    if (rimorchioFinale.isEmpty) {
      rimorchioFinale = "/ / / / / /";
      statoImm2Finale = "/ / / / / / / / / /";
    } else {
      rimorchioFinale = rimorchioFinale.toUpperCase();
      statoImm2Finale = statoImm2Finale.isEmpty ? "ITALIA" : statoImm2Finale.toUpperCase();
    }

    if (currentIsB) {
      GlobalData.Cognome_contraente_B = _cognome.text.trim().toUpperCase();
      GlobalData.Nome_contraente_B = _nome.text.trim().toUpperCase();
      GlobalData.Codice_Fiscale_contraente_B = cfInserito;
      GlobalData.Indirizzo_contraente_B = _indirizzo.text.trim().toUpperCase();
      GlobalData.CAP_contraente_B = _cap.text.trim();
      GlobalData.Stato_contraente_B = _stato.text.trim().toUpperCase();
      GlobalData.N_telefono_mail_contraente_B = _tel.text.trim().toUpperCase();
      GlobalData.Marca_e_Tipo_B = _marca.text.trim().toUpperCase();
      GlobalData.Targa_B = _targa.text.trim().toUpperCase();
      GlobalData.Stato_immatricolazione_B = _statoImm.text.trim().toUpperCase();
      GlobalData.Rimorchio_B = rimorchioFinale;
      GlobalData.Stato_immatricolazione2_B = statoImm2Finale;
    } else {
      GlobalData.Cognome_contraente_A = _cognome.text.trim().toUpperCase();
      GlobalData.Nome_contraente_A = _nome.text.trim().toUpperCase();
      GlobalData.Codice_Fiscale_contraente_A = cfInserito;
      GlobalData.Indirizzo_contraente_A = _indirizzo.text.trim().toUpperCase();
      GlobalData.CAP_contraente_A = _cap.text.trim();
      GlobalData.Stato_contraente_A = _stato.text.trim().toUpperCase();
      GlobalData.N_telefono_mail_contraente_A = _tel.text.trim().toUpperCase();
      GlobalData.Marca_e_Tipo_A = _marca.text.trim().toUpperCase();
      GlobalData.Targa_A = _targa.text.trim().toUpperCase();
      GlobalData.Stato_immatricolazione_A = _statoImm.text.trim().toUpperCase();
      GlobalData.Rimorchio_A = rimorchioFinale;
      GlobalData.Stato_immatricolazione2_A = statoImm2Finale;
    }

    Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp8Screen()));
  }

  @override
  Widget build(BuildContext context) {
    Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgCol = isB ? const Color(0xFFFFF9C4) : const Color(0xFFE3F2FD);

    if (!_isReady) {
      return Scaffold(backgroundColor: bgCol, body: Container());
    }

    return PopScope(
      canPop: true,
      child: GestureDetector(
        onTap: () => FocusScope.of(context).unfocus(),
        child: Scaffold(
          backgroundColor: bgCol,
          resizeToAvoidBottomInset: true,
          appBar: AppBar(
            title: Text("Sez. 6-7: Veicolo ${GlobalData.latoCorrente}"),
            backgroundColor: mainCol,
            foregroundColor: isB ? Colors.black : Colors.white,
          ),
          body: SafeArea(
            child: CustomScrollView(
              physics: const BouncingScrollPhysics(),
              slivers: [
                SliverPadding(
                  padding: const EdgeInsets.all(16),
                  sliver: SliverList(
                    delegate: SliverChildListDelegate([
                      _buildSectionCard(
                        titolo: "6. CONTRAENTE / ASSICURATO",
                        accentColor: mainCol,
                        children: [
                          _buildField(_cognome, "Cognome *", Icons.person),
                          _buildField(_nome, "Nome *", Icons.person_outline),

                          // Il tuo campo originale, col tuo onChanged e il tuo FocusNode!
                          _buildField(
                              _cf,
                              "Codice Fiscale *",
                              Icons.badge,
                              isCF: true,
                              focusNode: _cfFocusNode,
                              onChanged: _controllaCfInTempoReale
                          ),

                          _buildField(_indirizzo, "Indirizzo *", Icons.home),
                          Row(
                              children: [
                                Expanded(child: _buildField(_cap, "C.A.P. *", Icons.location_on, isNumeric: true)),
                                const SizedBox(width: 10),
                                Expanded(child: _buildField(_stato, "Stato *", Icons.flag)),
                              ]
                          ),
                          _buildField(_tel, "Tel / Email *", Icons.email),
                        ],
                      ),
                      _buildSectionCard(
                        titolo: "7. VEICOLO A MOTORE",
                        accentColor: mainCol,
                        children: [
                          _buildField(_marca, "Marca e Tipo *", Icons.directions_car),
                          const SizedBox(height: 10),
                          Row(
                              children: [
                                Expanded(child: _buildField(_targa, "Targa *", Icons.numbers, isUpper: true)),
                                const SizedBox(width: 10),
                                Expanded(child: _buildField(_rimorchio, "Rimorchio (Opz)", Icons.rv_hookup)),
                              ]
                          ),
                          const SizedBox(height: 10),
                          Row(
                              children: [
                                Expanded(child: _buildField(_statoImm, "Stato Imm. *", Icons.public)),
                                const SizedBox(width: 10),
                                Expanded(child: _buildField(_statoImm2, "Stato Rimorchio", Icons.public_off)),
                              ]
                          ),
                        ],
                      ),
                    ]),
                  ),
                ),
                SliverFillRemaining(
                  hasScrollBody: false,
                  child: Align(
                    alignment: Alignment.bottomCenter,
                    child: Padding(
                      padding: const EdgeInsets.all(16),
                      child: _navButtons(mainCol),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  // Il tuo widget originale intatto
  Widget _buildField(
      TextEditingController controller,
      String label,
      IconData icon,
      {
        bool isUpper = false,
        bool isNumeric = false,
        bool isCF = false,
        FocusNode? focusNode,
        Function(String)? onChanged,
      }
      ) {
    List<TextInputFormatter> formatters = [];

    if (isNumeric) {
      formatters.add(FilteringTextInputFormatter.digitsOnly);
      formatters.add(LengthLimitingTextInputFormatter(5));
    } else if (isCF) {
      formatters.add(FilteringTextInputFormatter.allow(RegExp("[a-zA-Z0-9]")));
      formatters.add(UpperCaseTextFormatter());
      formatters.add(LengthLimitingTextInputFormatter(16));
    } else if (isUpper) {
      formatters.add(UpperCaseTextFormatter());
      formatters.add(FilteringTextInputFormatter.deny(RegExp(r'\s')));
    }

    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: TextField(
        controller: controller,
        focusNode: focusNode,
        onChanged: onChanged,
        keyboardType: isNumeric ? TextInputType.number : TextInputType.text,
        inputFormatters: formatters,
        textCapitalization: (isUpper || isCF) ? TextCapitalization.characters : TextCapitalization.sentences,
        decoration: InputDecoration(
          labelText: label,
          prefixIcon: Icon(icon, size: 20, color: isB ? Colors.orange.shade800 : Colors.blue.shade700),
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
          filled: true,
          fillColor: Colors.white,
        ),
      ),
    );
  }

  Widget _buildSectionCard({required String titolo, required List<Widget> children, required Color accentColor}) {
    return Card(
      elevation: 2,
      margin: const EdgeInsets.only(bottom: 16),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                  titolo,
                  style: TextStyle(fontWeight: FontWeight.bold, color: accentColor, fontSize: 16)
              ),
              const Divider(height: 25),
              ...children,
            ]
        ),
      ),
    );
  }

  Widget _navButtons(Color col) {
    return Row(
        children: [
          Expanded(
              child: OutlinedButton(
                  onPressed: () => Navigator.pop(context),
                  style: OutlinedButton.styleFrom(minimumSize: const Size(0, 55)),
                  child: const Text("INDIETRO")
              )
          ),
          const SizedBox(width: 15),
          Expanded(
              flex: 2,
              child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                      backgroundColor: col,
                      foregroundColor: isB ? Colors.black : Colors.white,
                      minimumSize: const Size(0, 55)
                  ),
                  onPressed: _salvaTutto,
                  child: const Text("SALVA E PROSEGUI", style: TextStyle(fontWeight: FontWeight.bold))
              )
          ),
        ]
    );
  }

  @override
  void dispose() {
    _cfFocusNode.removeListener(_onCfFocusChange);
    _cfFocusNode.dispose();

    _cognome.dispose(); _nome.dispose(); _cf.dispose(); _indirizzo.dispose();
    _cap.dispose(); _stato.dispose(); _tel.dispose();
    _marca.dispose(); _targa.dispose(); _rimorchio.dispose();
    _statoImm.dispose(); _statoImm2.dispose();
    super.dispose();
  }
}
=== FILE: lib/cai_mapping.dart ===
class CaiMapping {

  static const Map<String, String> testi = {
    // HEADER
    'data_incidente': 'data_sinistro',
    'ora': 'ora',
    'luogo': 'luogo_sinistro',
    'testimoni': 'testimoni1',

    // VEICOLO A
    'Cognome_contraente_A': 'cognome_contraenteA',
    'Nome_contraente_A': 'nome_contraenteA',
    'Codice_Fiscale_contraente_A': 'codice_fiscale_contrA',
    'Indirizzo_contraente_A': 'indirizzo_contrA',
    'CAP_contraente_A': 'cap_contrA',
    'Stato_contraente_A': 'stato_contrA',
    'N_telefono_mail_contraente_A': 'tel_contrA',
    'Marca_e_Tipo_A': 'marcaA',
    'Targa_A': 'targa_veicoloA',
    'Stato_immatricolazione_A': 'stato_im_veicoloA',
    'Rimorchio_A': 'targa_rimorchioA',
    'Stato_immatricolazione2_A': 'stato_im_rimorchioA',
    'Denominazione_A': 'COMPAGNIA',
    'Numero_Polizza_A': 'numero_polizzaA',
    'N_carta_verde_A': 'CVA',
    'Data_Inizio_Dal_A': 'ass_dalA',
    'Data_Scadenza_Al_A': 'ass_alA',
    'Agenzia_A': 'AGENZIA_A',
    'Denominazione_agenzia_A': 'denom_A',
    'Indirizzo_agenzia_A': 'ind_ag_A',
    'Stato_agenzia_A': 'ag_stat_A',
    'N_tel_mail_agenzia_A': 'tel_ag_A',
    'Cognome_cond_A': 'cogn_cond_A',
    'Nome_cond_A': 'nome_cond_A',
    'Data_nascita_cond_A': 'dnascita_condA',
    'Cod_fiscale_cond_A': 'codice_fiscale_conduA',
    'Indirizzo_cond_A': 'indir_conduA',
    'Stato_cond_A': 'stato_conduA',
    'N_tel_mail_cond_A': 'tel_conduA',
    'N_Patente_cond_A': 'n_p_conduA',
    'Scadenza_cond_A': 'condu_scad_A',

    // --- AGGIUNTO CATEGORIA A ---
    'Categoria_cond_A': 'cat_A', // <--- VERIFICA QUESTO NOME NEL PDF (es. cat_A, catA, CategA...)

    'danni_visibili_A': 'danni_vis_A1',
    'osservazioni_A': 'osservazioniA',

    // VEICOLO B
    'Cognome_contraente_B': 'cognome_contraenteB',
    'Nome_contraente_B': 'nome_contraenteB',
    'Codice_Fiscale_contraente_B': 'codice_fiscale_contrB',
    'Indirizzo_contraente_B': 'indirizzo_contrB',
    'CAP_contraente_B': 'cap_contrB',
    'Stato_contraente_B': 'stato_contrB',
    'N_telefono_mail_contraente_B': 'tel_contrB',
    'Marca_e_Tipo_B': 'marcaB',
    'Targa_B': 'targa_veicoloB',
    'Stato_immatricolazione_B': 'stato_im_veicoloB',
    'Rimorchio_B': 'targa_rimorchioB',
    'Stato_immatricolazione2_B': 'stato_im_rimorchioB',
    'Denominazione_B': 'compagnia1',
    'Numero_Polizza_B': 'numero_polizzaB',
    'N_carta_verde_B': 'CVB',
    'Data_Inizio_Dal_B': 'ass_dalB',
    'Data_Scadenza_Al_B': 'ass_alB',
    'Agenzia_B': 'AGENZIA_B',
    'Denominazione_agenzia_B': 'denom_B',
    'Indirizzo_agenzia_B': 'ind_ag_B',
    'Stato_agenzia_B': 'ag_stat_B',
    'N_tel_mail_agenzia_B': 'tel_ag_B',
    'Cognome_cond_B': 'cogn_cond_B',
    'Nome_cond_B': 'nome_cond_B',
    'Data_nascita_cond_B': 'dnascita_condB',
    'Cod_fiscale_cond_B': 'codice_fiscale_conduB',
    'Indirizzo_cond_B': 'indir_conduB',
    'Stato_cond_B': 'stato_conduB',
    'N_tel_mail_cond_B': 'tel_conduB',
    'N_Patente_cond_B': 'n_p_conduB',
    'Scadenza_cond_B': 'condu_scad_B',

    // --- AGGIUNTO CATEGORIA B ---
    'Categoria_cond_B': 'cat_B', // <--- VERIFICA QUESTO NOME NEL PDF

    'danni_visibili_B': 'danni_vis_B1',
    'osservazioni_B': 'osservazioniB',
  };

  // CHECKBOX
  static const String feriti_NO = 'x';
  static const String feriti_SI = 'y';
  static const String danni_veicoli_NO = 'C';
  static const String danni_veicoli_SI = 'D';
  static const String danni_oggetti_NO = 'A';
  static const String danni_oggetti_SI = 'B';
  static const String danni_mat_A_NO = 'danni_noA';
  static const String danni_mat_A_SI = 'danni_siA';
  static const String danni_mat_B_NO = 'danni_noB';
  static const String danni_mat_B_SI = 'danni_siB';

  // CIRCOSTANZE (Indice 0 vuoto)
  static const List<String> circostanzeA = [
    '',
    'A01', 'A02', 'A03', 'A04', 'A05', 'A06', 'A07', 'A08', 'A09',
    'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17'
  ];

  static const List<String> circostanzeB = [
    '',
    'B01', 'B02', 'B03', 'B04', 'B05', 'B06', 'B07', 'B08', 'B09',
    'B10', 'B11', 'B12', 'B13', 'B14', 'B15', 'B16', 'B17'
  ];

  // TOTALI
  static const String tot_crocette_A = 'A_tot';
  static const String tot_crocette_B = 'B_tot';

  // BOX IMMAGINI
  static const String box_grafico = 'disegno13';
  static const String box_firma_A = 'firmaA';
  static const String box_firma_B = 'firmaB';

  // Opzionali se servono
  static const String box_urto_A = 'danni_vis_A1';
  static const String box_urto_B = 'danni_vis_B1';
}
=== FILE: lib/temp/pdf_engine.dart ===
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/services.dart' show rootBundle;
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'package:flutter/material.dart';

import 'global_data.dart';
import 'models.dart';
import 'cai_mapping.dart';

class PdfEngine {

  static Future<List<int>> generaDocumentoCai() async {
    PdfDocument? document;
    try {
      final ByteData data = await rootBundle.load('assets/CAI_p1.pdf');

      // 1. Caricamento e Copia
      final List<int> bytesCopia = data.buffer.asUint8List().toList();
      document = PdfDocument(inputBytes: bytesCopia);

      final PdfForm form = document.form;
      final PdfPage page = document.pages[0];

      form.setDefaultAppearance(false);

      // Mappatura
      Map<String, PdfField> mappaCampi = {};
      for (int i = 0; i < form.fields.count; i++) {
        if (form.fields[i].name != null) {
          mappaCampi[form.fields[i].name!.trim().toUpperCase()] = form.fields[i];
        }
      }

      // --- COMPILAZIONE STANDARD (La tua versione preferita) ---

      // 1. TESTI
      CaiMapping.testi.forEach((keyGlobal, keyPdf) {
        String valore = _valoreDaGlobal(keyGlobal);
        String keyPdfNorm = keyPdf.trim().toUpperCase();
        if (mappaCampi.containsKey(keyPdfNorm) && valore.isNotEmpty) {
          final field = mappaCampi[keyPdfNorm];
          if (field is PdfTextBoxField) {
            field.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
            field.text = valore.toUpperCase();
          }
        }
      });

      // 2. CHECKBOX
      _scriviX(mappaCampi, [GlobalData.feriti ? CaiMapping.feriti_SI : CaiMapping.feriti_NO]);
      _scriviX(mappaCampi, [GlobalData.Veicoli_danni_materiali_oltre ? CaiMapping.danni_veicoli_SI : CaiMapping.danni_veicoli_NO]);
      _scriviX(mappaCampi, [GlobalData.Oggetti_diversi_danni_materiali ? CaiMapping.danni_oggetti_SI : CaiMapping.danni_oggetti_NO]);
      _scriviX(mappaCampi, [GlobalData.FLAG_danni_mat_assicurati_A ? CaiMapping.danni_mat_A_SI : CaiMapping.danni_mat_A_NO]);
      _scriviX(mappaCampi, [GlobalData.FLAG_danni_mat_assicurati_B ? CaiMapping.danni_mat_B_SI : CaiMapping.danni_mat_B_NO]);

      String catA = GlobalData.Categoria_cond_A.toUpperCase().trim();
      if (catA == 'A') _scriviX(mappaCampi, ['cat_a_A']);
      else if (catA == 'B') _scriviX(mappaCampi, ['cat_b_A']);
      else if (catA.isNotEmpty) _scriviTesto(mappaCampi, ['cat_altro_A'], catA);

      String catB = GlobalData.Categoria_cond_B.toUpperCase().trim();
      if (catB == 'A') _scriviX(mappaCampi, ['cat_a_B']);
      else if (catB == 'B') _scriviX(mappaCampi, ['cat_b_B']);
      else if (catB.isNotEmpty) _scriviTesto(mappaCampi, ['cat_altro_B'], catB);

      // 3. CIRCOSTANZE
      int countA = 0;
      int countB = 0;
      for (int i = 1; i <= 17; i++) {
        if (GlobalData.circostanzeA[i] == true) {
          if (_scriviX(mappaCampi, [i < 10 ? "A0$i" : "A$i"])) countA++;
        }
        if (GlobalData.circostanzeB[i] == true) {
          List<String> nomiTarget = [];
          if (i == 9) nomiTarget = ["Check Box 26", "CheckBox26", "26"];
          else if (i == 10) nomiTarget = ["Check Box 27", "CheckBox27", "27"];
          else if (i == 11) nomiTarget = ["Check Box 28", "CheckBox28", "28"];
          else if (i == 12) nomiTarget = ["Check Box 29", "CheckBox29", "29"];
          else nomiTarget = [i < 10 ? "B0$i" : "B$i"];
          if (_scriviX(mappaCampi, nomiTarget)) countB++;
        }
      }
      _scriviTestoTotale(mappaCampi, ['A_TOT', 'A_tot'], countA.toString());
      _scriviTestoTotale(mappaCampi, ['B_TOT', 'B_tot'], countB.toString());

      // 4. PUNTI URTO
      for (String punto in GlobalData.puntiUrtoA_List) _scriviXRossa(mappaCampi, [punto]);
      for (String punto in GlobalData.puntiUrtoB_List) _scriviXRossa(mappaCampi, [punto]);

      // 5. IMMAGINI
      await _disegnaInBox(page, mappaCampi, CaiMapping.box_grafico,
          await _renderGraficoV40(GlobalData.tratti.cast<TrattoPenna>().toList(), GlobalData.elementi.cast<ElementoGrafico>().toList()));

      await _disegnaInBox(page, mappaCampi, CaiMapping.box_firma_A, await _renderFirmaTight(GlobalData.puntiFirmaA, Colors.black));
      await _disegnaInBox(page, mappaCampi, CaiMapping.box_firma_B, await _renderFirmaTight(GlobalData.puntiFirmaB, Colors.black));

      // =================================================================
      // FASE CRITICA: SALVATAGGIO -> RICARICA -> FLATTEN (Anti-Crash)
      // =================================================================

      // 1. Salviamo il file compilato in memoria. Questo corregge gli errori interni del PDF.
      List<int> bytesTemporanei = await document.save();
      document.dispose(); // Chiudiamo il vecchio

      // 2. Riapriamo il file "pulito"
      PdfDocument docFinale = PdfDocument(inputBytes: bytesTemporanei);

      // 3. Ora eseguiamo il FLATTEN.
      // È INDISPENSABILE per vedere le X nell'immagine di anteprima.
      // Poiché il file è stato appena rigenerato, NON DOVREBBE CRASHARE.
      try {
        docFinale.form.flattenAllFields();
      } catch (e) {
        debugPrint("⚠️ Errore Flattening anche dopo pulizia: $e");
        // Se fallisce ancora, usiamo il fallback ReadOnly, ma l'immagine potrebbe essere incompleta.
        docFinale.form.readOnly = true;
      }

      // 4. Salvataggio finale
      List<int> bytesFinali = await docFinale.save();
      docFinale.dispose();

      return bytesFinali;

    } catch (e) {
      debugPrint("ERRORE GENERAZIONE PDF: $e");
      return [];
    }
  }

  // --- HELPERS (Standard) ---

  static bool _scriviX(Map<String, PdfField> mappa, List<String> nomiPossibili) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 14);
          field.foreColor = PdfColor(0, 0, 0);
          field.text = "X";
        } else if (field is PdfCheckBoxField) {
          field.isChecked = true;
        }
        return true;
      }
    }
    return false;
  }

  static void _scriviTesto(Map<String, PdfField> mappa, List<String> nomiPossibili, String testo) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 10);
          field.foreColor = PdfColor(0, 0, 0);
          field.text = testo;
        }
        return;
      }
    }
  }

  static bool _scriviXRossa(Map<String, PdfField> mappa, List<String> nomiPossibili) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 16, style: PdfFontStyle.bold);
          field.foreColor = PdfColor(255, 0, 0);
          field.text = "X";
          return true;
        }
      }
    }
    return false;
  }

  static void _scriviTestoTotale(Map<String, PdfField> mappa, List<String> nomi, String testo) {
    for (String nome in nomi) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
          field.textAlignment = PdfTextAlignment.center;
          field.text = testo;
        }
        return;
      }
    }
  }

  static Future<void> _disegnaInBox(PdfPage page, Map<String, PdfField> mappa, String nomeCampo, Uint8List? imgBytes) async {
    String key = nomeCampo.trim().toUpperCase();
    if (imgBytes == null || !mappa.containsKey(key)) return;
    Rect boxRect = mappa[key]!.bounds;
    PdfBitmap bitmap = PdfBitmap(imgBytes);
    double imageW = bitmap.width.toDouble();
    double imageH = bitmap.height.toDouble();
    if (imageW <= 0 || imageH <= 0) return;
    double ratioX = boxRect.width / imageW;
    double ratioY = boxRect.height / imageH;
    double scale = (ratioX < ratioY) ? ratioX : ratioY;
    double drawW = imageW * scale;
    double drawH = imageH * scale;
    double offsetX = boxRect.left + (boxRect.width - drawW) / 2;
    double offsetY = boxRect.top + (boxRect.height - drawH) / 2;
    page.graphics.drawImage(bitmap, Rect.fromLTWH(offsetX, offsetY, drawW, drawH));
  }

  static Future<Uint8List?> _renderFirmaTight(List<Offset?> punti, Color colore) async {
    if (punti.isEmpty) return null;
    double minX = double.infinity, minY = double.infinity, maxX = double.negativeInfinity, maxY = double.negativeInfinity;
    for (var p in punti) { if (p != null) { if (p.dx < minX) minX = p.dx; if (p.dx > maxX) maxX = p.dx; if (p.dy < minY) minY = p.dy; if (p.dy > maxY) maxY = p.dy; } }
    double padding = 20.0;
    double firmaW = maxX - minX;
    double firmaH = maxY - minY;
    if (firmaW <= 0) firmaW = 1; if (firmaH <= 0) firmaH = 1;
    double resolutionScale = 3.0;
    double canvasW = (firmaW + padding * 2) * resolutionScale;
    double canvasH = (firmaH + padding * 2) * resolutionScale;
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    canvas.scale(resolutionScale);
    canvas.translate(-minX + padding, -minY + padding);
    final paint = Paint()..color = colore..strokeWidth = 5.0..style = PaintingStyle.stroke..strokeCap = StrokeCap.round..strokeJoin = StrokeJoin.round;
    for (int i = 0; i < punti.length - 1; i++) { if (punti[i] != null && punti[i+1] != null) { canvas.drawLine(punti[i]!, punti[i+1]!, paint); } }
    final img = await recorder.endRecording().toImage(canvasW.toInt(), canvasH.toInt());
    final byteData = await img.toByteData(format: ui.ImageByteFormat.png);
    return byteData?.buffer.asUint8List();
  }

  static Future<Uint8List?> _renderGraficoV40(List<TrattoPenna> tratti, List<ElementoGrafico> elementi) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final size = const Size(2000, 800);
    final painter = PainterV40(tratti, elementi);
    painter.paint(canvas, size);
    final img = await recorder.endRecording().toImage(size.width.toInt(), size.height.toInt());
    final byteData = await img.toByteData(format: ui.ImageByteFormat.png);
    return byteData?.buffer.asUint8List();
  }

  static String _valoreDaGlobal(String key) {
    switch (key) {
      case 'data_incidente': return GlobalData.data_incidente;
      case 'ora': return GlobalData.ora;
      case 'luogo': return GlobalData.luogo;
      case 'testimoni': return GlobalData.testimoni;
      case 'danni_visibili_A': return GlobalData.danni_visibili_A;
      case 'osservazioni_A': return GlobalData.osservazioni_A;
      case 'danni_visibili_B': return GlobalData.danni_visibili_B;
      case 'osservazioni_B': return GlobalData.osservazioni_B;
      case 'Cognome_contraente_A': return GlobalData.Cognome_contraente_A;
      case 'Nome_contraente_A': return GlobalData.Nome_contraente_A;
      case 'Codice_Fiscale_contraente_A': return GlobalData.Codice_Fiscale_contraente_A;
      case 'Indirizzo_contraente_A': return GlobalData.Indirizzo_contraente_A;
      case 'CAP_contraente_A': return GlobalData.CAP_contraente_A;
      case 'Stato_contraente_A': return GlobalData.Stato_contraente_A;
      case 'N_telefono_mail_contraente_A': return GlobalData.N_telefono_mail_contraente_A;
      case 'Marca_e_Tipo_A': return GlobalData.Marca_e_Tipo_A;
      case 'Targa_A': return GlobalData.Targa_A;
      case 'Stato_immatricolazione_A': return GlobalData.Stato_immatricolazione_A;
      case 'Rimorchio_A': return GlobalData.Rimorchio_A;
      case 'Stato_immatricolazione2_A': return GlobalData.Stato_immatricolazione2_A;
      case 'Denominazione_A': return GlobalData.Denominazione_A;
      case 'Numero_Polizza_A': return GlobalData.Numero_Polizza_A;
      case 'N_carta_verde_A': return GlobalData.N_carta_verde_A;
      case 'Data_Inizio_Dal_A': return GlobalData.Data_Inizio_Dal_A;
      case 'Data_Scadenza_Al_A': return GlobalData.Data_Scadenza_Al_A;
      case 'Agenzia_A': return GlobalData.Agenzia_A;
      case 'Indirizzo_agenzia_A': return GlobalData.Indirizzo_agenzia_A;
      case 'Stato_agenzia_A': return GlobalData.Stato_agenzia_A;
      case 'Denominazione_agenzia_A': return GlobalData.Denominazione_agenzia_A;
      case 'N_tel_mail_agenzia_A': return GlobalData.N_tel_mail_agenzia_A;
      case 'Cognome_cond_A': return GlobalData.Cognome_cond_A;
      case 'Nome_cond_A': return GlobalData.Nome_cond_A;
      case 'Data_nascita_cond_A': return GlobalData.Data_nascita_cond_A;
      case 'Cod_fiscale_cond_A': return GlobalData.Cod_fiscale_cond_A;
      case 'Indirizzo_cond_A': return GlobalData.Indirizzo_cond_A;
      case 'Stato_cond_A': return GlobalData.Stato_cond_A;
      case 'N_tel_mail_cond_A': return GlobalData.N_tel_mail_cond_A;
      case 'N_Patente_cond_A': return GlobalData.N_Patente_cond_A;
      case 'Scadenza_cond_A': return GlobalData.Scadenza_cond_A;
      case 'Cognome_contraente_B': return GlobalData.Cognome_contraente_B;
      case 'Nome_contraente_B': return GlobalData.Nome_contraente_B;
      case 'Codice_Fiscale_contraente_B': return GlobalData.Codice_Fiscale_contraente_B;
      case 'Indirizzo_contraente_B': return GlobalData.Indirizzo_contraente_B;
      case 'CAP_contraente_B': return GlobalData.CAP_contraente_B;
      case 'Stato_contraente_B': return GlobalData.Stato_contraente_B;
      case 'N_telefono_mail_contraente_B': return GlobalData.N_telefono_mail_contraente_B;
      case 'Marca_e_Tipo_B': return GlobalData.Marca_e_Tipo_B;
      case 'Targa_B': return GlobalData.Targa_B;
      case 'Stato_immatricolazione_B': return GlobalData.Stato_immatricolazione_B;
      case 'Rimorchio_B': return GlobalData.Rimorchio_B;
      case 'Stato_immatricolazione2_B': return GlobalData.Stato_immatricolazione2_B;
      case 'Denominazione_B': return GlobalData.Denominazione_B;
      case 'Numero_Polizza_B': return GlobalData.Numero_Polizza_B;
      case 'N_carta_verde_B': return GlobalData.N_carta_verde_B;
      case 'Data_Inizio_Dal_B': return GlobalData.Data_Inizio_Dal_B;
      case 'Data_Scadenza_Al_B': return GlobalData.Data_Scadenza_Al_B;
      case 'Agenzia_B': return GlobalData.Agenzia_B;
      case 'Indirizzo_agenzia_B': return GlobalData.Indirizzo_agenzia_B;
      case 'Stato_agenzia_B': return GlobalData.Stato_agenzia_B;
      case 'Denominazione_agenzia_B': return GlobalData.Denominazione_agenzia_B;
      case 'N_tel_mail_agenzia_B': return GlobalData.N_tel_mail_agenzia_B;
      case 'Cognome_cond_B': return GlobalData.Cognome_cond_B;
      case 'Nome_cond_B': return GlobalData.Nome_cond_B;
      case 'Data_nascita_cond_B': return GlobalData.Data_nascita_cond_B;
      case 'Cod_fiscale_cond_B': return GlobalData.Cod_fiscale_cond_B;
      case 'Indirizzo_cond_B': return GlobalData.Indirizzo_cond_B;
      case 'Stato_cond_B': return GlobalData.Stato_cond_B;
      case 'N_tel_mail_cond_B': return GlobalData.N_tel_mail_cond_B;
      case 'N_Patente_cond_B': return GlobalData.N_Patente_cond_B;
      case 'Scadenza_cond_B': return GlobalData.Scadenza_cond_B;
      default: return "";
    }
  }
}

class PainterV40 extends CustomPainter {
final List<TrattoPenna> tr;
final List<ElementoGrafico> el;

PainterV40(this.tr, this.el);

final List<Color> palette = [Colors.blue, Colors.orange, Colors.green, Colors.purple, Colors.red];

@override
void paint(Canvas canvas, Size size) {
  // 1. SFONDO BIANCO (Risolve il problema del nero)
  final Paint backgroundPaint = Paint()..color = Colors.white;
  canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), backgroundPaint);

  // 2. DISEGNO GRIGLIA (Opzionale, ma rende il disegno professionale come l'originale)
  final Paint gridPaint = Paint()
    ..color = Colors.grey.shade300
    ..strokeWidth = 2.0;

  double step = 40.0; // Dimensione quadretti
  // Linee verticali
  for (double x = 0; x <= size.width; x += step) {
    canvas.drawLine(Offset(x, 0), Offset(x, size.height), gridPaint);
  }
  // Linee orizzontali
  for (double y = 0; y <= size.height; y += step) {
    canvas.drawLine(Offset(0, y), Offset(size.width, y), gridPaint);
  }

  // Se non ci sono tratti o elementi, ci fermiamo qui (abbiamo disegnato solo sfondo e griglia pulita)
  if (tr.isEmpty && el.isEmpty) return;

  // --- CALCOLO BOUNDING BOX PER IL CONTENUTO ---
  double minX = double.infinity, minY = double.infinity;
  double maxX = double.negativeInfinity, maxY = double.negativeInfinity;

  for (var t in tr) {
    for (var p in t.punti) {
      if (p.dx < minX) minX = p.dx;
      if (p.dx > maxX) maxX = p.dx;
      if (p.dy < minY) minY = p.dy;
      if (p.dy > maxY) maxY = p.dy;
    }
  }
  for (var e in el) {
    if (e.posizione.dx - 30 < minX) minX = e.posizione.dx - 30;
    if (e.posizione.dx + 30 > maxX) maxX = e.posizione.dx + 30;
    if (e.posizione.dy - 30 < minY) minY = e.posizione.dy - 30;
    if (e.posizione.dy + 30 > maxY) maxY = e.posizione.dy + 30;
  }

  // Se non abbiamo trovato nulla (caso raro), usiamo valori di default
  if (minX == double.infinity) { minX = 0; maxX = 100; minY = 0; maxY = 100; }

  double padding = 40.0;
  double drawingW = maxX - minX + (padding * 2);
  double drawingH = maxY - minY + (padding * 2);

  if (drawingW <= 0) drawingW = 100;
  if (drawingH <= 0) drawingH = 100;

  // Scala per adattare il disegno al box (Contain)
  double scaleX = size.width / drawingW;
  double scaleY = size.height / drawingH;
  double scale = (scaleX < scaleY) ? scaleX : scaleY;

  // Centratura
  double offsetX = (size.width - (drawingW * scale)) / 2;
  double offsetY = (size.height - (drawingH * scale)) / 2;

  canvas.save();
  canvas.translate(offsetX, offsetY);
  canvas.scale(scale);
  canvas.translate(-minX + padding, -minY + padding);

  // --- DISEGNO STRADE E FRECCE ---
  Paint pStrada = Paint()
    ..color = Colors.black
    ..strokeWidth = 4.0 / scale
    ..style = PaintingStyle.stroke
    ..strokeCap = StrokeCap.round;

  for (var t in tr) {
    if (t.punti.length > 1) {
      Path path = Path()..moveTo(t.punti[0].dx, t.punti[0].dy);
      for (var pt in t.punti) path.lineTo(pt.dx, pt.dy);
      canvas.drawPath(path, pStrada);

      if (t.tipo == 'freccia') {
        double a = (t.punti.last - t.punti[t.punti.length - 2]).direction;
        canvas.drawLine(t.punti.last, t.punti.last - Offset.fromDirection(a - 0.5, 15), pStrada);
        canvas.drawLine(t.punti.last, t.punti.last - Offset.fromDirection(a + 0.5, 15), pStrada);
      }
    }
  }

  // --- DISEGNO AUTO E TESTI ---
  for (var e in el) {
    canvas.save();
    canvas.translate(e.posizione.dx, e.posizione.dy);
    canvas.rotate(e.rotazione);

    if (e.tipo == 'testo') {
      final tp = TextPainter(
          text: TextSpan(text: e.label ?? "", style: const TextStyle(color: Colors.black, fontSize: 24, fontWeight: FontWeight.bold)),
          textDirection: TextDirection.ltr
      )..layout();
      tp.paint(canvas, Offset(-tp.width/2, -tp.height/2));
    }
    else if (e.tipo.startsWith('auto')) {
      int idx = ((e.label ?? "A").codeUnitAt(0) - 65) % palette.length;
      Paint p = Paint()..color = palette[idx];

      // Corpo auto colorato
      canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: 60, height: 30), p);
      // Bordo auto nero
      canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: 60, height: 30), Paint()..style=PaintingStyle.stroke..color=Colors.black..strokeWidth=2);

      // Lettera A/B Bianca
      final tp = TextPainter(
          text: TextSpan(text: e.label ?? "A", style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20)),
          textDirection: TextDirection.ltr
      )..layout();
      tp.paint(canvas, Offset(-tp.width/2, -tp.height/2));
    }
    canvas.restore();
  }

  canvas.restore();
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
=== FILE: lib/temp/comp_16.dart ===
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:path_provider/path_provider.dart';
import 'package:printing/printing.dart';
import 'package:share_plus/share_plus.dart';

import 'scambio_dati_screen.dart';
import 'pdf_engine.dart';
import 'global_data.dart';
import 'main.dart';
import 'comp_6-7.dart';
import 'comp_1-5.dart';

class Comp16Screen extends StatefulWidget {
  const Comp16Screen({super.key});

  @override
  State<Comp16Screen> createState() => _Comp16ScreenState();
}

class _Comp16ScreenState extends State<Comp16Screen> with WidgetsBindingObserver {
  bool _scambioEffettuato = false;
  bool _datiPresenti = false;
  bool _ioHoApprovato = false;
  bool _tuttiHannoApprovato = false;

  bool _staCancellando = false;
  bool _cancellazioneAvviataDaMe = false;

  String _statusText = "Esegui lo Scambio Dati per iniziare.";
  Color _statusColor = Colors.orange.shade800;
  IconData _statusIcon = Icons.warning_amber_rounded;

  File? _filePdfReale;
  Uint8List? _immagineAnteprima;
  bool _isLoading = false;
  StreamSubscription? _roomSubscription;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    _puliziaIngresso();
  }

  Future<void> _puliziaIngresso() async {
    if (GlobalData.idScambioTemporaneo == null && GlobalData.idSessione != null) {
      GlobalData.idScambioTemporaneo = GlobalData.idSessione;
    }
    if (GlobalData.idScambioTemporaneo == null) {
      if (GlobalData.latoCorrente == 'A') GlobalData.resetB(); else GlobalData.resetA();
    }
    if (mounted) _verificaStatoPostScambio();
  }

  void _verificaStatoPostScambio() {
    bool datiOk = false;
    if (GlobalData.latoCorrente == 'A') {
      datiOk = GlobalData.Cognome_contraente_B.trim().isNotEmpty && GlobalData.Targa_B.trim().isNotEmpty;
    } else {
      datiOk = GlobalData.Cognome_contraente_A.trim().isNotEmpty && GlobalData.Targa_A.trim().isNotEmpty;
    }

    if (mounted) {
      setState(() {
        if (datiOk) {
          _scambioEffettuato = true;
          _datiPresenti = true;
          _statusText = "Dati ricevuti. Generazione anteprima...";
          _statusColor = Colors.blue.shade800;
          _statusIcon = Icons.pending_actions;
          _generaDocumenti();
          _attivaAscoltoStanza();
        } else {
          _resetStatiUI();
        }
      });
    }
  }

  void _resetStatiUI() {
    _scambioEffettuato = false;
    _datiPresenti = false;
    _ioHoApprovato = false;
    _tuttiHannoApprovato = false;
    _statusText = "Esegui lo Scambio Dati per iniziare.";
    _statusColor = Colors.orange.shade800;
    _statusIcon = Icons.warning_amber_rounded;
    _filePdfReale = null;
    _immagineAnteprima = null;
  }

  void _attivaAscoltoStanza() {
    String? idDaAscoltare = GlobalData.idScambioTemporaneo ?? GlobalData.idSessione;
    if (idDaAscoltare == null || _roomSubscription != null) return;

    _roomSubscription = FirebaseFirestore.instance
        .collection('scambi_cid')
        .doc(idDaAscoltare)
        .snapshots()
        .listen((snapshot) async {

      if (!snapshot.exists) {
        if (_ioHoApprovato) {
          _roomSubscription?.cancel();
          _roomSubscription = null;
          return;
        }
        if (!_staCancellando && !_cancellazioneAvviataDaMe && mounted) {
          _gestisciCancellazioneAltrui();
        }
        return;
      }

      final data = snapshot.data();
      if (data == null) return;

      if (data['status'] == 'retry') {
        if (!_cancellazioneAvviataDaMe) _gestisciCancellazioneAltrui();
        return;
      }

      bool appA = data['approved_A'] == true;
      bool appB = data['approved_B'] == true;

      if (appA && appB) {
        if (mounted) {
          setState(() {
            _tuttiHannoApprovato = true;
            _ioHoApprovato = true;
            _statusText = "DATI APPROVATI!\nPDF creato procedi con il salvataggio sul dispositivo o invialo";
            _statusColor = Colors.green.shade800;
            _statusIcon = Icons.check_circle;
          });
          String? id = GlobalData.idSessione ?? GlobalData.idScambioTemporaneo;
          if (id != null) FirebaseFirestore.instance.collection('scambi_cid').doc(id).delete().catchError((_){});
        }
      }
      else if (_ioHoApprovato) {
        if (mounted) {
          setState(() {
            _statusText = "Hai approvato. In attesa dell'altro utente...";
            _statusColor = Colors.amber.shade800;
            _statusIcon = Icons.hourglass_top;
          });
        }
      }
    });
  }

  // ===========================================================================
  //                     GESTIONE CANCELLAZIONE
  // ===========================================================================

  Future<void> _eseguiPuliziaFirebase({required bool notificaAltri}) async {
    setState(() {
      _isLoading = true;
      _cancellazioneAvviataDaMe = true;
    });

    await _roomSubscription?.cancel();
    _roomSubscription = null;

    Set<String> idsDaCancellare = {};
    if (GlobalData.idScambioTemporaneo != null) idsDaCancellare.add(GlobalData.idScambioTemporaneo!);
    if (GlobalData.idSessione != null) idsDaCancellare.add(GlobalData.idSessione!);

    for (String id in idsDaCancellare) {
      if (notificaAltri) {
        try {
          await FirebaseFirestore.instance.collection('scambi_cid').doc(id).update({'status': 'retry'})
              .timeout(const Duration(seconds: 2));
          await Future.delayed(const Duration(milliseconds: 300));
        } catch (_) {}
      }
      try {
        await FirebaseFirestore.instance.collection('scambi_cid').doc(id).delete();
      } catch (_) {}
    }
  }

  Future<void> _tornaIndietroConPulizia() async {
    await _eseguiPuliziaFirebase(notificaAltri: true);
    _resetDatiLocali();

    if (mounted) {
      setState(() => _isLoading = false);
      if (GlobalData.latoCorrente == 'A') {
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
      } else {
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
      }
    }
  }

  Future<void> _ioApprovo() async {
    String? id = GlobalData.idSessione ?? GlobalData.idScambioTemporaneo;
    if (id != null) {
      try {
        String field = (GlobalData.latoCorrente == 'A') ? 'approved_A' : 'approved_B';
        await FirebaseFirestore.instance.collection('scambi_cid').doc(id).update({field: true});
      } catch (_) {}
    }

    if (mounted) {
      setState(() {
        _ioHoApprovato = true;
      });
    }
  }

  Future<void> _concludiEHome() async {
    await _eseguiPuliziaFirebase(notificaAltri: false);
    GlobalData.reset();
    await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    if (mounted) {
      Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (c) => const HomeScreen()), (r) => false);
    }
  }

  void _resetDatiLocali() {
    if (GlobalData.latoCorrente == 'A') GlobalData.resetB(); else GlobalData.resetA();
    GlobalData.idScambioTemporaneo = null;
    GlobalData.idSessione = null;
  }

  void _gestisciCancellazioneAltrui() {
    _roomSubscription?.cancel();
    _roomSubscription = null;

    if (mounted) {
      // Chiude eventuali altri dialoghi aperti (es. quello dell'anteprima)
      Navigator.of(context).popUntil((route) => route.isFirst || route.settings.name == null);

      showDialog(
        context: context,
        barrierDismissible: false, // L'utente DEVE premere il tasto
        builder: (ctx) => AlertDialog(
          // 1. Forma moderna con angoli molto arrotondati
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
          backgroundColor: Colors.white,
          surfaceTintColor: Colors.transparent, // Evita tinte strane su Material 3

          // 2. Icona grande in cima al titolo
          icon: Icon(
              Icons.warning_amber_rounded,
              size: 60,
              color: Colors.amber.shade800
          ),
          iconPadding: const EdgeInsets.only(top: 24, bottom: 16),

          // 3. Titolo in grassetto
          title: Text(
              "Attenzione",
              textAlign: TextAlign.center,
              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 22,
                  color: Colors.amber.shade900
              )
          ),

          // 4. Contenuto con il tuo testo, centrato e leggibile
          content: const Padding(
            padding: EdgeInsets.symmetric(vertical: 8.0),
            child: Text(
              "L'altro utente ha deciso di modificare i propri dati o non ha accettato i tuoi.\n\nSarai riportato alla schermata iniziale dove potrai eventualmente apporre modifiche.",
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 16, height: 1.4, color: Colors.black87),
            ),
          ),

          // 5. Spaziatura azioni
          actionsPadding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
          actions: [
            // 6. Pulsante moderno full-width
            SizedBox(
              width: double.infinity, // Occupa tutta la larghezza
              child: ElevatedButton(
                  onPressed: () {
                    Navigator.pop(ctx); // Chiude il dialog
                    _resetDatiLocali(); // Pulisce la RAM
                    // Torna alla schermata di input corretta
                    if (GlobalData.latoCorrente == 'A') {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
                    } else {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
                    }
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.amber.shade800, // Colore coerente con l'icona
                    foregroundColor: Colors.white,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
                    elevation: 0, // Look più piatto e moderno
                  ),
                  child: const Text(
                      "HO CAPITO",
                      style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)
                  )
              ),
            )
          ],
        ),
      );
    }
  }

  Future<void> _generaDocumenti() async {
    if (!mounted) return;
    setState(() => _isLoading = true);
    try {
      final List<int> pdfBytes = await PdfEngine.generaDocumentoCai();
      if (pdfBytes.isEmpty) throw Exception("PDF vuoto");
      final tempDir = await getTemporaryDirectory();
      final file = File('${tempDir.path}/CID_${DateTime.now().millisecondsSinceEpoch}.pdf');
      await file.writeAsBytes(pdfBytes, flush: true);
      Uint8List? anteprima;
      await for (final page in Printing.raster(Uint8List.fromList(pdfBytes), pages: [0], dpi: 150)) {
        anteprima = await page.toPng(); break;
      }
      if (mounted) {
        setState(() { _filePdfReale = file; _immagineAnteprima = anteprima; _isLoading = false; });
      }
    } catch (e) {
      if (mounted) setState(() => _isLoading = false);
    }
  }

  Future<void> _vaiAScambioDati() async {
    await Navigator.push(context, MaterialPageRoute(builder: (context) => const ScambioDatiScreen()));
    _verificaStatoPostScambio();
  }

  void _apriAnteprimaSchermoIntero() {
    if (!_scambioEffettuato || !_datiPresenti || _immagineAnteprima == null || _filePdfReale == null) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Dati non pronti!")));
      return;
    }
    Navigator.push(context, MaterialPageRoute(builder: (context) => ImageViewerScreen(
        imageBytes: _immagineAnteprima!,
        pdfFile: _filePdfReale!,
        isAlreadyApproved: _ioHoApprovato,
        onConfirmCorrection: _tornaIndietroConPulizia,
        onConfirmApproval: _ioApprovo
    )));
  }

  Future<void> _inviaMailConAllegato(BuildContext context) async {
    if (_filePdfReale == null) return;
    try {
      bool isA = GlobalData.latoCorrente == 'A';
      String polizzaChiScrive = (isA ? GlobalData.Numero_Polizza_A : GlobalData.Numero_Polizza_B).trim();
      String targaChiScrive = (isA ? GlobalData.Targa_A : GlobalData.Targa_B).trim();
      String firmaChiScrive = "${isA ? GlobalData.Nome_contraente_A : GlobalData.Nome_contraente_B} ${isA ? GlobalData.Cognome_contraente_A : GlobalData.Cognome_contraente_B}";
      String contattoChiScrive = (isA ? GlobalData.N_telefono_mail_contraente_A : GlobalData.N_telefono_mail_contraente_B).trim();

      String compagniaUtente = (isA ? GlobalData.Denominazione_A : GlobalData.Denominazione_B).trim().toUpperCase();
      String emailDestinatario = "";

      if (GlobalData.assicurazioni.containsKey(compagniaUtente)) {
        emailDestinatario = GlobalData.assicurazioni[compagniaUtente]!;
      } else {
        for (var key in GlobalData.assicurazioni.keys) {
          if (key.isNotEmpty && (compagniaUtente.contains(key) || key.contains(compagniaUtente))) {
            emailDestinatario = GlobalData.assicurazioni[key]!;
            break;
          }
        }
      }

      List<String> listaCC = [];
      if (contattoChiScrive.contains("@")) listaCC.add(contattoChiScrive);

      String oggetto = "DENUNCIA SINISTRO - Polizza n. $polizzaChiScrive - Targa $targaChiScrive";
      String corpo = "Spett.le Compagnia,\n\n"
          "Con la presente inoltro in allegato il modulo CAI relativo al sinistro avvenuto in data ${GlobalData.data_incidente} alle ore ${GlobalData.ora} nel comune di ${GlobalData.luogo}.\n\n"
          "Rimaniamo in attesa dell'apertura del fascicolo.\n\n"
          "Cordiali saluti,\n$firmaChiScrive\nContatto: $contattoChiScrive";

      final Email email = Email(
        subject: oggetto,
        body: corpo,
        recipients: emailDestinatario.isNotEmpty ? [emailDestinatario] : [],
        cc: listaCC,
        attachmentPaths: [_filePdfReale!.path],
        isHTML: false,
      );

      await FlutterEmailSender.send(email);
    } catch (e) {
      if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Errore mail: $e")));
    }
  }

  Future<void> _salvaPdfLocale(BuildContext context) async {
    if (_filePdfReale == null) return;
    await Share.shareXFiles([XFile(_filePdfReale!.path, mimeType: 'application/pdf')], subject: 'Modulo CAI', text: 'Ecco il modulo CAI compilato.');
  }

  @override
  void dispose() {
    _roomSubscription?.cancel();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool pdfPronto = !_isLoading && _filePdfReale != null && _immagineAnteprima != null;
    bool abilitaAnteprima = _scambioEffettuato && _datiPresenti && pdfPronto;
    bool abilitaFinali = _tuttiHannoApprovato && pdfPronto;

    String testoAnteprima = !_scambioEffettuato ? "2. ANTEPRIMA (Prima fai Scambio)" :
    (_ioHoApprovato ? "ANTEPRIMA (IN ATTESA...)" : "2. APRI ANTEPRIMA E APPROVA");
    if (_tuttiHannoApprovato) testoAnteprima = "ANTEPRIMA (COMPLETATA)";

    return PopScope(
      canPop: false,
      onPopInvoked: (didPop) async {
        if (didPop) return;
        if (_ioHoApprovato) _concludiEHome(); else _tornaIndietroConPulizia();
      },
      child: Scaffold(
        extendBodyBehindAppBar: true,
        appBar: AppBar(
          title: const Text("Invio e Salvataggio", style: TextStyle(fontWeight: FontWeight.w800, fontSize: 20)),
          centerTitle: true,
          backgroundColor: Colors.blue.shade900.withOpacity(0.95),
          foregroundColor: Colors.white,
          elevation: 10,
          leading: IconButton(
              icon: const Icon(Icons.arrow_back),
              onPressed: _ioHoApprovato ? _concludiEHome : _tornaIndietroConPulizia
          ),
          shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(20))),
        ),
        body: Stack(children: [
          Positioned.fill(child: Comp16BackgroundImage()),
          SafeArea(child: SingleChildScrollView(padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20), child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [

            _buildStatusCard(),

            const SizedBox(height: 20),

            _btn("1. SCAMBIO DATI (QR CODE)", Icons.qr_code_scanner, Colors.orange.shade800, onTap: _vaiAScambioDati, disabled: _ioHoApprovato),

            const SizedBox(height: 20),

            _btn(testoAnteprima, Icons.visibility, _statusColor, onTap: abilitaAnteprima ? _apriAnteprimaSchermoIntero : null, disabled: !abilitaAnteprima),

            const SizedBox(height: 8),
            Divider(color: Colors.white.withOpacity(0.5), thickness: 1),
            const SizedBox(height: 8),

            Builder(builder: (ctx) => _btn("SALVA SUL DISPOSITIVO", Icons.save_alt, Colors.green.shade700, onTap: abilitaFinali ? () => _salvaPdfLocale(ctx) : null, disabled: !abilitaFinali)),

            const SizedBox(height: 20),

            Builder(builder: (ctx) => _btn("INVIA ALL'ASSICURAZIONE", Icons.send_rounded, Colors.green.shade700, onTap: abilitaFinali ? () => _inviaMailConAllegato(ctx) : null, disabled: !abilitaFinali)),

            const SizedBox(height: 40),

            _btn(
                _tuttiHannoApprovato ? "TORNA ALLA HOME" : "CANCELLA TUTTO E ESCI",
                _tuttiHannoApprovato ? Icons.home : Icons.delete_sweep,
                _tuttiHannoApprovato ? Colors.green.shade800 : Colors.red.shade900,
                onTap: _tuttiHannoApprovato ? _concludiEHome : _tornaIndietroConPulizia,
                disabled: false
            ),

            const SizedBox(height: 30)
          ]))),

          if (_isLoading)
            Container(color: Colors.black54, child: const Center(child: Column(mainAxisSize: MainAxisSize.min, children: [CircularProgressIndicator(color: Colors.white), SizedBox(height: 20), Text("Elaborazione in corso...", style: TextStyle(color: Colors.white))]))),
        ]),
      ),
    );
  }

  Widget _btn(String label, IconData icon, Color color, {VoidCallback? onTap, bool disabled = false}) {
    bool on = onTap != null && !disabled;
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        boxShadow: on ? [BoxShadow(color: Colors.black.withOpacity(0.3), offset: const Offset(0, 4), blurRadius: 5)] : [],
      ),
      child: ElevatedButton(
          onPressed: on ? onTap : null,
          style: ElevatedButton.styleFrom(
            backgroundColor: on ? color : Colors.grey,
            foregroundColor: Colors.white,
            padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20),
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          ),
          child: Row(children: [
            Icon(icon, size: 28), const SizedBox(width: 20),
            Expanded(child: Text(label, textAlign: TextAlign.center, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
            Icon(Icons.lock, size: 20, color: Colors.transparent)
          ])
      ),
    );
  }

  Widget _buildStatusCard() {
    return Container(
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(16), border: Border.all(color: _statusColor, width: 2), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 6, offset: const Offset(0, 3))]),
        child: Row(children: [
          Icon(_statusIcon, color: _statusColor, size: 36), const SizedBox(width: 15),
          Expanded(child: Text(_statusText, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: _statusColor)))
        ])
    );
  }
}

// Widget Sfondo Modificato: Ingrandito (1.3x) e Spostato in basso (+100px)
class Comp16BackgroundImage extends StatelessWidget {
  const Comp16BackgroundImage({super.key});
  @override
  Widget build(BuildContext context) {
    return Container(
      height: double.infinity,
      width: double.infinity,
      color: const Color(0xFFF0F4F8),
      child: Transform.translate(
        offset: const Offset(0, 100), // Sposta in basso di 100px
        child: Transform.scale(
          scale: 1.3, // Ingrandisce del 30%
          child: Image.asset(
            'assets/sfondo_mappa.jpg',
            fit: BoxFit.cover,
            alignment: Alignment.center, // Centrale per zoomare uniforme
            color: const Color(0xFFF0F4F8).withOpacity(0.6),
            colorBlendMode: BlendMode.lighten,
            errorBuilder: (c, e, s) => Container(color: Colors.grey.shade200),
          ),
        ),
      ),
    );
  }
}

class ImageViewerScreen extends StatelessWidget {
  final Uint8List imageBytes;
  final File pdfFile;
  final bool isAlreadyApproved;
  final Function onConfirmCorrection;
  final Function onConfirmApproval;

  const ImageViewerScreen({super.key, required this.imageBytes, required this.pdfFile, required this.isAlreadyApproved, required this.onConfirmCorrection, required this.onConfirmApproval});

  Future<void> _askCorrection(BuildContext context) async {
    String titolo = isAlreadyApproved ? "Chiudere?" : "Richiedere correzione?";
    String testo = isAlreadyApproved
        ? "Hai già approvato. Uscendo tornerai alla schermata precedente in attesa dell'altro utente."
        : "Questo annullerà lo scambio per entrambi e vi riporterà alla modifica.";
    String tasto = isAlreadyApproved ? "CHIUDI" : "CORREGGI";

    bool? conf = await showDialog(context: context, builder: (c) => AlertDialog(
        title: Text(titolo),
        content: Text(testo),
        actions: [
          TextButton(onPressed: () => Navigator.pop(c, false), child: const Text("ANNULLA")),
          ElevatedButton(onPressed: () => Navigator.pop(c, true), child: Text(tasto))
        ]
    ));
    if (conf == true) {
      Navigator.pop(context);
      if (!isAlreadyApproved) onConfirmCorrection();
    }
  }

  Future<void> _askApproval(BuildContext context) async { Navigator.pop(context); onConfirmApproval(); }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: const Text("Verifica Dati"), backgroundColor: Colors.black, foregroundColor: Colors.white),
      body: Column(children: [
        Expanded(child: InteractiveViewer(minScale: 0.5, maxScale: 4.0, child: Center(child: Container(color: Colors.white, child: Image.memory(imageBytes, fit: BoxFit.contain))))),
        Container(
          padding: const EdgeInsets.all(16.0),
          decoration: BoxDecoration(color: Colors.white, boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10, offset: const Offset(0, -2))]),
          child: SafeArea(
            child: Row(children: [
              Expanded(
                child: ElevatedButton.icon(
                  onPressed: () => _askCorrection(context),
                  icon: Icon(isAlreadyApproved ? Icons.arrow_back : Icons.edit),
                  label: Text(isAlreadyApproved ? "INDIETRO" : "CORREGGI"),
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.orange.shade800, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: ElevatedButton.icon(
                  onPressed: isAlreadyApproved ? null : () => _askApproval(context),
                  icon: isAlreadyApproved ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.check_circle),
                  label: Text(isAlreadyApproved ? "IN ATTESA..." : "APPROVA"),
                  style: ElevatedButton.styleFrom(backgroundColor: isAlreadyApproved ? Colors.grey : Colors.green.shade700, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
                ),
              ),
            ]),
          ),
        )
      ]),
    );
  }
}
=== FILE: lib/global_data.dart ===
import 'dart:ui';
import 'package:cid_app/models.dart';

class GlobalData {
  // --- VARIABILI DI SESSIONE ---
  static String latoCorrente = 'A';
  static String? idScambioTemporaneo;
  static String? chiaveSegretaCorrente;
  static String? idSessione;

  // --- DATI GENERALI (NON CANCELLATI DAI RESET PARZIALI) ---
  static String data_incidente = "";
  static String ora = "";
  static String luogo = "";
  static String testimoni = "";
  static bool feriti = false;
  static bool Veicoli_danni_materiali_oltre = false;
  static bool Oggetti_diversi_danni_materiali = false;

  // --- DATI LATO A (BLU) ---
  static String Cognome_contraente_A = ""; static String Nome_contraente_A = ""; static String Codice_Fiscale_contraente_A = ""; static String Indirizzo_contraente_A = ""; static String CAP_contraente_A = ""; static String Stato_contraente_A = ""; static String N_telefono_mail_contraente_A = "";
  static String Marca_e_Tipo_A = ""; static String Targa_A = ""; static String Stato_immatricolazione_A = ""; static String Rimorchio_A = ""; static String Stato_immatricolazione2_A = "";
  static String Denominazione_A = ""; static String Numero_Polizza_A = ""; static String N_carta_verde_A = ""; static String Data_Inizio_Dal_A = ""; static String Data_Scadenza_Al_A = ""; static String Agenzia_A = ""; static String Denominazione_agenzia_A = ""; static String Indirizzo_agenzia_A = ""; static String Stato_agenzia_A = ""; static String N_tel_mail_agenzia_A = ""; static bool FLAG_danni_mat_assicurati_A = false;
  static String Cognome_cond_A = ""; static String Nome_cond_A = ""; static String Data_nascita_cond_A = ""; static String Cod_fiscale_cond_A = ""; static String Indirizzo_cond_A = ""; static String Stato_cond_A = ""; static String N_tel_mail_cond_A = ""; static String N_Patente_cond_A = ""; static String Scadenza_cond_A = ""; static String Categoria_cond_A = "";
  static List<String> puntiUrtoA_List = []; static String danni_visibili_A = ""; static String osservazioni_A = ""; static Map<int, bool> circostanzeA = {}; static int totaleCrocetteA = 0; static List<Offset?> puntiFirmaA = [];

  // --- DATI LATO B (GIALLO) ---
  static String Cognome_contraente_B = ""; static String Nome_contraente_B = ""; static String Codice_Fiscale_contraente_B = ""; static String Indirizzo_contraente_B = ""; static String CAP_contraente_B = ""; static String Stato_contraente_B = ""; static String N_telefono_mail_contraente_B = "";
  static String Marca_e_Tipo_B = ""; static String Targa_B = ""; static String Stato_immatricolazione_B = ""; static String Rimorchio_B = ""; static String Stato_immatricolazione2_B = "";
  static String Denominazione_B = ""; static String Numero_Polizza_B = ""; static String N_carta_verde_B = ""; static String Data_Inizio_Dal_B = ""; static String Data_Scadenza_Al_B = ""; static String Agenzia_B = ""; static String Denominazione_agenzia_B = ""; static String Indirizzo_agenzia_B = ""; static String Stato_agenzia_B = ""; static String N_tel_mail_agenzia_B = ""; static bool FLAG_danni_mat_assicurati_B = false;
  static String Cognome_cond_B = ""; static String Nome_cond_B = ""; static String Data_nascita_cond_B = ""; static String Cod_fiscale_cond_B = ""; static String Indirizzo_cond_B = ""; static String Stato_cond_B = ""; static String N_tel_mail_cond_B = ""; static String N_Patente_cond_B = ""; static String Scadenza_cond_B = ""; static String Categoria_cond_B = "";
  static List<String> puntiUrtoB_List = []; static String danni_visibili_B = ""; static String osservazioni_B = ""; static Map<int, bool> circostanzeB = {}; static int totaleCrocetteB = 0; static List<Offset?> puntiFirmaB = [];

  // --- DATI GRAFICI ---
  static List<dynamic> tratti = [];
  static List<dynamic> elementi = [];

  static Map<String, String> assicurazioni = {
    "AEGON": "aegon@pec.aegon.it",
    "AIG EUROPE": "insurance@aigeurope.postecert.it",
    "AIG LIFE": "aiglifestabile@pec.it",
    "ALLIANZ": "allianz.spa@pec.allianz.it",
    "ALLIANZ DIRECT": "allianzdirect@pec.allianzdirect.it",
    "ALLEANZA": "alleanza@pec.alleanza.it",
    "AMISSIMA": "amissima@pec.it",
    "AMTRUST ASSICURAZIONI": "amtrust.assicurazioni@pec.it",
    "ARAG": "arag@legalmail.it",
    "ARCA": "arcaassicurazioni@pec.unipol.it",
    "ASSICURATRICE MILANESE": "assicuratricemilanese@legalmail.it",
    "ASSIMOCO": "assimoco@legalmail.it",
    "ATHORA ITALIA": "athoraitalia@legalmail.it",
    "AVIVA": "aviva@pec.aviva.it",
    "AXA": "axaassicurazioni@axa.legalmail.it",
    "BCC ASSICURAZIONI": "bccassicurazioni@pec.it",
    "BCC VITA": "bccvita@legalmail.it",
    "BENE ASSICURAZIONI": "beneassicurazioni@legalmail.it",
    "BEREBEL": "berebel@pec.unipol.it",
    "BNP PARIBAS CARDIF": "cardif.assicurazioni@pec.bnpparibas.com",
    "CARIGE ASSICURAZIONI": "carigeassicurazioni@pec.it",
    "CATTOLICA": "cattolica.assicurazioni@pec.gruppocattolica.it",
    "CF ASSICURAZIONI": "cfassicurazioni@pec.it",
    "CHUBB": "chubb.italy@pec.chubb.com",
    "CNP VITA ASSICURA": "cnpvitaassicura@pec.it",
    "CONTE.IT": "admiralinteractive@legalmail.it",
    "CREDIT AGRICOLE": "creditagricoleassicurazioni@pec.ca-assurances.it",
    "CRONOS VITA": "cronosvita@legalmail.it",
    "DARAG ITALIA": "darag.italia@legalmail.it",
    "DAS": "das@legalmail.it",
    "DONAU": "donau@pec.it",
    "ERGO ASSICURAZIONI": "ergoassicurazioni@legalmail.it",
    "EUROHERC": "euroherc@legalmail.it",
    "EUROP ASSISTANCE": "europassistance@pec.europassistance.it",
    "FIDEURAM VITA": "fideuramvita@pec.fideuram.it",
    "GENERALI ITALIA": "generaliitalia@pec.generaligroup.com",
    "GENERTEL": "genertel@pec.genertel.it",
    "GIOTTO ASSICURAZIONI": "giottoassicurazioni@pec.it",
    "GLOBAL ASSISTANCE": "globalassistancespa@legalmail.it",
    "GREAT LAKES": "greatlakes@legalmail.it",
    "GROUPAMA": "groupama@legalmail.it",
    "HDI": "hdi.assicurazioni@pec.hdia.it",
    "HELVETIA": "helvetia@actaliscertymail.it",
    "INCONTRA ASSICURAZIONI": "incontraassicurazioni@pec.it",
    "INTESA SANPAOLO": "intesasanpaoloassicura@pec.intesasanpaolo.com",
    "INTESA SANPAOLO RBM SALUTE": "rbmsalute@pec.rbmsalute.it",
    "ITALIANA ASSICURAZIONI": "italiana@pec.italiana.it",
    "ITAS": "itas.mutua@pec-gruppoitas.it",
    "LINEAR": "linear@pec.unipol.it",
    "MAPFRE": "mapfreassicurazioni@pec.it",
    "MEDIOLANUM ASSICURAZIONI": "mediolanumassicurazioni@pec.mediolanum.it",
    "METLIFE": "metlife@pec.metlife.it",
    "NET INSURANCE": "netinsurance@legalmail.it",
    "NOBIS ASSICURAZIONI": "nobisassicurazioni@pec.it",
    "POSTE ASSICURA": "posteassicura@pec.posteassicura.it",
    "POSTE VITA": "postevita@pec.postevita.it",
    "PRIMA.IT": "prima@pec.prima.it",
    "QBE INSURANCE": "qbeitaly@pec.qbe.com",
    "QUIXA": "quixa.assicurazioni@legalmail.it",
    "REALE MUTUA": "realemutua@pec.realemutua.it",
    "SARA": "saraassicurazioni@sara.telecompost.it",
    "SOGESSUR": "sogessur@pec.it",
    "SWISS RE": "swissre@pec.swissre.com",
    "TELEPASS ASSICURA": "telepassassicura@pec.telepass.com",
    "TOKIO MARINE EUROPE": "tokiomareineeurope@legalmail.it",
    "TUA": "tuaassicurazioni@pec.it",
    "UNIQA": "uniqa@pec.uniqa.it",
    "UNIPOLSAI": "unipolsaiassicurazioni@pec.unipol.it",
    "VERTI": "verti@pec.verti.it",
    "VIENNA INSURANCE (WIENER)": "wieneritalia@legalmail.it",
    "VITTORIA": "vittoriaassicurazioni@pec.vittoriaassicurazioni.it",
    "WAKAM": "wakam@pec.it",
    "XL INSURANCE": "xlinsurance@legalmail.it",
    "ZURICH": "zurich.insurance.company@pec.zurich.it",
    "ALTRO (Inserimento manuale)": ""
  };

  // --- RESET TOTALE ---
  static void reset() {
    latoCorrente = 'A';
    data_incidente = ""; ora = ""; luogo = ""; testimoni = ""; feriti = false;
    Veicoli_danni_materiali_oltre = false; Oggetti_diversi_danni_materiali = false;
    resetA();
    resetB();
    elementi = []; tratti = [];
    idSessione = null; chiaveSegretaCorrente = null; idScambioTemporaneo = null;
  }

  // --- RESET PARZIALE ---
  static void resetSoloLatoOpposto() {
    if (latoCorrente == 'A') {
      resetB();
    } else {
      resetA();
    }
    idScambioTemporaneo = null;
    chiaveSegretaCorrente = null;
  }

  static void resetA() {
    Cognome_contraente_A = ""; Nome_contraente_A = ""; Codice_Fiscale_contraente_A = ""; Indirizzo_contraente_A = ""; CAP_contraente_A = ""; Stato_contraente_A = ""; N_telefono_mail_contraente_A = "";
    Marca_e_Tipo_A = ""; Targa_A = ""; Stato_immatricolazione_A = ""; Rimorchio_A = ""; Stato_immatricolazione2_A = "";
    Denominazione_A = ""; Numero_Polizza_A = ""; N_carta_verde_A = ""; Data_Inizio_Dal_A = ""; Data_Scadenza_Al_A = ""; Agenzia_A = ""; Denominazione_agenzia_A = ""; Indirizzo_agenzia_A = ""; Stato_agenzia_A = ""; N_tel_mail_agenzia_A = ""; FLAG_danni_mat_assicurati_A = false;
    Cognome_cond_A = ""; Nome_cond_A = ""; Data_nascita_cond_A = ""; Cod_fiscale_cond_A = ""; Indirizzo_cond_A = ""; Stato_cond_A = ""; N_tel_mail_cond_A = ""; N_Patente_cond_A = ""; Scadenza_cond_A = ""; Categoria_cond_A = "";
    puntiUrtoA_List = []; danni_visibili_A = ""; osservazioni_A = ""; circostanzeA = {}; totaleCrocetteA = 0; puntiFirmaA = [];
  }

  static void resetB() {
    Cognome_contraente_B = ""; Nome_contraente_B = ""; Codice_Fiscale_contraente_B = ""; Indirizzo_contraente_B = ""; CAP_contraente_B = ""; Stato_contraente_B = ""; N_telefono_mail_contraente_B = "";
    Marca_e_Tipo_B = ""; Targa_B = ""; Stato_immatricolazione_B = ""; Rimorchio_B = ""; Stato_immatricolazione2_B = "";
    Denominazione_B = ""; Numero_Polizza_B = ""; N_carta_verde_B = ""; Data_Inizio_Dal_B = ""; Data_Scadenza_Al_B = ""; Agenzia_B = ""; Denominazione_agenzia_B = ""; Indirizzo_agenzia_B = ""; Stato_agenzia_B = ""; N_tel_mail_agenzia_B = ""; FLAG_danni_mat_assicurati_B = false;
    Cognome_cond_B = ""; Nome_cond_B = ""; Data_nascita_cond_B = ""; Cod_fiscale_cond_B = ""; Indirizzo_cond_B = ""; Stato_cond_B = ""; N_tel_mail_cond_B = ""; N_Patente_cond_B = ""; Scadenza_cond_B = ""; Categoria_cond_B = "";
    puntiUrtoB_List = []; danni_visibili_B = ""; osservazioni_B = ""; circostanzeB = {}; totaleCrocetteB = 0; puntiFirmaB = [];
  }

  // --- DEBUG COMPLETO (Tutti i campi popolati) ---
  static void popolaDatiDiTest() {
    idScambioTemporaneo = null;

    // Header
    data_incidente = "01/01/2024"; ora = "12:30"; luogo = "ROMA, VIA DEL CORSO 10"; testimoni = "SIG. BIANCHI GIOVANNI, VIA VERDI 5, MILANO";
    feriti = false; Veicoli_danni_materiali_oltre = false; Oggetti_diversi_danni_materiali = true;

    if (latoCorrente == 'A') {
      // Dati A
      Cognome_contraente_A = "ROSSI"; Nome_contraente_A = "MARIO"; Codice_Fiscale_contraente_A = "RSSMRA80A01H501U"; Indirizzo_contraente_A = "VIA ROMA 1"; CAP_contraente_A = "00100"; Stato_contraente_A = "ITALIA"; N_telefono_mail_contraente_A = "333.1234567";
      Marca_e_Tipo_A = "FIAT PANDA"; Targa_A = "AA123AA"; Stato_immatricolazione_A = "IT"; Rimorchio_A = ""; Stato_immatricolazione2_A = "";
      Denominazione_A = "GENERALI"; Numero_Polizza_A = "123456"; N_carta_verde_A = "CV-001"; Data_Inizio_Dal_A = "01/01/2023"; Data_Scadenza_Al_A = "01/01/2024";
      Agenzia_A = "ROMA"; Denominazione_agenzia_A = "AG. CENTRALE"; Indirizzo_agenzia_A = "VIA PO 20"; Stato_agenzia_A = "IT"; N_tel_mail_agenzia_A = "ag@mail.it"; FLAG_danni_mat_assicurati_A = true;
      Cognome_cond_A = "ROSSI"; Nome_cond_A = "MARIO"; Data_nascita_cond_A = "01/01/1980"; Cod_fiscale_cond_A = "RSSMRA80"; Indirizzo_cond_A = "VIA ROMA 1"; Stato_cond_A = "IT"; N_tel_mail_cond_A = "333.1234567";
      N_Patente_cond_A = "PAT-001"; Scadenza_cond_A = "01/01/2030"; Categoria_cond_A = "B";
      puntiUrtoA_List = ["Anteriore"]; danni_visibili_A = "PARAURTI ROTTO"; osservazioni_A = "RAGIONE PIENA"; circostanzeA = {1:true};
      puntiFirmaA = [const Offset(0,0), const Offset(10,10)];
      tratti = [TrattoPenna([const Offset(10,10), const Offset(100,100)], tipo: 'penna')];
      resetB();
    } else {
      // Dati B
      Cognome_contraente_B = "VERDI"; Nome_contraente_B = "LUIGI"; Codice_Fiscale_contraente_B = "VRDLGU90B02F205Z"; Indirizzo_contraente_B = "MILANO"; CAP_contraente_B = "20100"; Stato_contraente_B = "ITALIA"; N_telefono_mail_contraente_B = "340.9876543";
      Marca_e_Tipo_B = "FORD FIESTA"; Targa_B = "BB987BB"; Stato_immatricolazione_B = "IT"; Rimorchio_B = ""; Stato_immatricolazione2_B = "";
      Denominazione_B = "ALLIANZ"; Numero_Polizza_B = "987654"; N_carta_verde_B = "CV-002"; Data_Inizio_Dal_B = "01/01/2023"; Data_Scadenza_Al_B = "01/01/2024";
      Agenzia_B = "MILANO"; Denominazione_agenzia_B = "AG. NORD"; Indirizzo_agenzia_B = "VIA DANTE 1"; Stato_agenzia_B = "IT"; N_tel_mail_agenzia_B = "mi@mail.it"; FLAG_danni_mat_assicurati_B = false;
      Cognome_cond_B = "VERDI"; Nome_cond_B = "LUIGI"; Data_nascita_cond_B = "02/02/1990"; Cod_fiscale_cond_B = "VRDLGU90"; Indirizzo_cond_B = "MILANO"; Stato_cond_B = "IT"; N_tel_mail_cond_B = "340.9876543";
      N_Patente_cond_B = "PAT-002"; Scadenza_cond_B = "02/02/2030"; Categoria_cond_B = "B";
      puntiUrtoB_List = ["Posteriore"]; danni_visibili_B = "PARAURTI POST ROTTO"; osservazioni_B = "NON HO VISTO"; circostanzeB = {12:true};
      puntiFirmaB = [const Offset(0,0), const Offset(10,10)];
      resetA();
    }
  }
}
=== FILE: lib/firebase_exchange.dart ===
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:math';
import 'dart:async';
import 'cid_data_manager.dart';
import 'global_data.dart';

class FirebaseExchange {
  static final FirebaseFirestore _db = FirebaseFirestore.instance;
  static const String collectionName = 'scambi_cid';

  // --- LATO CHE GENERA IL QR (Host) ---
  static Future<Map<String, dynamic>> avviaSessioneRealTime() async {
    String sessionId = _generaCodiceUnivoco();
    String mioLato = GlobalData.latoCorrente;

    // Estrazione dati
    Map<String, dynamic> mieiDati = CidDataManager.estraiDatiPerExport();

    Map<String, dynamic> payload = {
      'created_at': FieldValue.serverTimestamp(),
      'expires_at': DateTime.now().add(const Duration(minutes: 10)).millisecondsSinceEpoch,
      'dati_$mioLato': mieiDati,
    };

    // Scrittura su Firebase
    await _db.collection(collectionName).doc(sessionId).set(payload);

    return {
      'sessionId': sessionId,
      'stream': _db.collection(collectionName).doc(sessionId).snapshots()
    };
  }

  // --- LATO CHE SCANSIONA (Guest) ---
  static Future<bool> completaScambio(String sessionId) async {
    try {
      sessionId = sessionId.trim().toUpperCase();
      DocumentReference docRef = _db.collection(collectionName).doc(sessionId);
      DocumentSnapshot doc = await docRef.get();

      if (!doc.exists) return false;

      Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
      String mioLato = GlobalData.latoCorrente;
      String latoAltro = mioLato == 'A' ? 'B' : 'A';

      // 1. Importo i dati dell'altro
      if (data['dati_$latoAltro'] != null) {
        CidDataManager.importaDati(data['dati_$latoAltro']);
      } else {
        return false;
      }

      // 2. Invio i miei dati per completare lo scambio
      Map<String, dynamic> mieiDati = CidDataManager.estraiDatiPerExport();

      await docRef.update({
        'dati_$mioLato': mieiDati
      });

      return true;
    } catch (e) {
      print("Errore durante lo scambio: $e");
      return false;
    }
  }

  static String _generaCodiceUnivoco() {
    const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    Random rnd = Random();
    return String.fromCharCodes(Iterable.generate(
        6, (_) => chars.codeUnitAt(rnd.nextInt(chars.length))));
  }
}
=== FILE: lib/security_service.dart ===
// FILE: lib/security_service.dart
import 'package:encrypt/encrypt.dart' as encrypt;
import 'dart:convert';
import 'dart:math';

class SecurityService {

  // 1. GENERATORE DI CHIAVI
  static String generaChiaveSessione() {
    const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
    Random rnd = Random.secure();
    return String.fromCharCodes(Iterable.generate(32, (_) => chars.codeUnitAt(rnd.nextInt(chars.length))));
  }

  // 2. CRIPTAZIONE
  static String criptaDati(Map<String, dynamic> dati, String chiaveSegreta) {
    try {
      final key = encrypt.Key.fromUtf8(chiaveSegreta);
      final iv = encrypt.IV.fromLength(16);
      final encrypter = encrypt.Encrypter(encrypt.AES(key));

      String jsonString = jsonEncode(dati);
      final encrypted = encrypter.encrypt(jsonString, iv: iv);

      return "${iv.base64}:${encrypted.base64}";
    } catch (e) {
      return "Errore Criptazione: $e";
    }
  }

  // 3. DECRIPTAZIONE
  static Map<String, dynamic> decriptaDati(String pacchettoCriptato, String chiaveSegreta) {
    try {
      final parts = pacchettoCriptato.split(':');
      if (parts.length != 2) throw Exception("Formato dati non valido");

      final iv = encrypt.IV.fromBase64(parts[0]);
      final encryptedData = encrypt.Encrypted.fromBase64(parts[1]);

      final key = encrypt.Key.fromUtf8(chiaveSegreta);
      final encrypter = encrypt.Encrypter(encrypt.AES(key));

      final decrypted = encrypter.decrypt(encryptedData, iv: iv);
      return jsonDecode(decrypted);
    } catch (e) {
      return {"errore": "Impossibile decriptare: $e"};
    }
  }
}
=== FILE: lib/pdf_engine.dart ===
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/services.dart' show rootBundle;
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'package:flutter/material.dart';

import 'global_data.dart';
import 'models.dart';
import 'cai_mapping.dart';

class PdfEngine {

  static Future<List<int>> generaDocumentoCai() async {
    PdfDocument? document;
    try {
      final ByteData data = await rootBundle.load('assets/CAI_p1.pdf');

      // 1. Caricamento e Copia
      final List<int> bytesCopia = data.buffer.asUint8List().toList();
      document = PdfDocument(inputBytes: bytesCopia);

      final PdfForm form = document.form;
      final PdfPage page = document.pages[0];

      // form.setDefaultAppearance(false); // REMOVED to fix empty fields issue

      // Mappatura Campi
      Map<String, PdfField> mappaCampi = {};
      for (int i = 0; i < form.fields.count; i++) {
        if (form.fields[i].name != null) {
          mappaCampi[form.fields[i].name!.trim().toUpperCase()] = form.fields[i];
        }
      }

      // --- COMPILAZIONE ---

      // 1. TESTI STANDARD (Escludiamo i Danni per gestirli dopo con split a 20 char)
      CaiMapping.testi.forEach((keyGlobal, keyPdf) {
        if (keyGlobal.contains("danni_visibili")) return;

        String valore = _valoreDaGlobal(keyGlobal);
        String keyPdfNorm = keyPdf.trim().toUpperCase();

        if (mappaCampi.containsKey(keyPdfNorm) && valore.isNotEmpty) {
          final field = mappaCampi[keyPdfNorm];
          if (field is PdfTextBoxField) {
            field.font = PdfStandardFont(PdfFontFamily.helvetica, 8); // Font 8
            field.foreColor = PdfColor(0, 0, 0);
            field.textAlignment = PdfTextAlignment.left;
            field.text = valore.toUpperCase();
          }
        }
      });

      // 1.1 GESTIONE SPECIALE DANNI (Split forzato a 20 caratteri)
      _riempiCampoSplit(mappaCampi, GlobalData.danni_visibili_A, "DANNI_VIS_A1", "DANNI_VIS_A2");
      _riempiCampoSplit(mappaCampi, GlobalData.danni_visibili_B, "DANNI_VIS_B1", "DANNI_VIS_B2");


      // 2. CHECKBOX
      _scriviX(mappaCampi, [GlobalData.feriti ? CaiMapping.feriti_SI : CaiMapping.feriti_NO]);
      _scriviX(mappaCampi, [GlobalData.Veicoli_danni_materiali_oltre ? CaiMapping.danni_veicoli_SI : CaiMapping.danni_veicoli_NO]);
      _scriviX(mappaCampi, [GlobalData.Oggetti_diversi_danni_materiali ? CaiMapping.danni_oggetti_SI : CaiMapping.danni_oggetti_NO]);
      _scriviX(mappaCampi, [GlobalData.FLAG_danni_mat_assicurati_A ? CaiMapping.danni_mat_A_SI : CaiMapping.danni_mat_A_NO]);
      _scriviX(mappaCampi, [GlobalData.FLAG_danni_mat_assicurati_B ? CaiMapping.danni_mat_B_SI : CaiMapping.danni_mat_B_NO]);

      String catA = GlobalData.Categoria_cond_A.toUpperCase().trim();
      if (catA == 'A') _scriviX(mappaCampi, ['cat_a_A']);
      else if (catA == 'B') _scriviX(mappaCampi, ['cat_b_A']);
      else if (catA.isNotEmpty) _scriviTesto(mappaCampi, ['cat_altro_A'], catA);

      String catB = GlobalData.Categoria_cond_B.toUpperCase().trim();
      if (catB == 'A') _scriviX(mappaCampi, ['cat_a_B']);
      else if (catB == 'B') _scriviX(mappaCampi, ['cat_b_B']);
      else if (catB.isNotEmpty) _scriviTesto(mappaCampi, ['cat_altro_B'], catB);

      // 3. CIRCOSTANZE
      int countA = 0;
      int countB = 0;
      for (int i = 1; i <= 17; i++) {
        if (GlobalData.circostanzeA[i] == true) {
          if (_scriviX(mappaCampi, [i < 10 ? "A0$i" : "A$i"])) countA++;
        }
        if (GlobalData.circostanzeB[i] == true) {
          List<String> nomiTarget = [];
          if (i == 9) nomiTarget = ["Check Box 26", "CheckBox26", "26"];
          else if (i == 10) nomiTarget = ["Check Box 27", "CheckBox27", "27"];
          else if (i == 11) nomiTarget = ["Check Box 28", "CheckBox28", "28"];
          else if (i == 12) nomiTarget = ["Check Box 29", "CheckBox29", "29"];
          else nomiTarget = [i < 10 ? "B0$i" : "B$i"];
          if (_scriviX(mappaCampi, nomiTarget)) countB++;
        }
      }
      _scriviTestoTotale(mappaCampi, ['A_TOT', 'A_tot'], countA.toString());
      _scriviTestoTotale(mappaCampi, ['B_TOT', 'B_tot'], countB.toString());

      // 4. PUNTI URTO
      for (String punto in GlobalData.puntiUrtoA_List) _scriviXRossa(mappaCampi, [punto]);
      for (String punto in GlobalData.puntiUrtoB_List) _scriviXRossa(mappaCampi, [punto]);

      // 5. IMMAGINI E GRAFICO
      // Render the updated graph (with new vehicle types) to an image
      Uint8List? graficoBytes = await _renderGraficoV40(
          GlobalData.tratti.cast<TrattoPenna>().toList(),
          GlobalData.elementi.cast<ElementoGrafico>().toList()
      );

      // Draw the graph image into the specific PDF box
      await _disegnaInBox(page, mappaCampi, CaiMapping.box_grafico, graficoBytes);

      await _disegnaInBox(page, mappaCampi, CaiMapping.box_firma_A, await _renderFirmaTight(GlobalData.puntiFirmaA, Colors.black));
      await _disegnaInBox(page, mappaCampi, CaiMapping.box_firma_B, await _renderFirmaTight(GlobalData.puntiFirmaB, Colors.black));

      // =================================================================
      // SALVATAGGIO SICURO
      // =================================================================

      List<int> bytesTemporanei = await document.save();
      document.dispose();

      PdfDocument docFinale = PdfDocument(inputBytes: bytesTemporanei);

      try {
        docFinale.form.flattenAllFields();
      } catch (e) {
        debugPrint("⚠️ Errore Flattening: $e");
        docFinale.form.readOnly = true;
      }

      List<int> bytesFinali = await docFinale.save();
      docFinale.dispose();

      return bytesFinali;

    } catch (e) {
      debugPrint("ERRORE GENERAZIONE PDF: $e");
      return [];
    }
  }

  // ... (Keep existing helper methods: _riempiCampoSplit, _scriviX, _scriviTesto, _scriviXRossa, _scriviTestoTotale, _disegnaInBox, _renderFirmaTight, _valoreDaGlobal)
  // Re-pasting them here for completeness to ensure no missing dependencies

  static void _riempiCampoSplit(Map<String, PdfField> mappa, String testoCompleto, String key1, String key2) {
    if (testoCompleto.isEmpty) return;
    String riga1 = "";
    String riga2 = "";
    int limite = 20;
    if (testoCompleto.length <= limite) {
      riga1 = testoCompleto;
    } else {
      int splitIndex = testoCompleto.lastIndexOf(" ", limite);
      if (splitIndex == -1) splitIndex = limite;
      riga1 = testoCompleto.substring(0, splitIndex).trim();
      riga2 = testoCompleto.substring(splitIndex).trim();
    }
    if (mappa.containsKey(key1)) {
      final f1 = mappa[key1] as PdfTextBoxField;
      f1.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
      f1.textAlignment = PdfTextAlignment.left;
      f1.text = riga1.toUpperCase();
    }
    if (mappa.containsKey(key2)) {
      final f2 = mappa[key2] as PdfTextBoxField;
      f2.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
      f2.textAlignment = PdfTextAlignment.left;
      f2.text = riga2.toUpperCase();
    }
  }

  static bool _scriviX(Map<String, PdfField> mappa, List<String> nomiPossibili) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 14);
          field.foreColor = PdfColor(0, 0, 0);
          field.textAlignment = PdfTextAlignment.center;
          field.text = "X";
        } else if (field is PdfCheckBoxField) {
          field.isChecked = true;
        }
        return true;
      }
    }
    return false;
  }

  static void _scriviTesto(Map<String, PdfField> mappa, List<String> nomiPossibili, String testo) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
          field.foreColor = PdfColor(0, 0, 0);
          field.text = testo;
        }
        return;
      }
    }
  }

  static bool _scriviXRossa(Map<String, PdfField> mappa, List<String> nomiPossibili) {
    for (String nome in nomiPossibili) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 16, style: PdfFontStyle.bold);
          field.foreColor = PdfColor(255, 0, 0);
          field.textAlignment = PdfTextAlignment.center;
          field.text = "X";
          return true;
        }
      }
    }
    return false;
  }

  static void _scriviTestoTotale(Map<String, PdfField> mappa, List<String> nomi, String testo) {
    for (String nome in nomi) {
      String key = nome.trim().toUpperCase();
      if (mappa.containsKey(key)) {
        final field = mappa[key]!;
        if (field is PdfTextBoxField) {
          field.font = PdfStandardFont(PdfFontFamily.helvetica, 8);
          field.textAlignment = PdfTextAlignment.center;
          field.text = testo;
        }
        return;
      }
    }
  }

  static Future<void> _disegnaInBox(PdfPage page, Map<String, PdfField> mappa, String nomeCampo, Uint8List? imgBytes) async {
    String key = nomeCampo.trim().toUpperCase();
    if (imgBytes == null || !mappa.containsKey(key)) return;
    Rect boxRect = mappa[key]!.bounds;
    PdfBitmap bitmap = PdfBitmap(imgBytes);
    double imageW = bitmap.width.toDouble();
    double imageH = bitmap.height.toDouble();
    if (imageW <= 0 || imageH <= 0) return;
    double ratioX = boxRect.width / imageW;
    double ratioY = boxRect.height / imageH;
    double scale = (ratioX < ratioY) ? ratioX : ratioY;
    double drawW = imageW * scale;
    double drawH = imageH * scale;
    double offsetX = boxRect.left + (boxRect.width - drawW) / 2;
    double offsetY = boxRect.top + (boxRect.height - drawH) / 2;
    page.graphics.drawImage(bitmap, Rect.fromLTWH(offsetX, offsetY, drawW, drawH));
  }

  static Future<Uint8List?> _renderFirmaTight(List<Offset?> punti, Color colore) async {
    if (punti.isEmpty) return null;
    double minX = double.infinity, minY = double.infinity, maxX = double.negativeInfinity, maxY = double.negativeInfinity;
    for (var p in punti) { if (p != null) { if (p.dx < minX) minX = p.dx; if (p.dx > maxX) maxX = p.dx; if (p.dy < minY) minY = p.dy; if (p.dy > maxY) maxY = p.dy; } }
    double padding = 20.0;
    double firmaW = maxX - minX;
    double firmaH = maxY - minY;
    if (firmaW <= 0) firmaW = 1; if (firmaH <= 0) firmaH = 1;
    double resolutionScale = 3.0;
    double canvasW = (firmaW + padding * 2) * resolutionScale;
    double canvasH = (firmaH + padding * 2) * resolutionScale;
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    canvas.scale(resolutionScale);
    canvas.translate(-minX + padding, -minY + padding);
    final paint = Paint()..color = colore..strokeWidth = 5.0..style = PaintingStyle.stroke..strokeCap = StrokeCap.round..strokeJoin = StrokeJoin.round;
    for (int i = 0; i < punti.length - 1; i++) { if (punti[i] != null && punti[i+1] != null) { canvas.drawLine(punti[i]!, punti[i+1]!, paint); } }
    final img = await recorder.endRecording().toImage(canvasW.toInt(), canvasH.toInt());
    final byteData = await img.toByteData(format: ui.ImageByteFormat.png);
    return byteData?.buffer.asUint8List();
  }

  static Future<Uint8List?> _renderGraficoV40(List<TrattoPenna> tratti, List<ElementoGrafico> elementi) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final size = const Size(2000, 800);
    final painter = PainterV40(tratti, elementi);
    painter.paint(canvas, size);
    final img = await recorder.endRecording().toImage(size.width.toInt(), size.height.toInt());
    final byteData = await img.toByteData(format: ui.ImageByteFormat.png);
    return byteData?.buffer.asUint8List();
  }

  static String _valoreDaGlobal(String key) {
    switch (key) {
      case 'data_incidente': return GlobalData.data_incidente;
      case 'ora': return GlobalData.ora;
      case 'luogo': return GlobalData.luogo;
      case 'testimoni': return GlobalData.testimoni;
      case 'danni_visibili_A': return GlobalData.danni_visibili_A;
      case 'osservazioni_A': return GlobalData.osservazioni_A;
      case 'danni_visibili_B': return GlobalData.danni_visibili_B;
      case 'osservazioni_B': return GlobalData.osservazioni_B;
      case 'Cognome_contraente_A': return GlobalData.Cognome_contraente_A;
      case 'Nome_contraente_A': return GlobalData.Nome_contraente_A;
      case 'Codice_Fiscale_contraente_A': return GlobalData.Codice_Fiscale_contraente_A;
      case 'Indirizzo_contraente_A': return GlobalData.Indirizzo_contraente_A;
      case 'CAP_contraente_A': return GlobalData.CAP_contraente_A;
      case 'Stato_contraente_A': return GlobalData.Stato_contraente_A;
      case 'N_telefono_mail_contraente_A': return GlobalData.N_telefono_mail_contraente_A;
      case 'Marca_e_Tipo_A': return GlobalData.Marca_e_Tipo_A;
      case 'Targa_A': return GlobalData.Targa_A;
      case 'Stato_immatricolazione_A': return GlobalData.Stato_immatricolazione_A;
      case 'Rimorchio_A': return GlobalData.Rimorchio_A;
      case 'Stato_immatricolazione2_A': return GlobalData.Stato_immatricolazione2_A;
      case 'Denominazione_A': return GlobalData.Denominazione_A;
      case 'Numero_Polizza_A': return GlobalData.Numero_Polizza_A;
      case 'N_carta_verde_A': return GlobalData.N_carta_verde_A;
      case 'Data_Inizio_Dal_A': return GlobalData.Data_Inizio_Dal_A;
      case 'Data_Scadenza_Al_A': return GlobalData.Data_Scadenza_Al_A;
      case 'Agenzia_A': return GlobalData.Agenzia_A;
      case 'Indirizzo_agenzia_A': return GlobalData.Indirizzo_agenzia_A;
      case 'Stato_agenzia_A': return GlobalData.Stato_agenzia_A;
      case 'Denominazione_agenzia_A': return GlobalData.Denominazione_agenzia_A;
      case 'N_tel_mail_agenzia_A': return GlobalData.N_tel_mail_agenzia_A;
      case 'Cognome_cond_A': return GlobalData.Cognome_cond_A;
      case 'Nome_cond_A': return GlobalData.Nome_cond_A;
      case 'Data_nascita_cond_A': return GlobalData.Data_nascita_cond_A;
      case 'Cod_fiscale_cond_A': return GlobalData.Cod_fiscale_cond_A;
      case 'Indirizzo_cond_A': return GlobalData.Indirizzo_cond_A;
      case 'Stato_cond_A': return GlobalData.Stato_cond_A;
      case 'N_tel_mail_cond_A': return GlobalData.N_tel_mail_cond_A;
      case 'N_Patente_cond_A': return GlobalData.N_Patente_cond_A;
      case 'Scadenza_cond_A': return GlobalData.Scadenza_cond_A;
      case 'Cognome_contraente_B': return GlobalData.Cognome_contraente_B;
      case 'Nome_contraente_B': return GlobalData.Nome_contraente_B;
      case 'Codice_Fiscale_contraente_B': return GlobalData.Codice_Fiscale_contraente_B;
      case 'Indirizzo_contraente_B': return GlobalData.Indirizzo_contraente_B;
      case 'CAP_contraente_B': return GlobalData.CAP_contraente_B;
      case 'Stato_contraente_B': return GlobalData.Stato_contraente_B;
      case 'N_telefono_mail_contraente_B': return GlobalData.N_telefono_mail_contraente_B;
      case 'Marca_e_Tipo_B': return GlobalData.Marca_e_Tipo_B;
      case 'Targa_B': return GlobalData.Targa_B;
      case 'Stato_immatricolazione_B': return GlobalData.Stato_immatricolazione_B;
      case 'Rimorchio_B': return GlobalData.Rimorchio_B;
      case 'Stato_immatricolazione2_B': return GlobalData.Stato_immatricolazione2_B;
      case 'Denominazione_B': return GlobalData.Denominazione_B;
      case 'Numero_Polizza_B': return GlobalData.Numero_Polizza_B;
      case 'N_carta_verde_B': return GlobalData.N_carta_verde_B;
      case 'Data_Inizio_Dal_B': return GlobalData.Data_Inizio_Dal_B;
      case 'Data_Scadenza_Al_B': return GlobalData.Data_Scadenza_Al_B;
      case 'Agenzia_B': return GlobalData.Agenzia_B;
      case 'Indirizzo_agenzia_B': return GlobalData.Indirizzo_agenzia_B;
      case 'Stato_agenzia_B': return GlobalData.Stato_agenzia_B;
      case 'Denominazione_agenzia_B': return GlobalData.Denominazione_agenzia_B;
      case 'N_tel_mail_agenzia_B': return GlobalData.N_tel_mail_agenzia_B;
      case 'Cognome_cond_B': return GlobalData.Cognome_cond_B;
      case 'Nome_cond_B': return GlobalData.Nome_cond_B;
      case 'Data_nascita_cond_B': return GlobalData.Data_nascita_cond_B;
      case 'Cod_fiscale_cond_B': return GlobalData.Cod_fiscale_cond_B;
      case 'Indirizzo_cond_B': return GlobalData.Indirizzo_cond_B;
      case 'Stato_cond_B': return GlobalData.Stato_cond_B;
      case 'N_tel_mail_cond_B': return GlobalData.N_tel_mail_cond_B;
      case 'N_Patente_cond_B': return GlobalData.N_Patente_cond_B;
      case 'Scadenza_cond_B': return GlobalData.Scadenza_cond_B;
      default: return "";
    }
  }
}

class PainterV40 extends CustomPainter {
  final List<TrattoPenna> tr;
  final List<ElementoGrafico> el;

  PainterV40(this.tr, this.el);

  final List<Color> palette = [Colors.blue, Colors.orange, Colors.green, Colors.purple, Colors.red];

  @override
  void paint(Canvas canvas, Size size) {
    // 1. SFONDO BIANCO
    final Paint backgroundPaint = Paint()..color = Colors.white;
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), backgroundPaint);

    // 2. GRIGLIA
    final Paint gridPaint = Paint()..color = Colors.grey.shade300..strokeWidth = 2.0;
    double step = 40.0;
    for (double x = 0; x <= size.width; x += step) {
      canvas.drawLine(Offset(x, 0), Offset(x, size.height), gridPaint);
    }
    for (double y = 0; y <= size.height; y += step) {
      canvas.drawLine(Offset(0, y), Offset(size.width, y), gridPaint);
    }

    if (tr.isEmpty && el.isEmpty) return;

    // --- BOUNDING BOX ---
    double minX = double.infinity, minY = double.infinity;
    double maxX = double.negativeInfinity, maxY = double.negativeInfinity;

    for (var t in tr) {
      for (var p in t.punti) {
        if (p.dx < minX) minX = p.dx;
        if (p.dx > maxX) maxX = p.dx;
        if (p.dy < minY) minY = p.dy;
        if (p.dy > maxY) maxY = p.dy;
      }
    }
    for (var e in el) {
      if (e.posizione.dx - 30 < minX) minX = e.posizione.dx - 30;
      if (e.posizione.dx + 30 > maxX) maxX = e.posizione.dx + 30;
      if (e.posizione.dy - 30 < minY) minY = e.posizione.dy - 30;
      if (e.posizione.dy + 30 > maxY) maxY = e.posizione.dy + 30;
    }

    if (minX == double.infinity) { minX = 0; maxX = 100; minY = 0; maxY = 100; }

    double padding = 40.0;
    double drawingW = maxX - minX + (padding * 2);
    double drawingH = maxY - minY + (padding * 2);

    if (drawingW <= 0) drawingW = 100;
    if (drawingH <= 0) drawingH = 100;

    double scaleX = size.width / drawingW;
    double scaleY = size.height / drawingH;
    double scale = (scaleX < scaleY) ? scaleX : scaleY;

    double offsetX = (size.width - (drawingW * scale)) / 2;
    double offsetY = (size.height - (drawingH * scale)) / 2;

    canvas.save();
    canvas.translate(offsetX, offsetY);
    canvas.scale(scale);
    canvas.translate(-minX + padding, -minY + padding);

    // --- DISEGNO STRADE E FRECCE ---
    Paint pStrada = Paint()
      ..color = Colors.black
      ..strokeWidth = 4.0 / scale
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    for (var t in tr) {
      if (t.punti.length > 1) {
        Path path = Path()..moveTo(t.punti[0].dx, t.punti[0].dy);
        for (var pt in t.punti) path.lineTo(pt.dx, pt.dy);
        canvas.drawPath(path, pStrada);

        if (t.tipo == 'freccia') {
          double a = (t.punti.last - t.punti[t.punti.length - 2]).direction;
          canvas.drawLine(t.punti.last, t.punti.last - Offset.fromDirection(a - 0.5, 15), pStrada);
          canvas.drawLine(t.punti.last, t.punti.last - Offset.fromDirection(a + 0.5, 15), pStrada);
        }
      }
    }

    // --- DISEGNO ELEMENTI ---
    for (var e in el) {
      canvas.save();
      canvas.translate(e.posizione.dx, e.posizione.dy);
      canvas.rotate(e.rotazione);

      if (e.tipo == 'testo') {
        final tp = TextPainter(
            text: TextSpan(text: e.label ?? "", style: const TextStyle(color: Colors.black, fontSize: 24, fontWeight: FontWeight.bold)),
            textDirection: TextDirection.ltr
        )..layout();
        tp.paint(canvas, Offset(-tp.width/2, -tp.height/2));
      }
      else {
        String lettera = e.label ?? "A";
        int idx = (lettera.isNotEmpty) ? (lettera.codeUnitAt(0) - 65) % palette.length : 0;
        Color colore = palette[idx];

        if (e.tipo.startsWith('auto')) {
          _disegnaAuto(canvas, colore, lettera);
        } else if (e.tipo.startsWith('moto')) {
          _disegnaMoto(canvas, colore, lettera);
        } else if (e.tipo.startsWith('furgone')) {
          _disegnaFurgone(canvas, colore, lettera);
        }
      }
      canvas.restore();
    }

    canvas.restore();
  }

  // --- METODI DI DISEGNO SPECIFICI ---

  void _disegnaAuto(Canvas canvas, Color colore, String lettera) {
    double w = 48.0; double h = 24.0;
    Paint pBody = Paint()..color = colore;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.5;

    // Corpo
    RRect bodyRect = RRect.fromRectAndRadius(Rect.fromCenter(center: Offset.zero, width: w, height: h), const Radius.circular(5));
    canvas.drawRRect(bodyRect, pBody);

    // Cabina
    Paint pCabin = Paint()..color = Colors.black.withOpacity(0.2);
    canvas.drawRect(Rect.fromLTRB(-w/2 + 6, -h/2 + 3, w/4, h/2 - 3), pCabin);

    // Fari
    Paint pLights = Paint()..color = Colors.yellow;
    canvas.drawCircle(Offset(w/2 - 2, h/2 - 4), 2.5, pLights);
    canvas.drawCircle(Offset(w/2 - 2, -h/2 + 4), 2.5, pLights);

    // Bordo
    canvas.drawRRect(bodyRect, pBorder);

    // Lettera
    _disegnaLettera(canvas, lettera);
  }

  void _disegnaMoto(Canvas canvas, Color colore, String lettera) {
    double w = 34.0; double h = 12.0;
    Paint pBody = Paint()..color = colore;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.0;
    Paint pBlack = Paint()..color = Colors.black;

    // Ruote (piene)
    canvas.drawCircle(Offset(-w/2 + 4, 0), 5.0, pBlack);
    canvas.drawCircle(Offset(w/2 - 4, 0), 5.0, pBlack);

    // Corpo
    Rect bodyRect = Rect.fromCenter(center: Offset.zero, width: w - 10, height: h - 4);
    canvas.drawRRect(RRect.fromRectAndRadius(bodyRect, const Radius.circular(4)), pBody);
    canvas.drawRRect(RRect.fromRectAndRadius(bodyRect, const Radius.circular(4)), pBorder);

    // Sella
    canvas.drawRect(Rect.fromCenter(center: Offset(-5, 0), width: 12, height: 8), pBlack);

    // Manubrio
    Paint pManubrio = Paint()..color = Colors.black..strokeWidth = 3.0..strokeCap = StrokeCap.round;
    canvas.drawLine(Offset(w/2 - 12, -10), Offset(w/2 - 12, 10), pManubrio);

    // Faro
    canvas.drawCircle(Offset(w/2, 0), 3.0, Paint()..color = Colors.yellow);

    _disegnaLettera(canvas, lettera, fontSize: 10);
  }

  void _disegnaFurgone(Canvas canvas, Color colore, String lettera) {
    double w = 60.0; double h = 26.0;
    Paint pBody = Paint()..color = colore;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.5;

    // Vano Carico (Box posteriore)
    Rect caricoRect = Rect.fromLTRB(-w/2, -h/2, w/4, h/2);
    canvas.drawRect(caricoRect, pBody);
    canvas.drawRect(caricoRect, pBorder);

    // Cabina (Box anteriore)
    Rect cabinaRect = Rect.fromLTRB(w/4, -h/2 + 1, w/2, h/2 - 1);
    canvas.drawRect(cabinaRect, pBody);
    canvas.drawRect(cabinaRect, pBorder);

    // Parabrezza
    Paint pVetro = Paint()..color = Colors.black.withOpacity(0.3);
    canvas.drawRect(Rect.fromLTRB(w/4 + 2, -h/2 + 3, w/2 - 2, h/2 - 3), pVetro);

    // Fari
    Paint pLights = Paint()..color = Colors.yellow;
    canvas.drawRect(Rect.fromLTWH(w/2 - 2, -h/2 + 2, 2, 4), pLights);
    canvas.drawRect(Rect.fromLTWH(w/2 - 2, h/2 - 6, 2, 4), pLights);

    _disegnaLettera(canvas, lettera);
  }

  void _disegnaLettera(Canvas canvas, String txt, {double fontSize = 16}) {
    final tp = TextPainter(
        text: TextSpan(text: txt, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize)),
        textDirection: TextDirection.ltr
    )..layout();
    tp.paint(canvas, Offset(-tp.width/2, -tp.height/2));
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
=== FILE: lib/comp_13.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'global_data.dart';
import 'models.dart';
import 'comp_15.dart';

class Comp13Screen extends StatefulWidget {
  const Comp13Screen({super.key});

  @override
  State<Comp13Screen> createState() => _Comp13ScreenState();
}

class _Comp13ScreenState extends State<Comp13Screen> {
  List<ElementoGrafico> _elementi = [];
  List<TrattoPenna> _tratti = [];
  String modo = 'penna';

  @override
  void initState() {
    super.initState();
    _elementi = List.from(GlobalData.elementi);
    _tratti = List.from(GlobalData.tratti);

    // Proviamo a chiedere il landscape al sistema (non sempre funziona su iPad)
    _setLandscape();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) _mostraIstruzioni();
    });
  }

  Future<void> _setLandscape() async {
    await SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);
  }

  Future<void> _setPortrait() async {
    await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  }

  Future<void> _esci() async {
    GlobalData.tratti = List.from(_tratti);
    GlobalData.elementi = List.from(_elementi);
    await _setPortrait();
    if (mounted) Navigator.pop(context);
  }

  Future<void> _vaiAvanti() async {
    GlobalData.tratti = List.from(_tratti);
    GlobalData.elementi = List.from(_elementi);

    // Prima di cambiare pagina, rimettiamo in verticale
    // await _setPortrait();

    if (mounted) {
      await Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp15Screen()));
      // Al ritorno, forziamo di nuovo orizzontale
      await _setLandscape();
    }
  }

  // --- FUNZIONE HELPER PER RUOTARE I DIALOGHI ---
  // Se l'iPad è verticale, ruota il contenuto del dialogo di 90 gradi
  Widget _ruotaSeNecessario(BuildContext context, Widget child) {
    return OrientationBuilder(
      builder: (context, orientation) {
        return orientation == Orientation.portrait
            ? RotatedBox(quarterTurns: 1, child: child)
            : child;
      },
    );
  }

  void _mostraIstruzioni() {
    showDialog(
      context: context,
      builder: (ctx) => _ruotaSeNecessario(ctx, AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
        title: Row(
          children: [
            Icon(Icons.help_outline, color: Colors.blue.shade900),
            const SizedBox(width: 10),
            const Text("Guida al Disegno", style: TextStyle(fontWeight: FontWeight.bold)),
          ],
        ),
        content: SizedBox(
          width: 500, // Larghezza fissa per evitare problemi di layout ruotato
          height: 300, // Altezza fissa per scrollare comodamente
          child: Scrollbar(
            thumbVisibility: true,
            child: SingleChildScrollView(
              physics: const BouncingScrollPhysics(),
              child: const Text(
                "• 🖊  Usa la penna per disegnare le strade\n"
                    "• 🚗 🏍️ 🚛 Seleziona e tocca per aggiungere veicoli\n"
                    "• ↗️  Inserisci frecce di direzione\n"
                    "• 📝  Aggiungi testo (es. nomi vie)\n"
                    "• 🔄  Tocca un elemento per ruotarlo\n"
                    "• ❌  Premi a lungo un oggetto per eliminarlo\n"
                    "• 🗑️  Usa il tasto Cestino per resettare tutto",
                style: TextStyle(fontSize: 16, height: 1.6, color: Colors.black87),
              ),
            ),
          ),
        ),
        actions: [
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue.shade900,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 12),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
              ),
              onPressed: () => Navigator.pop(ctx),
              child: const Text("HO CAPITO", style: TextStyle(fontWeight: FontWeight.bold)),
            ),
          )
        ],
      )),
    );
  }

  void _gestisciInserimento(Offset pos) async {
    if (modo == 'testo') {
      TextEditingController tc = TextEditingController();
      await showDialog(
        context: context,
        builder: (c) => _ruotaSeNecessario(c, Dialog(
          backgroundColor: Colors.white,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          child: Container(
            width: 300,
            padding: const EdgeInsets.all(20),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text("Inserisci Testo", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                const SizedBox(height: 10),
                TextField(
                    controller: tc,
                    autofocus: true,
                    decoration: const InputDecoration(hintText: "Nome via...", border: OutlineInputBorder())
                ),
                const SizedBox(height: 20),
                ElevatedButton(
                    onPressed: () {
                      if (tc.text.isNotEmpty) {
                        setState(() => _elementi.add(ElementoGrafico(pos, 'testo', label: tc.text)));
                      }
                      Navigator.pop(c);
                    },
                    child: const Text("INSERISCI")
                )
              ],
            ),
          ),
        )),
      );
    } else if (['auto', 'moto', 'furgone'].contains(modo)) {
      int numeroVeicoli = _elementi.where((e) =>
      e.tipo.startsWith('auto') ||
          e.tipo.startsWith('moto') ||
          e.tipo.startsWith('furgone')).length;

      String prossimaLettera = String.fromCharCode(65 + numeroVeicoli);

      setState(() {
        _elementi.add(ElementoGrafico(pos, '$modo$prossimaLettera', label: prossimaLettera));
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // 1. Logica di orientamento principale (Body)
    // Se siamo verticali, ruotiamo tutto di 90 gradi.
    return PopScope(
      canPop: false,
      onPopInvokedWithResult: (didPop, result) async {
        if (!didPop) await _esci();
      },
      child: OrientationBuilder(
        builder: (context, orientation) {
          final bool isPortrait = orientation == Orientation.portrait;

          return Scaffold(
            backgroundColor: Colors.white,
            resizeToAvoidBottomInset: false,
            // Se Portrait -> Ruota Body. Se Landscape -> Body normale.
            body: isPortrait
                ? RotatedBox(quarterTurns: 1, child: _buildBodyContent(context))
                : _buildBodyContent(context),
          );
        },
      ),
    );
  }

  // Contenuto principale estratto per facilitare la rotazione
  Widget _buildBodyContent(BuildContext context) {
    // Calcoliamo dimensioni sicure
    final size = MediaQuery.of(context).size;
    final double maxToolbarHeight = size.shortestSide * 0.8;

    return SafeArea(
      child: Stack(
        children: [
          Column(
            children: [
              Container(
                height: 50,
                color: Colors.blueGrey[50],
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: Row(
                  children: [
                    IconButton(
                      icon: const Icon(Icons.arrow_back, color: Colors.black),
                      onPressed: _esci,
                    ),
                    const Expanded(
                      child: Text(
                        "13. Grafico",
                        textAlign: TextAlign.center,
                        style: TextStyle(color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold),
                      ),
                    ),
                    IconButton(
                        icon: const Icon(Icons.help_outline, color: Colors.black),
                        onPressed: _mostraIstruzioni
                    ),
                    const SizedBox(width: 15),
                    ElevatedButton.icon(
                      style: ElevatedButton.styleFrom(
                          backgroundColor: Colors.green,
                          foregroundColor: Colors.white,
                          padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8)
                      ),
                      icon: const Icon(Icons.check),
                      label: const Text("SALVA"),
                      onPressed: _vaiAvanti,
                    ),
                  ],
                ),
              ),
              Expanded(
                child: GestureDetector(
                  onLongPressStart: (d) {
                    setState(() {
                      _elementi.removeWhere((e) => e.contiene(d.localPosition));
                      _tratti.removeWhere((t) => t.contiene(d.localPosition));
                    });
                  },
                  onTapDown: (d) {
                    bool colpito = false;
                    for (var e in _elementi) {
                      if (e.contiene(d.localPosition)) {
                        setState(() => e.rotazione += 0.785);
                        colpito = true;
                        break;
                      }
                    }
                    if (!colpito && (['auto', 'moto', 'furgone', 'testo'].contains(modo))) {
                      _gestisciInserimento(d.localPosition);
                    }
                  },
                  onPanStart: (d) {
                    if (modo == 'penna' || modo == 'freccia') {
                      setState(() => _tratti.add(TrattoPenna([d.localPosition], tipo: modo)));
                    }
                  },
                  onPanUpdate: (d) {
                    if (modo == 'penna' || modo == 'freccia') {
                      setState(() => _tratti.last.punti.add(d.localPosition));
                    }
                  },
                  child: Container(
                    color: Colors.white,
                    width: double.infinity,
                    height: double.infinity,
                    child: CustomPaint(
                      painter: PainterV40(_tratti, _elementi),
                      size: Size.infinite,
                    ),
                  ),
                ),
              ),
            ],
          ),
          Positioned(
            left: 10, top: 60,
            child: Container(
              width: 55,
              constraints: BoxConstraints(maxHeight: maxToolbarHeight),
              decoration: BoxDecoration(
                color: Colors.white.withOpacity(0.95),
                borderRadius: BorderRadius.circular(25),
                boxShadow: [const BoxShadow(color: Colors.black26, blurRadius: 4)],
                border: Border.all(color: Colors.grey.shade300),
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(25),
                child: SingleChildScrollView(
                  padding: const EdgeInsets.symmetric(vertical: 8),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      _toolBtn(Icons.edit, 'penna', Colors.black),
                      _toolBtn(Icons.trending_flat, 'freccia', Colors.black),
                      _toolBtn(Icons.title, 'testo', Colors.black),
                      const Divider(indent: 8, endIndent: 8, height: 15),
                      _toolBtn(Icons.directions_car, 'auto', Colors.blue),
                      _toolBtn(Icons.two_wheeler, 'moto', Colors.orange.shade800),
                      _toolBtn(Icons.local_shipping, 'furgone', Colors.green),
                      const Divider(indent: 8, endIndent: 8, height: 15),
                      IconButton(
                        icon: const Icon(Icons.delete_forever, color: Colors.red),
                        tooltip: "Cancella tutto",
                        onPressed: () => setState(() { _tratti.clear(); _elementi.clear(); }),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _toolBtn(IconData icon, String tool, Color activeColor) {
    bool isSelected = modo == tool;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Material(
        color: Colors.transparent,
        child: InkWell(
          borderRadius: BorderRadius.circular(20),
          onTap: () => setState(() => modo = tool),
          child: Container(
            width: 40,
            height: 40,
            decoration: BoxDecoration(
              color: isSelected ? activeColor.withOpacity(0.15) : Colors.transparent,
              border: isSelected ? Border.all(color: activeColor, width: 2) : null,
              shape: BoxShape.circle,
            ),
            child: Icon(
              icon,
              color: activeColor,
              size: 24,
            ),
          ),
        ),
      ),
    );
  }
}

class PainterV40 extends CustomPainter {
  final List<TrattoPenna> tr;
  final List<ElementoGrafico> el;
  PainterV40(this.tr, this.el);

  final List<Color> palette = [Colors.blue, Colors.orange, Colors.green, Colors.purple, Colors.red, Colors.teal];

  @override
  void paint(Canvas canvas, Size size) {
    Paint pStrada = Paint()..color = Colors.black..strokeWidth = 3.0..style = PaintingStyle.stroke..strokeCap = StrokeCap.round;

    for (var t in tr) {
      if (t.punti.length > 1) {
        // Disegno il tratto stradale
        Path path = Path()..moveTo(t.punti[0].dx, t.punti[0].dy);
        for (var pt in t.punti) path.lineTo(pt.dx, pt.dy);
        canvas.drawPath(path, pStrada);

        // --- CORREZIONE FRECCIA ---
        if (t.tipo == 'freccia') {
          Offset pTip = t.punti.last;
          Offset pBack = t.punti[t.punti.length - 2];

          // STABILIZZAZIONE: Cerco un punto precedente che sia distante almeno 10 pixel
          // dalla punta. Questo ignora i micro-movimenti finali del dito (jitter)
          // che causavano l'inversione della freccia.
          for (int i = t.punti.length - 2; i >= 0; i--) {
            if ((t.punti[i] - pTip).distance > 10.0) {
              pBack = t.punti[i];
              break;
            }
          }
          _disegnaPunta(canvas, pBack, pTip, pStrada);
        }
        // --------------------------
      }
    }

    for (var e in el) {
      canvas.save();
      canvas.translate(e.posizione.dx, e.posizione.dy);
      canvas.rotate(e.rotazione);

      if (e.tipo == 'testo') {
        _disegnaTesto(canvas, e.label ?? "");
      } else if (e.tipo.startsWith('auto')) {
        _disegnaAuto(canvas, e);
      } else if (e.tipo.startsWith('moto')) {
        _disegnaMoto(canvas, e);
      } else if (e.tipo.startsWith('furgone')) {
        _disegnaFurgone(canvas, e);
      }
      canvas.restore();
    }
  }

  // ... (TUTTI GLI ALTRI METODI RESTANO IDENTICI) ...

  Color _getColoreDaLettera(String lettera) {
    if (lettera.isEmpty) return Colors.grey;
    int idx = (lettera.codeUnitAt(0) - 65) % palette.length;
    return palette[idx];
  }

  void _disegnaLettera(Canvas canvas, String lettera, {double fontSize = 16}) {
    final tp = TextPainter(
        text: TextSpan(text: lettera, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize)),
        textDirection: TextDirection.ltr
    )..layout();
    tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2));
  }

  void _disegnaAuto(Canvas canvas, ElementoGrafico e) {
    String lettera = e.label ?? "A";
    Color colore = _getColoreDaLettera(lettera);
    double w = 48.0;
    double h = 24.0;

    Paint pBody = Paint()..color = colore;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.5;

    RRect bodyRect = RRect.fromRectAndRadius(Rect.fromCenter(center: Offset.zero, width: w, height: h), const Radius.circular(5));
    canvas.drawRRect(bodyRect, pBody);

    Paint pCabin = Paint()..color = Colors.black.withOpacity(0.2);
    canvas.drawRect(Rect.fromLTRB(-w/2 + 6, -h/2 + 3, w/4, h/2 - 3), pCabin);

    Paint pLights = Paint()..color = Colors.yellow;
    canvas.drawCircle(Offset(w/2 - 2, h/2 - 4), 2.5, pLights);
    canvas.drawCircle(Offset(w/2 - 2, -h/2 + 4), 2.5, pLights);

    canvas.drawRRect(bodyRect, pBorder);
    _disegnaLettera(canvas, lettera);
  }

  void _disegnaMoto(Canvas canvas, ElementoGrafico e) {
    String lettera = e.label ?? "A";
    Color colore = _getColoreDaLettera(lettera);

    double len = 40.0;
    double wid = 14.0;

    Paint pBody = Paint()..color = colore;
    Paint pBlack = Paint()..color = Colors.black;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.0;

    canvas.drawCircle(Offset(-len/2 + 4, 0), 5.0, pBlack);
    canvas.drawCircle(Offset(len/2 - 4, 0), 5.0, pBlack);

    Rect bodyRect = Rect.fromCenter(center: Offset.zero, width: len - 10, height: wid - 4);
    canvas.drawRRect(RRect.fromRectAndRadius(bodyRect, const Radius.circular(4)), pBody);
    canvas.drawRRect(RRect.fromRectAndRadius(bodyRect, const Radius.circular(4)), pBorder);

    Rect sellaRect = Rect.fromCenter(center: Offset(-5, 0), width: 12, height: 8);
    canvas.drawRect(sellaRect, pBlack);

    Paint pManubrio = Paint()..color = Colors.black..strokeWidth = 3.0..strokeCap = StrokeCap.round;
    double xHandle = len/2 - 12;
    canvas.drawLine(Offset(xHandle, -10), Offset(xHandle, 10), pManubrio);

    Paint pLights = Paint()..color = Colors.yellow;
    canvas.drawCircle(Offset(len/2, 0), 3.0, pLights);

    _disegnaLettera(canvas, lettera, fontSize: 10);
  }

  void _disegnaFurgone(Canvas canvas, ElementoGrafico e) {
    String lettera = e.label ?? "A";
    Color colore = _getColoreDaLettera(lettera);
    double w = 60.0;
    double h = 26.0;

    Paint pBody = Paint()..color = colore;
    Paint pBorder = Paint()..style = PaintingStyle.stroke..color = Colors.black..strokeWidth = 1.5;

    Rect caricoRect = Rect.fromLTRB(-w/2, -h/2, w/4, h/2);
    canvas.drawRect(caricoRect, pBody);
    canvas.drawRect(caricoRect, pBorder);

    Rect cabinaRect = Rect.fromLTRB(w/4, -h/2 + 1, w/2, h/2 - 1);
    canvas.drawRect(cabinaRect, pBody);
    canvas.drawRect(cabinaRect, pBorder);

    Paint pVetro = Paint()..color = Colors.black.withOpacity(0.3);
    canvas.drawRect(Rect.fromLTRB(w/4 + 2, -h/2 + 3, w/2 - 2, h/2 - 3), pVetro);

    Paint pLights = Paint()..color = Colors.yellow;
    canvas.drawRect(Rect.fromLTWH(w/2 - 2, -h/2 + 2, 2, 4), pLights);
    canvas.drawRect(Rect.fromLTWH(w/2 - 2, h/2 - 6, 2, 4), pLights);

    _disegnaLettera(canvas, lettera);
  }

  void _disegnaTesto(Canvas canvas, String txt) {
    final tp = TextPainter(
        text: TextSpan(text: txt, style: const TextStyle(color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold)),
        textDirection: TextDirection.ltr
    )..layout();
    tp.paint(canvas, Offset(-tp.width/2, -tp.height/2));
  }

  void _disegnaPunta(Canvas canvas, Offset p1, Offset p2, Paint paint) {
    double angle = (p2 - p1).direction;
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle - 0.5, 10), paint);
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle + 0.5, 10), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
=== FILE: lib/cid_data_manager.dart ===
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'global_data.dart';
import 'models.dart';

class CidDataManager {

  // ===========================================================================
  //                     METODI PER SCAMBIO DATI (QR/P2P)
  // ===========================================================================

  static Map<String, dynamic> estraiDatiPerExport() {
    String lato = GlobalData.latoCorrente;

    String val(String vA, String vB, String l) => l == 'A' ? vA : vB;
    bool valB(bool bA, bool bB, String l) => l == 'A' ? bA : bB;

    return {
      'lato': lato,
      'generali': {
        'data': GlobalData.data_incidente,
        'ora': GlobalData.ora,
        'luogo': GlobalData.luogo,
        'feriti': GlobalData.feriti,
        'testimoni': GlobalData.testimoni,
        'danni_materiali': GlobalData.Veicoli_danni_materiali_oltre,
        'oggetti_diversi': GlobalData.Oggetti_diversi_danni_materiali,
      },

      'circostanze': _serializeCircostanze(lato == 'A' ? GlobalData.circostanzeA : GlobalData.circostanzeB),
      'punti_urto': lato == 'A' ? GlobalData.puntiUrtoA_List : GlobalData.puntiUrtoB_List,

      // CASSETTO 1: GRAFICO INCIDENTE (Strade, Auto)
      'grafico': {
        'tratti_dinamica': GlobalData.tratti.map((t) => t.toMap()).toList(),
        'elementi_dinamica': GlobalData.elementi.map((e) => e.toMap()).toList(),
      },

      // CASSETTO 2: FIRMA (Dati grafici personali)
      'firma': _serializePunti(lato == 'A' ? GlobalData.puntiFirmaA : GlobalData.puntiFirmaB),

      'contraente': {
        'cognome': val(GlobalData.Cognome_contraente_A, GlobalData.Cognome_contraente_B, lato),
        'nome': val(GlobalData.Nome_contraente_A, GlobalData.Nome_contraente_B, lato),
        'cf': val(GlobalData.Codice_Fiscale_contraente_A, GlobalData.Codice_Fiscale_contraente_B, lato),
        'indirizzo': val(GlobalData.Indirizzo_contraente_A, GlobalData.Indirizzo_contraente_B, lato),
        'cap': val(GlobalData.CAP_contraente_A, GlobalData.CAP_contraente_B, lato),
        'stato': val(GlobalData.Stato_contraente_A, GlobalData.Stato_contraente_B, lato),
        'tel': val(GlobalData.N_telefono_mail_contraente_A, GlobalData.N_telefono_mail_contraente_B, lato),
      },
      'veicolo': {
        'marca': val(GlobalData.Marca_e_Tipo_A, GlobalData.Marca_e_Tipo_B, lato),
        'targa': val(GlobalData.Targa_A, GlobalData.Targa_B, lato),
        'stato_imm': val(GlobalData.Stato_immatricolazione_A, GlobalData.Stato_immatricolazione_B, lato),
        'stato_imm2': val(GlobalData.Stato_immatricolazione2_A, GlobalData.Stato_immatricolazione2_B, lato),
        'rimorchio': val(GlobalData.Rimorchio_A, GlobalData.Rimorchio_B, lato),
      },
      'assicurazione': {
        'denominazione': val(GlobalData.Denominazione_A, GlobalData.Denominazione_B, lato),
        'polizza': val(GlobalData.Numero_Polizza_A, GlobalData.Numero_Polizza_B, lato),
        'agenzia': val(GlobalData.Agenzia_A, GlobalData.Agenzia_B, lato),
        'denom_agenzia': val(GlobalData.Denominazione_agenzia_A, GlobalData.Denominazione_agenzia_B, lato),
        'indirizzo_agenzia': val(GlobalData.Indirizzo_agenzia_A, GlobalData.Indirizzo_agenzia_B, lato),
        'stato_agenzia': val(GlobalData.Stato_agenzia_A, GlobalData.Stato_agenzia_B, lato),
        'tel_agenzia': val(GlobalData.N_tel_mail_agenzia_A, GlobalData.N_tel_mail_agenzia_B, lato),
        'carta_verde': val(GlobalData.N_carta_verde_A, GlobalData.N_carta_verde_B, lato),
        'validita_dal': val(GlobalData.Data_Inizio_Dal_A, GlobalData.Data_Inizio_Dal_B, lato),
        'validita_al': val(GlobalData.Data_Scadenza_Al_A, GlobalData.Data_Scadenza_Al_B, lato),
        'flag_danni': valB(GlobalData.FLAG_danni_mat_assicurati_A, GlobalData.FLAG_danni_mat_assicurati_B, lato),
      },
      'conducente': {
        'cognome': val(GlobalData.Cognome_cond_A, GlobalData.Cognome_cond_B, lato),
        'nome': val(GlobalData.Nome_cond_A, GlobalData.Nome_cond_B, lato),
        'nascita': val(GlobalData.Data_nascita_cond_A, GlobalData.Data_nascita_cond_B, lato),
        'cf': val(GlobalData.Cod_fiscale_cond_A, GlobalData.Cod_fiscale_cond_B, lato),
        'indirizzo': val(GlobalData.Indirizzo_cond_A, GlobalData.Indirizzo_cond_B, lato),
        'stato': val(GlobalData.Stato_cond_A, GlobalData.Stato_cond_B, lato),
        'tel': val(GlobalData.N_tel_mail_cond_A, GlobalData.N_tel_mail_cond_B, lato),
        'patente': val(GlobalData.N_Patente_cond_A, GlobalData.N_Patente_cond_B, lato),
        'cat_patente': val(GlobalData.Categoria_cond_A, GlobalData.Categoria_cond_B, lato),
        'scad_patente': val(GlobalData.Scadenza_cond_A, GlobalData.Scadenza_cond_B, lato),
      },
      'danni_osservazioni': {
        'visibili': val(GlobalData.danni_visibili_A, GlobalData.danni_visibili_B, lato),
        'osservazioni': val(GlobalData.osservazioni_A, GlobalData.osservazioni_B, lato),
      }
    };
  }

  static void importaDati(Map<String, dynamic> data) {
    String latoRemoto = data['lato'] ?? 'B';

    // 1. Dati Comuni
    if (data['generali'] != null) {
      var gen = data['generali'];
      if ((gen['data'] ?? "").isNotEmpty) GlobalData.data_incidente = gen['data'];
      if ((gen['ora'] ?? "").isNotEmpty) GlobalData.ora = gen['ora'];
      if ((gen['luogo'] ?? "").isNotEmpty) GlobalData.luogo = gen['luogo'];
      if (gen['feriti'] != null) GlobalData.feriti = gen['feriti'];
      if (gen['testimoni'] != null) GlobalData.testimoni = gen['testimoni'];
      if (gen['danni_materiali'] != null) GlobalData.Veicoli_danni_materiali_oltre = gen['danni_materiali'];
      if (gen['oggetti_diversi'] != null) GlobalData.Oggetti_diversi_danni_materiali = gen['oggetti_diversi'];
    }

    // --- PROTEZIONE GRAFICO (CASSETTO 1) ---
    // Solo se i dati arrivano da A, permettiamo di sovrascrivere il grafico comune.
    // Se arrivano da B, IGNORIAMO questa chiave (così il disegno di A resta intatto).
    if (latoRemoto == 'A' && data['grafico'] != null) {
      var graf = data['grafico'];

      if (graf['tratti_dinamica'] != null) {
        List<dynamic> listRaw = graf['tratti_dinamica'];
        GlobalData.tratti = listRaw.map((x) => TrattoPenna.fromMap(x)).toList();
      }

      if (graf['elementi_dinamica'] != null) {
        List<dynamic> listRaw = graf['elementi_dinamica'];
        GlobalData.elementi = listRaw.map((x) => ElementoGrafico.fromMap(x)).toList();
      }
    }

    // --- PROTEZIONE FIRMA (CASSETTO 2) ---
    // La firma NON viene bloccata. Ognuno ha la sua firma e deve poterla inviare.
    // Viene salvata in variabili distinte (puntiFirmaA e puntiFirmaB).
    if (data['firma'] != null) {
      List<Offset?> puntiFirma = _deserializePunti(data['firma']);
      if (latoRemoto == 'A') GlobalData.puntiFirmaA = puntiFirma;
      else GlobalData.puntiFirmaB = puntiFirma; // Qui B salva la sua firma
    }

    // 3. Circostanze
    if (data['circostanze'] != null) {
      Map<String, dynamic> rawCirc = data['circostanze'];
      Map<int, bool> mappaCirc = {};
      rawCirc.forEach((k, v) => mappaCirc[int.tryParse(k) ?? 0] = v as bool);
      if (latoRemoto == 'A') GlobalData.circostanzeA = mappaCirc;
      else GlobalData.circostanzeB = mappaCirc;
    }

    // 4. Punti Urto
    if (data['punti_urto'] != null) {
      List<String> puntiRecuperati = List<String>.from(data['punti_urto']);
      if (latoRemoto == 'A') {
        GlobalData.puntiUrtoA_List = puntiRecuperati;
      } else {
        GlobalData.puntiUrtoB_List = puntiRecuperati;
      }
    }

    void setVal(Function(String) setA, Function(String) setB, dynamic val) {
      if (val == null) return;
      if (latoRemoto == 'A') setA(val.toString()); else setB(val.toString());
    }
    void setBool(Function(bool) setA, Function(bool) setB, dynamic val) {
      if (val == null) return;
      if (latoRemoto == 'A') setA(val as bool); else setB(val as bool);
    }

    if (data['contraente'] != null) {
      var c = data['contraente'];
      setVal((v) => GlobalData.Cognome_contraente_A = v, (v) => GlobalData.Cognome_contraente_B = v, c['cognome']);
      setVal((v) => GlobalData.Nome_contraente_A = v, (v) => GlobalData.Nome_contraente_B = v, c['nome']);
      setVal((v) => GlobalData.Codice_Fiscale_contraente_A = v, (v) => GlobalData.Codice_Fiscale_contraente_B = v, c['cf']);
      setVal((v) => GlobalData.Indirizzo_contraente_A = v, (v) => GlobalData.Indirizzo_contraente_B = v, c['indirizzo']);
      setVal((v) => GlobalData.CAP_contraente_A = v, (v) => GlobalData.CAP_contraente_B = v, c['cap']);
      setVal((v) => GlobalData.Stato_contraente_A = v, (v) => GlobalData.Stato_contraente_B = v, c['stato']);
      setVal((v) => GlobalData.N_telefono_mail_contraente_A = v, (v) => GlobalData.N_telefono_mail_contraente_B = v, c['tel']);
    }

    if (data['veicolo'] != null) {
      var v = data['veicolo'];
      setVal((v) => GlobalData.Marca_e_Tipo_A = v, (v) => GlobalData.Marca_e_Tipo_B = v, v['marca']);
      setVal((v) => GlobalData.Targa_A = v, (v) => GlobalData.Targa_B = v, v['targa']);
      setVal((v) => GlobalData.Stato_immatricolazione_A = v, (v) => GlobalData.Stato_immatricolazione_B = v, v['stato_imm']);
      setVal((v) => GlobalData.Stato_immatricolazione2_A = v, (v) => GlobalData.Stato_immatricolazione2_B = v, v['stato_imm2']);
      setVal((v) => GlobalData.Rimorchio_A = v, (v) => GlobalData.Rimorchio_B = v, v['rimorchio']);
    }

    if (data['assicurazione'] != null) {
      var a = data['assicurazione'];
      setVal((v) => GlobalData.Denominazione_A = v, (v) => GlobalData.Denominazione_B = v, a['denominazione']);
      setVal((v) => GlobalData.Numero_Polizza_A = v, (v) => GlobalData.Numero_Polizza_B = v, a['polizza']);
      setVal((v) => GlobalData.Agenzia_A = v, (v) => GlobalData.Agenzia_B = v, a['agenzia']);
      setVal((v) => GlobalData.Denominazione_agenzia_A = v, (v) => GlobalData.Denominazione_agenzia_B = v, a['denom_agenzia']);
      setVal((v) => GlobalData.Indirizzo_agenzia_A = v, (v) => GlobalData.Indirizzo_agenzia_B = v, a['indirizzo_agenzia']);
      setVal((v) => GlobalData.Stato_agenzia_A = v, (v) => GlobalData.Stato_agenzia_B = v, a['stato_agenzia']);
      setVal((v) => GlobalData.N_tel_mail_agenzia_A = v, (v) => GlobalData.N_tel_mail_agenzia_B = v, a['tel_agenzia']);
      setVal((v) => GlobalData.N_carta_verde_A = v, (v) => GlobalData.N_carta_verde_B = v, a['carta_verde']);
      setVal((v) => GlobalData.Data_Inizio_Dal_A = v, (v) => GlobalData.Data_Inizio_Dal_B = v, a['validita_dal']);
      setVal((v) => GlobalData.Data_Scadenza_Al_A = v, (v) => GlobalData.Data_Scadenza_Al_B = v, a['validita_al']);
      setBool((v) => GlobalData.FLAG_danni_mat_assicurati_A = v, (v) => GlobalData.FLAG_danni_mat_assicurati_B = v, a['flag_danni']);
    }

    if (data['conducente'] != null) {
      var c = data['conducente'];
      setVal((v) => GlobalData.Cognome_cond_A = v, (v) => GlobalData.Cognome_cond_B = v, c['cognome']);
      setVal((v) => GlobalData.Nome_cond_A = v, (v) => GlobalData.Nome_cond_B = v, c['nome']);
      setVal((v) => GlobalData.Data_nascita_cond_A = v, (v) => GlobalData.Data_nascita_cond_B = v, c['nascita']);
      setVal((v) => GlobalData.Cod_fiscale_cond_A = v, (v) => GlobalData.Cod_fiscale_cond_B = v, c['cf']);
      setVal((v) => GlobalData.Indirizzo_cond_A = v, (v) => GlobalData.Indirizzo_cond_B = v, c['indirizzo']);
      setVal((v) => GlobalData.Stato_cond_A = v, (v) => GlobalData.Stato_cond_B = v, c['stato']);
      setVal((v) => GlobalData.N_tel_mail_cond_A = v, (v) => GlobalData.N_tel_mail_cond_B = v, c['tel']);
      setVal((v) => GlobalData.N_Patente_cond_A = v, (v) => GlobalData.N_Patente_cond_B = v, c['patente']);
      setVal((v) => GlobalData.Categoria_cond_A = v, (v) => GlobalData.Categoria_cond_B = v, c['cat_patente']);
      setVal((v) => GlobalData.Scadenza_cond_A = v, (v) => GlobalData.Scadenza_cond_B = v, c['scad_patente']);
    }

    if (data['danni_osservazioni'] != null) {
      var d = data['danni_osservazioni'];
      setVal((v) => GlobalData.danni_visibili_A = v, (v) => GlobalData.danni_visibili_B = v, d['visibili']);
      setVal((v) => GlobalData.osservazioni_A = v, (v) => GlobalData.osservazioni_B = v, d['osservazioni']);
    }
  }

  // ===========================================================================
  //                     METODI PER SALVATAGGIO CLOUD (FIREBASE)
  // ===========================================================================

  static Future<String> salvaDati(String sessionId, String lato) async {
    final docRef = FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId);

    // Estrae tutti i dati dalla memoria locale
    Map<String, dynamic> datiExport = estraiDatiPerExport();

    // Prepariamo i dati da inviare al server
    Map<String, dynamic> updateData = {
      'generali': datiExport['generali'],
      'lato_$lato': {
        ...datiExport['contraente'],
        ...datiExport['veicolo'],
        ...datiExport['assicurazione'],
        ...datiExport['conducente'],
        'danni_visibili': datiExport['danni_osservazioni']['visibili'],
        'osservazioni': datiExport['danni_osservazioni']['osservazioni'],
        'circostanze': datiExport['circostanze'],
        'punti_urto': datiExport['punti_urto'],
        'firma': datiExport['firma'], // <-- La firma è dentro "lato_A" o "lato_B", quindi è al sicuro
        'completo': true,
      },
      'timestamp': FieldValue.serverTimestamp(),
    };

    // --- PROTEZIONE AGGIUNTIVA PER IL CLOUD ---
    // Il GRAFICO lo aggiorniamo nel DB solo se siamo il LATO A.
    // Il LATO B non ha diritto di toccare questa chiave.
    if (lato == 'A') {
      updateData['grafico'] = datiExport['grafico'];
    }

    await docRef.set(updateData, SetOptions(merge: true));

    return sessionId;
  }

  // --- METODO RECUPERA DATI CLOUD ---
  static Future<void> caricaDati(String sessionId, String latoDaCaricare) async {
    final doc = await FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).get();
    if (!doc.exists) return;

    final data = doc.data()!;

    Map<String, dynamic> datiDaImportare = {};
    datiDaImportare['lato'] = latoDaCaricare;

    if (data['generali'] != null) datiDaImportare['generali'] = data['generali'];
    if (data['grafico'] != null) datiDaImportare['grafico'] = data['grafico'];

    if (data['lato_$latoDaCaricare'] != null) {
      Map<String, dynamic> latoData = data['lato_$latoDaCaricare'];

      datiDaImportare['contraente'] = latoData;
      datiDaImportare['veicolo'] = latoData;
      datiDaImportare['assicurazione'] = latoData;
      datiDaImportare['conducente'] = latoData;

      datiDaImportare['danni_osservazioni'] = {
        'visibili': latoData['danni_visibili'],
        'osservazioni': latoData['osservazioni'],
      };
      datiDaImportare['circostanze'] = latoData['circostanze'];
      datiDaImportare['punti_urto'] = latoData['punti_urto'];
      datiDaImportare['firma'] = latoData['firma']; // Recupera la firma specifica dal lato
    }

    importaDati(datiDaImportare);
  }

  // ===========================================================================
  //                     HELPER SERIALIZZAZIONE
  // ===========================================================================

  static Map<String, bool> _serializeCircostanze(Map<int, bool> circ) {
    return circ.map((key, value) => MapEntry(key.toString(), value));
  }

  static List<Map<String, double>> _serializePunti(List<Offset?> punti) {
    List<Map<String, double>> res = [];
    for (var p in punti) {
      if (p != null) res.add({'dx': p.dx, 'dy': p.dy});
    }
    return res;
  }

  static List<Offset?> _deserializePunti(dynamic lista) {
    if (lista is! List) return [];
    return lista.map<Offset?>((item) {
      if (item == null) return null;
      return Offset((item['dx'] as num).toDouble(), (item['dy'] as num).toDouble());
    }).toList();
  }
}
=== FILE: lib/firebase_options.dart ===
// File: lib/firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, TargetPlatform, kIsWeb;

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      throw UnsupportedError(
        'DefaultFirebaseOptions have not been configured for web',
      );
    }
    switch (defaultTargetPlatform) {

    // =======================================================
    // 🤖 CONFIGURAZIONE ANDROID (Compilata con i tuoi dati JSON)
    // =======================================================
      case TargetPlatform.android:
        return const FirebaseOptions(
          apiKey: 'AIzaSyB9f420xu5fu_aaaFgvRYMQVS2L8Ddudbo', // Presa dal tuo JSON
          appId: '1:1060927868658:android:84884a85cd60c4e8084a6b', // Presa dal tuo JSON
          messagingSenderId: '1060927868658',
          projectId: 'cid-app-sincro',
          storageBucket: 'cid-app-sincro.firebasestorage.app',
          databaseURL: 'https://cid-app-sincro-default-rtdb.europe-west1.firebasedatabase.app',
        );

    // =======================================================
    // 🍎 CONFIGURAZIONE iOS (Compilata con i tuoi dati PLIST)
    // =======================================================
      case TargetPlatform.iOS:
        return const FirebaseOptions(
          apiKey: 'AIzaSyBDEXTqdXbwNVeK4yy8m9uMwk1xzeSYWJ8',
          appId: '1:1060927868658:ios:be05f4b773c220e3084a6b',
          messagingSenderId: '1060927868658',
          projectId: 'cid-app-sincro',
          storageBucket: 'cid-app-sincro.firebasestorage.app',
          databaseURL: 'https://cid-app-sincro-default-rtdb.europe-west1.firebasedatabase.app',
          iosBundleId: 'com.example.cidApp',
        );

      case TargetPlatform.macOS:
        throw UnsupportedError('MacOS not configured');
      case TargetPlatform.windows:
        throw UnsupportedError('Windows not configured');
      case TargetPlatform.linux:
        throw UnsupportedError('Linux not configured');
      default:
        throw UnsupportedError(
          'DefaultFirebaseOptions are not supported for this platform.',
        );
    }
  }
}
=== FILE: lib/build_cai_app.dart ===
import 'dart:io';

void main() async {
  print("🛠️  Avvio build...");

  // 1. Esegui la build
  var process = await Process.start('flutter', ['build', 'appbundle']);

  // Mostra l'output in tempo reale
  stdout.addStream(process.stdout);
  stderr.addStream(process.stderr);

  var exitCode = await process.exitCode;

  if (exitCode != 0) {
    print("❌ Errore nella build.");
    return;
  }

  // 2. Leggi la versione dal pubspec.yaml
  var pubspec = await File('pubspec.yaml').readAsLines();
  var versionLine = pubspec.firstWhere((line) => line.startsWith('version:'));
  var version = versionLine.split('version: ')[1].trim();

  // 3. DEFINIZIONE PERCORSI

  // A. DOVE SI TROVA ORA (Sempre nella cartella del progetto)
  var sourceFile = File('build/app/outputs/bundle/release/app-release.aab');

  // B. DOVE LO VUOI METTERE (Il tuo disco esterno)
  // Nota: Assicurati che la cartella "buid" esista o correggi in "build" se era un refuso
  var targetDirectory = '/Volumes/NVME-2TB/cai/buid';

  if (await sourceFile.exists()) {
    // Crea la directory sul disco esterno se non esiste (per sicurezza)
    await Directory(targetDirectory).create(recursive: true);

    // Crea il percorso completo di destinazione
    var newPath = '$targetDirectory/CAI_App_v$version.aab';

    // Esegue la copia
    await sourceFile.copy(newPath);

    print("✅ File creato con successo!");
    print("📂 Destinazione: $newPath");
  } else {
    print("❌ Impossibile trovare il file generato in build/app/outputs/...");
  }
}
=== FILE: lib/comp_12.dart ===
// Versione: FINAL - SLIVER LAYOUT (Footer Sicuro e Testi Corretti)
import 'package:flutter/material.dart';
import 'global_data.dart';
import 'comp_13.dart'; // IMPORTA IL GRAFICO
import 'comp_15.dart'; // IMPORTA LE FIRME

class Comp12Screen extends StatefulWidget {
  const Comp12Screen({super.key});

  @override
  _Comp12ScreenState createState() => _Comp12ScreenState();
}

class _Comp12ScreenState extends State<Comp12Screen> {
  final List<String> _testiCircostanze = [
    "1. In fermata / in sosta",
    "2. Ripartiva dopo una sosta / apriva una portiera",
    "3. Stava parcheggiando",
    "4. Usciva da un parcheggio / luogo privato",
    "5. Entrava in un parcheggio / luogo privato",
    "6. Si immetteva in una piazza a senso rotatorio",
    "7. Circolava su una piazza a senso rotatorio",
    "8. Tamponava procedendo nello stesso senso",
    "9. Procedeva nello stesso senso ma in fila diversa",
    "10. Cambiava fila",
    "11. Sorpassava",
    "12. Girava a destra",
    "13. Girava a sinistra",
    "14. Retrocedeva",
    "15. Invadeva la sede stradale riservata",
    "16. Proveniva da destra",
    "17. Non osservava il segnale di precedenza/semaforo"
  ];

  bool _isReady = false;

  @override
  void initState() {
    super.initState();
    _inizializzaPagina();
  }

  Future<void> _inizializzaPagina() async {
    await Future.delayed(const Duration(milliseconds: 200));
    if (mounted) {
      setState(() => _isReady = true);

      // MOSTRA IL POPUP ANIMATO ALL'AVVIO
      WidgetsBinding.instance.addPostFrameCallback((_) => _mostraInfoPopup(context));
    }
  }

  // --- POPUP INFORMATIVO ANIMATO ---
  void _mostraInfoPopup(BuildContext context) {
    bool isB = GlobalData.latoCorrente == 'B';
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.fact_check, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Circostanze Incidente", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("Indica l'esatta dinamica del Veicolo ${GlobalData.latoCorrente} al momento dell'urto.", style: const TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.check_box_outlined, "Selezione Multipla", "Puoi spuntare anche più di una circostanza, ma assicurati che descrivano correttamente l'accaduto."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.warning_amber_rounded, "Attenzione", "Le circostanze selezionate in questa pagina sono fondamentali per stabilire la responsabilità del sinistro!"),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOutBack,
          reverseCurve: Curves.easeInBack,
        );

        var curveOpacita = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
          reverseCurve: Curves.easeIn,
        );

        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0.0, 0.4),
            end: Offset.zero,
          ).animate(curvePosizione),
          child: FadeTransition(
            opacity: curveOpacita,
            child: child,
          ),
        );
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  void _prosegui() {
    bool isB = GlobalData.latoCorrente == 'B';

    if (isB) {
      // IL LATO B SALTA IL GRAFICO E VA DIRETTAMENTE ALLE FIRME (15)
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => const Comp15Screen()),
      );
    } else {
      // IL LATO A VA AL GRAFICO (13)
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => const Comp13Screen()),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    bool isB = GlobalData.latoCorrente == 'B';
    Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgCol = isB ? const Color(0xFFFFF9C4) : const Color(0xFFF5F7FA);

    if (!_isReady) {
      return Scaffold(backgroundColor: bgCol, body: Container());
    }

    return Scaffold(
      backgroundColor: bgCol,
      appBar: AppBar(
        title: Text("12. Circostanze (${GlobalData.latoCorrente})"),
        backgroundColor: mainCol,
        foregroundColor: isB ? Colors.black : Colors.white,
      ),

      // --- SLIVER LAYOUT ---
      body: SafeArea(
        child: CustomScrollView(
          physics: const BouncingScrollPhysics(),
          slivers: [
            // 1. Header (Testo Istruzioni)
            SliverToBoxAdapter(
              child: Container(
                padding: const EdgeInsets.all(15),
                color: Colors.white,
                margin: const EdgeInsets.only(bottom: 1),
                child: Text(
                  "Seleziona le circostanze per il veicolo ${GlobalData.latoCorrente}.",
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: mainCol),
                ),
              ),
            ),

            // 2. Lista Scrollabile (Le 17 Checkbox)
            SliverList(
              delegate: SliverChildBuilderDelegate(
                    (context, index) {
                  int circIndex = index + 1;
                  bool isChecked = isB
                      ? (GlobalData.circostanzeB[circIndex] ?? false)
                      : (GlobalData.circostanzeA[circIndex] ?? false);

                  return Column(
                    children: [
                      Container(
                        color: Colors.white,
                        child: CheckboxListTile(
                          activeColor: mainCol,
                          contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                          title: Text("${circIndex}. ${_testiCircostanze[index]}", style: const TextStyle(fontSize: 14)),
                          value: isChecked,
                          onChanged: (bool? val) {
                            setState(() {
                              if (isB) {
                                GlobalData.circostanzeB[circIndex] = val ?? false;
                              } else {
                                GlobalData.circostanzeA[circIndex] = val ?? false;
                              }
                            });
                          },
                        ),
                      ),
                      const Divider(height: 1, thickness: 1, indent: 16, endIndent: 16),
                    ],
                  );
                },
                childCount: _testiCircostanze.length,
              ),
            ),

            // 3. Piè di pagina elastico (Bottoni)
            SliverFillRemaining(
              hasScrollBody: false,
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Container(
                  padding: const EdgeInsets.all(20),
                  child: _navButtons(context, mainCol, isB),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _navButtons(BuildContext context, Color color, bool isB) {
    return Row(
      children: [
        // Tasto INDIETRO (Expanded flex 1)
        Expanded(
            flex: 4, // Proporzione 4/10
            child: OutlinedButton(
                onPressed: () => Navigator.pop(context),
                style: OutlinedButton.styleFrom(
                  minimumSize: const Size(0, 55),
                  padding: const EdgeInsets.symmetric(horizontal: 5), // Padding ridotto
                ),
                // FittedBox evita che il testo vada a capo se lo spazio è poco
                child: const FittedBox(
                    child: Text("INDIETRO", style: TextStyle(fontWeight: FontWeight.bold))
                )
            )
        ),
        const SizedBox(width: 15),

        // Tasto SALVA E PROCEDI (Expanded flex 2)
        Expanded(
            flex: 6, // Proporzione 6/10 (più largo)
            child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                    backgroundColor: color,
                    foregroundColor: isB ? Colors.black : Colors.white,
                    minimumSize: const Size(0, 55)
                ),
                onPressed: _prosegui,
                child: const FittedBox(
                    child: Text("SALVA E PROCEDI", style: TextStyle(fontWeight: FontWeight.bold))
                )
            )
        ),
      ],
    );
  }
}
=== FILE: lib/utils/cai_constants.dart ===
class CaiMapping {
  static const Map<String, String> fields = {
    // --- 1. INFORMAZIONI GENERALI ---
    'dataIncidente': 'data sinistro',
    'oraIncidente': 'ora',
    'luogoIncidente': 'luogo sinistro',

    // --- 2. VEICOLO A (Colonna Sinistra) ---
    // Contraente/Assicurato A
    'cognomeContraenteA': 'cognome',
    'nomeContraenteA': 'nome',
    'codiceFiscaleA': 'codice fiscale',
    'comuneA': 'comune',
    'capA': 'cap',
    'statoA': 'stato',
    // Dati Veicolo A
    'marcaVeicoloA': 'marca e tipo',
    'targaA': 'targa',
    'statoImmatricolazioneA': 'stato immatricolazione',
    // Compagnia Assicurativa A
    'compagniaA': 'COMPAGNIA',
    'numeroPolizzaA': 'numero polizza',
    'agenziaA': 'AGENZIA',
    // Conducente A (ATTENZIONE: Refuso 'cogmome' nel PDF originale)
    'cognomeConducenteA': 'cogmome',
    'nomeConducenteA': 'Nome',
    'codiceFiscaleConducenteA': 'Codice fiscale',
    'patenteA': 'numero patente',

    // --- 3. VEICOLO B (Colonna Destra) ---
    // Contraente/Assicurato B
    'cognomeContraenteB': 'Cognome assicurato',
    'nomeContraenteB': 'Nome Assicurato',
    'codiceFiscaleB': 'codice fiscale assicurato',
    'comuneB': 'comune/prov/indirizzo',
    // Dati Veicolo B
    'marcaVeicoloB': 'marca e modello',
    'targaB': 'targa1',
    'statoImmatricolazioneB': 'stato immatricolazione1',
    // Compagnia Assicurativa B
    'compagniaB': 'compagnia1',
    'numeroPolizzaB': 'numero polizza1',
    'agenziaB': 'agenzia1',
    // Conducente B
    'cognomeConducenteB': 'cognome1',
    'nomeConducenteB': 'nome1',
    'codiceFiscaleConducenteB': 'codice fiscale1',
    'patenteB': 'num patente',

    // --- 4. TESTIMONI E OSSERVAZIONI ---
    'testimone1': '1° teste',
    'testimone2': '2° teste',
    'osservazioniA': 'osservazioni',
    'osservazioniB': 'osservazioni1',
  };
}
=== FILE: lib/test_scraping.dart ===
import 'package:flutter/material.dart';
import 'verifica_rca_screen.dart'; // Assicurati che l'import sia corretto

void main() {
  runApp(const MaterialApp(
    home: TestScrapingPage(),
  ));
}

class TestScrapingPage extends StatefulWidget {
  const TestScrapingPage({super.key});

  @override
  _TestScrapingPageState createState() => _TestScrapingPageState();
}

class _TestScrapingPageState extends State<TestScrapingPage> {
  // Metti una targa vera qui per fare prima nei test
  final TextEditingController _targaController = TextEditingController(text: "AB123CD");
  String _risultato = "Nessun dato ancora";

  void _lanciaVerifica() async {
    // 1. Lancia la schermata di verifica
    final dataScadenza = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => VerificaRcaScreen(targa: _targaController.text),
      ),
    );

    // 2. Quando torni indietro, se c'è un risultato, mostralo
    if (dataScadenza != null) {
      setState(() {
        _risultato = "Scadenza trovata: $dataScadenza";
      });

      // Feedback visivo
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("Data importata: $dataScadenza"), backgroundColor: Colors.green),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("TEST SCRAPING RCA"), backgroundColor: Colors.orange),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("Inserisci una targa reale per testare:", style: TextStyle(fontSize: 16)),
            const SizedBox(height: 10),
            TextField(
              controller: _targaController,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: "Targa",
                hintText: "Es. GA000GA",
              ),
              textCapitalization: TextCapitalization.characters,
            ),
            const SizedBox(height: 30),
            ElevatedButton.icon(
              onPressed: _lanciaVerifica,
              icon: const Icon(Icons.search),
              label: const Text("VERIFICA COPERTURA"),
              style: ElevatedButton.styleFrom(
                minimumSize: const Size(double.infinity, 50),
                textStyle: const TextStyle(fontSize: 18),
              ),
            ),
            const SizedBox(height: 40),
            const Divider(),
            const Text("RISULTATO:", style: TextStyle(fontWeight: FontWeight.bold, color: Colors.grey)),
            const SizedBox(height: 10),
            Text(
              _risultato,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue),
            ),
          ],
        ),
      ),
    );
  }
}
=== FILE: lib/main.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

// ⚠️ IMPORTANTE: Assicurati che questo file esista (generato da flutterfire configure)
import 'firebase_options.dart';

import 'global_data.dart';
import 'scelta_lato.dart';
import 'carro_attr.dart';
import 'ps.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 1. BLOCCO INIZIALE VERTICALE
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

  // 2. INIZIALIZZAZIONE FIREBASE CON BIVIO IOS/ANDROID
  // Il controllo .isEmpty evita il crash "Duplicate App" durante il debug
  if (Firebase.apps.isEmpty) {
    await Firebase.initializeApp(
      // Questa riga gestisce automaticamente il bivio tra le chiavi Android e iOS
      // leggendole dal file firebase_options.dart
      options: DefaultFirebaseOptions.currentPlatform,
    );
  }

  _effettuaLoginAnonimo();
  runApp(const MyApp());
}

Future<void> _effettuaLoginAnonimo() async {
  try {
    if (FirebaseAuth.instance.currentUser == null) {
      await FirebaseAuth.instance.signInAnonymously();
      debugPrint("✅ Login anonimo effettuato.");
    }
  } catch (e) {
    debugPrint("⚠️ Login anonimo fallito (ritento tra 2s): $e");
    Future.delayed(const Duration(seconds: 2), _effettuaLoginAnonimo);
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'La tua App CAI',
      debugShowCheckedModeBanner: false,

      // --- IMPOSTIAMO I COLORI GLOBALI DEL CALENDARIO E DELL'APP ---
      theme: ThemeData.light().copyWith(
        colorScheme: const ColorScheme.light(
          primary: Color(0xFF1565C0), // Blu (usato per i calendari)
          onPrimary: Colors.white,
          onSurface: Colors.black,
        ),
      ),

      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('it', 'IT'),
      ],

      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with RouteAware {

  @override
  void initState() {
    super.initState();
    // Al primo avvio puliamo tutto
    _resetCompleto();
  }

  // Metodo centralizzato per reset e orientamento
  Future<void> _resetCompleto() async {
    GlobalData.reset();
    await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    debugPrint("🏠 Home: Dati resettati e Verticale forzato.");
  }

  @override
  Widget build(BuildContext context) {
    // Intercettiamo il "ritorno" alla home per forzare il verticale
    // (utile se si torna indietro con gesture o tasto back fisico)
    return PopScope(
      canPop: false, // La home è la root, non si esce
      child: Scaffold(
        extendBodyBehindAppBar: true,
        appBar: AppBar(
          title: const Text(
              'CAI Facile',
              style: TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.5, fontSize: 24)
          ),
          centerTitle: true,
          backgroundColor: Colors.blue.shade900.withOpacity(0.95),
          foregroundColor: Colors.white,
          elevation: 10,
          shape: const RoundedRectangleBorder(
              borderRadius: BorderRadius.vertical(bottom: Radius.circular(20))
          ),
        ),
        body: Stack(
          children: [
            // 1. Sfondo Base (Mappa)
            const Positioned.fill(child: BackgroundImage()),



            // Contenuto
            SafeArea(
              child: Center(
                child: SingleChildScrollView(
                  physics: const BouncingScrollPhysics(),
                  child: Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [

                        // 1. Compila Sinistro
                        _buildButton3D(
                          context: context,
                          label: "COMPILA SINISTRO",
                          icon: Icons.assignment_outlined,
                          baseColor: Colors.blue.shade800,
                          onTap: () async {
                            // Reset esplicito prima di iniziare
                            await _resetCompleto();
                            if (context.mounted) {
                              Navigator.push(
                                  context,
                                  MaterialPageRoute(builder: (c) => const SceltaLatoScreen())
                              ).then((_) {
                                // Quando l'utente torna indietro dalla compilazione,
                                // forziamo di nuovo il reset e il verticale
                                _resetCompleto();
                              });
                            }
                          },
                        ),

                        const SizedBox(height: 25),

                        // 2. Carro Attrezzi
                        _buildButton3D(
                          context: context,
                          label: "SOS CARRO ATTREZZI",
                          icon: Icons.support_agent,
                          baseColor: Colors.red.shade800,
                          onTap: () {
                            Navigator.push(context, MaterialPageRoute(builder: (c) => const CarroAttrezziScreen()));
                          },
                        ),

                        const SizedBox(height: 25),

                        // 3. Pronto Soccorso
                        _buildButton3D(
                          context: context,
                          label: "PRONTO SOCCORSO",
                          icon: Icons.local_hospital_outlined,
                          baseColor: Colors.green.shade800,
                          onTap: () {
                            Navigator.push(context, MaterialPageRoute(builder: (c) => const ProntoSoccorsoScreen()));
                          },
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  // Widget helper per i bottoni con effetto 3D
  Widget _buildButton3D({
    required BuildContext context,
    required String label,
    required IconData icon,
    required Color baseColor,
    required VoidCallback onTap,
  }) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        boxShadow: [
          BoxShadow(color: Colors.black.withOpacity(0.4), offset: const Offset(0, 6), blurRadius: 8, spreadRadius: 1)
        ],
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [
            baseColor.withOpacity(0.9),
            baseColor,
            baseColor.withRed((baseColor.red - 20).clamp(0, 255))
          ],
        ),
      ),
      child: Material(
        color: Colors.transparent,
        child: InkWell(
          borderRadius: BorderRadius.circular(16),
          onTap: onTap,
          splashColor: Colors.white.withOpacity(0.2),
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
            child: Row(
              children: [
                Icon(icon, size: 32, color: Colors.white),
                const SizedBox(width: 20),
                Expanded(
                    child: Text(
                        label,
                        style: const TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.w800,
                            fontSize: 18,
                            letterSpacing: 1.0
                        )
                    )
                ),
                Icon(Icons.arrow_forward_ios, size: 18, color: Colors.white.withOpacity(0.7)),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

// Widget Sfondo
class BackgroundImage extends StatelessWidget {
  const BackgroundImage({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color(0xFFF0F4F8),
      child: Image.asset(
        'assets/sfondo_mappa.jpg',
        fit: BoxFit.cover,
        color: const Color(0xFFF0F4F8).withOpacity(0.6),
        colorBlendMode: BlendMode.lighten,
        errorBuilder: (c, e, s) => Container(color: Colors.grey.shade200),
      ),
    );
  }
}
=== FILE: lib/verifica_rca_screen.dart ===
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

class VerificaRcaScreen extends StatefulWidget {
  final String targa;

  const VerificaRcaScreen({super.key, required this.targa});

  @override
  _VerificaRcaScreenState createState() => _VerificaRcaScreenState();
}

class _VerificaRcaScreenState extends State<VerificaRcaScreen> {
  InAppWebViewController? webViewController;
  bool isLoading = true;
  String? dataScadenzaTrovata;
  bool ricercaFallita = false;

  final String urlPortale = "https://www.ilportaledellautomobilista.it/web/portale-automobilista/verifica-copertura-rc";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Verifica Copertura RCA"),
        backgroundColor: Colors.blue[900],
        foregroundColor: Colors.white,
      ),
      body: Stack(
        children: [
          // 1. WEBVIEW (Il motore nascosto/mascherato)
          InAppWebView(
            initialUrlRequest: URLRequest(url: WebUri(urlPortale)),
            initialSettings: InAppWebViewSettings(
              javaScriptEnabled: true,
              supportZoom: false,
            ),
            onWebViewCreated: (controller) {
              webViewController = controller;
            },
            onLoadStop: (controller, url) async {
              setState(() { isLoading = false; });
              // Appena caricata, nascondiamo la grafica del sito
              await _preparaPagina();
            },
            onProgressChanged: (controller, progress) {
              // Ogni volta che la pagina cambia (es. dopo il click su Cerca), controlliamo se c'è il risultato
              if (progress == 100) {
                _cercaRisultato();
              }
            },
          ),

          // 2. LOADER / SCHERMATA SUCCESSO (Copre la WebView quando serve)
          if (isLoading || dataScadenzaTrovata != null || ricercaFallita)
            Container(
              color: Colors.white,
              width: double.infinity,
              height: double.infinity,
              child: Center(
                child: _buildOverlayContent(),
              ),
            ),
        ],
      ),
    );
  }

  Widget _buildOverlayContent() {
    if (ricercaFallita) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Icon(Icons.error_outline, color: Colors.red, size: 60),
          const SizedBox(height: 20),
          const Text("Veicolo non assicurato\no targa errata", textAlign: TextAlign.center, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          const SizedBox(height: 30),
          ElevatedButton(
            onPressed: () {
              setState(() {
                ricercaFallita = false;
                isLoading = false; // Rimostra la webview per riprovare
                webViewController?.reload();
              });
            },
            child: const Text("Riprova"),
          )
        ],
      );
    }

    if (dataScadenzaTrovata != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Icon(Icons.check_circle, color: Colors.green, size: 80),
          const SizedBox(height: 20),
          const Text("Scadenza Trovata!", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
          const SizedBox(height: 10),
          Text(dataScadenzaTrovata!, style: TextStyle(fontSize: 30, color: Colors.blue[900], fontWeight: FontWeight.bold)),
          const SizedBox(height: 40),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.blue[900],
              foregroundColor: Colors.white,
              padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15),
            ),
            onPressed: () {
              Navigator.pop(context, dataScadenzaTrovata);
            },
            child: const Text("USA QUESTA DATA", style: TextStyle(fontSize: 18)),
          )
        ],
      );
    }

    return const CircularProgressIndicator();
  }

  // --- FUNZIONI DI SCRAPING ---

  Future<void> _preparaPagina() async {
    if (webViewController == null) return;

    // 1. INIEZIONE CSS: Stile "App Mobile"
    await webViewController!.evaluateJavascript(source: """
      // Nascondi tutto il contorno inutile
      var elementsToHide = document.querySelectorAll('header, footer, .navbar, .breadcrumb, #cookie-bar, .portlet-title, .lfr-meta-actions');
      elementsToHide.forEach(el => el.style.display = 'none');

      var mainForm = document.querySelector('form'); 
      
      if(mainForm) {
        document.body.innerHTML = '';
        document.body.appendChild(mainForm);
        document.body.style.backgroundColor = '#ffffff';
        document.body.style.padding = '20px';
        document.body.style.fontFamily = 'sans-serif';
      }
    """);

    // 2. INIEZIONE JS: Compilazione e UX
    await webViewController!.evaluateJavascript(source: """
      // A. Compila Targa
      var campoTarga = document.getElementById('targa');
      if (campoTarga) {
        campoTarga.value = '${widget.targa}';
        campoTarga.style.fontSize = '24px';
        campoTarga.style.fontWeight = 'bold';
        campoTarga.style.textAlign = 'center';
        campoTarga.style.border = '2px solid #1565C0';
        campoTarga.readOnly = true;
      }

      // B. Seleziona "Autoveicolo"
      var selectVeicolo = document.querySelector('select');
      if (selectVeicolo) {
         for (var i = 0; i < selectVeicolo.options.length; i++) {
           if (selectVeicolo.options[i].text.toLowerCase().includes('auto')) {
             selectVeicolo.selectedIndex = i;
             break;
           }
         }
         // Nascondi la select e la sua label
         selectVeicolo.style.display = 'none'; 
         if(selectVeicolo.previousElementSibling) selectVeicolo.previousElementSibling.style.display = 'none';
      }

      // C. Restyling Bottone Ricerca
      var btn = document.querySelector("input[name='ricercaCoperturaVeicolo']");
      if (btn) {
        btn.style.cssText = ''; 
        btn.style.width = '100%';
        btn.style.height = '60px';
        btn.style.backgroundColor = '#1565C0';
        btn.style.color = 'white';
        btn.style.border = 'none';
        btn.style.borderRadius = '12px';
        btn.style.fontSize = '20px';
        btn.style.marginTop = '30px';
        btn.value = 'CERCA SCADENZA';
      }

      // D. Focus sul Captcha
      var campoCaptcha = document.querySelector("input[name*='captcha']");
      if(campoCaptcha) {
        campoCaptcha.placeholder = 'Inserisci i caratteri qui';
        campoCaptcha.style.height = '50px';
        campoCaptcha.style.fontSize = '20px';
        campoCaptcha.style.textAlign = 'center';
        campoCaptcha.style.marginTop = '10px';
        campoCaptcha.scrollIntoView();
      }
    """);
  }

  Future<void> _cercaRisultato() async {
    if (webViewController == null) return;

    // Leggiamo tutto l'HTML della pagina
    String? html = await webViewController!.getHtml();
    if (html == null) return;

    // CASO 1: SUCCESSO
    if (html.contains("Scadenza copertura")) {
      // Eseguiamo JS per estrarre la data precisa
      var dataEstratta = await webViewController!.evaluateJavascript(source: """
        (function() {
           // Cerca tutti i 'td' (celle di tabella)
           var cells = document.querySelectorAll('td');
           for (var i = 0; i < cells.length; i++) {
             // Se la cella contiene la label...
             if (cells[i].innerText.includes('Scadenza copertura')) {
                // ...prendi il testo della cella successiva (dove c'è la data)
                var nextCell = cells[i].nextElementSibling;
                return nextCell ? nextCell.innerText : null;
             }
           }
           return null;
        })();
      """);

      if (dataEstratta != null && dataEstratta.toString().trim().isNotEmpty) {
        setState(() {
          dataScadenzaTrovata = dataEstratta.toString().trim();
        });
      }
    }
    // CASO 2: FALLIMENTO (Non assicurata o targa errata)
    else if (html.contains("dal controllo non risulta coperto") || html.contains("Targa non trovata")) {
      setState(() {
        ricercaFallita = true;
      });
    }
    // CASO 3: ANCORA NEL FORM (Es. captcha errato)
    else {
      // Riapplichiamo lo stile grafico perché il reload della pagina potrebbe averlo resettato
      _preparaPagina();
    }
  }
}
=== FILE: lib/comp_10.dart ===
// Versione: FINAL - FIX CONTATORE VISIBILE
import 'package:flutter/material.dart';
import 'global_data.dart';
import 'comp_12.dart';

class Comp10Screen extends StatefulWidget {
  const Comp10Screen({super.key});

  @override
  _Comp10ScreenState createState() => _Comp10ScreenState();
}

class _Comp10ScreenState extends State<Comp10Screen> {
  // Set per gestire selezioni multiple uniche
  Set<String> _selectedSectors = {};

  final double _canvasWidth = 300.0;
  final double _canvasHeight = 220.0;
  late TextEditingController _controllerDanni;
  late TextEditingController _controllerOsservazioni;
  final bool isB = GlobalData.latoCorrente == 'B';
  late Map<String, Rect> _hitboxes;

  @override
  void initState() {
    super.initState();
    _selectedSectors = isB
        ? Set.from(GlobalData.puntiUrtoB_List)
        : Set.from(GlobalData.puntiUrtoA_List);

    _controllerDanni = TextEditingController(text: isB ? GlobalData.danni_visibili_B : GlobalData.danni_visibili_A);
    _controllerOsservazioni = TextEditingController(text: isB ? GlobalData.osservazioni_B : GlobalData.osservazioni_A);
    _hitboxes = isB ? _getHitboxesB() : _getHitboxesA();

    // MOSTRA IL POPUP INFORMATIVO ANIMATO AL CARICAMENTO
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _mostraInfoPopup(context);
    });
  }

  // --- POPUP INFORMATIVO ---
  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.minor_crash, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Danni e Osservazioni", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("In questa sezione indicherai i danni subiti dal Veicolo ${GlobalData.latoCorrente}.", style: const TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.touch_app, "Punto d'urto", "Tocca direttamente sull'immagine per inserire una 'X' nel punto d'urto. Puoi selezionare più punti. Tocca di nuovo per rimuovere la 'X'."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.edit_document, "Danni Visibili", "Descrivi brevemente i danni visibili (es. 'Paraurti rotto')."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.comment, "Osservazioni", "Aggiungi eventuali commenti personali sulla dinamica (opzionale)."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOutBack,
          reverseCurve: Curves.easeInBack,
        );
        var curveOpacita = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
          reverseCurve: Curves.easeIn,
        );
        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0.0, 0.4),
            end: Offset.zero,
          ).animate(curvePosizione),
          child: FadeTransition(
            opacity: curveOpacita,
            child: child,
          ),
        );
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  // --- MAPPATURA LATO A (BLU) ---
  Map<String, Rect> _getHitboxesA() {
    return {
      '9':  const Rect.fromLTWH(35, 85, 40, 40),
      '10': const Rect.fromLTWH(25, 110, 25, 50),
      '11': const Rect.fromLTWH(60, 110, 25, 50),
      '12': const Rect.fromLTWH(35, 175, 40, 40),
      '1':  const Rect.fromLTWH(90, 50, 35, 40),
      '8':  const Rect.fromLTWH(127, 50, 35, 40),
      '2':  const Rect.fromLTWH(87, 90, 30, 60),
      '7':  const Rect.fromLTWH(138, 90, 30, 60),
      '3':  const Rect.fromLTWH(80, 150, 35, 40),
      '6':  const Rect.fromLTWH(130, 150, 30, 40),
      '4':  const Rect.fromLTWH(100, 190, 25, 30),
      '5':  const Rect.fromLTWH(135, 190, 25, 30),
      '13': const Rect.fromLTWH(180, 35, 30, 40),
      '14': const Rect.fromLTWH(210, 35, 30, 40),
      '15': const Rect.fromLTWH(240, 35, 30, 40),
      '16': const Rect.fromLTWH(172, 75, 30, 70),
      '17': const Rect.fromLTWH(240, 75, 30, 70),
      '19': const Rect.fromLTWH(165, 145, 40, 60),
      '18': const Rect.fromLTWH(238, 145, 40, 60),
      '20': const Rect.fromLTWH(200, 195, 50, 25),
    };
  }

  // --- MAPPATURA LATO B (GIALLO) ---
  Map<String, Rect> _getHitboxesB() {
    return {
      'M9':  const Rect.fromLTWH(35, 78, 40, 40),
      'M10': const Rect.fromLTWH(25, 110, 25, 50),
      'M11': const Rect.fromLTWH(60, 110, 25, 50),
      'M12': const Rect.fromLTWH(35, 175, 40, 40),
      '21': const Rect.fromLTWH(88, 50, 35, 40),
      '22': const Rect.fromLTWH(130, 50, 35, 40),
      '23': const Rect.fromLTWH(85, 90, 30, 60),
      '24': const Rect.fromLTWH(140, 90, 30, 60),
      '25': const Rect.fromLTWH(95, 190, 25, 30),
      '26': const Rect.fromLTWH(138, 190, 25, 30),
      '27': const Rect.fromLTWH(180, 35, 30, 40),
      '34': const Rect.fromLTWH(210, 35, 30, 40),
      '28': const Rect.fromLTWH(240, 35, 30, 40),
      '29': const Rect.fromLTWH(170, 75, 30, 90),
      '30': const Rect.fromLTWH(245, 75, 30, 90),
      '31': const Rect.fromLTWH(168, 171, 40, 60),
      '33': const Rect.fromLTWH(208, 178, 31, 60),
      '32': const Rect.fromLTWH(239, 171, 40, 60),
    };
  }

  void _handleTap(TapUpDetails details) {
    Offset touchPosition = details.localPosition;
    String? foundSector;
    _hitboxes.forEach((key, rect) {
      if (rect.contains(touchPosition)) {
        foundSector = key;
      }
    });

    if (foundSector != null) {
      setState(() {
        if (_selectedSectors.contains(foundSector)) {
          _selectedSectors.remove(foundSector);
        } else {
          _selectedSectors.add(foundSector!);
        }
      });
    }
  }

  void _salvaEProsegui() {
    setState(() {
      if (isB) {
        GlobalData.puntiUrtoB_List = _selectedSectors.toList();
        GlobalData.danni_visibili_B = _controllerDanni.text.toUpperCase();
        GlobalData.osservazioni_B = _controllerOsservazioni.text.toUpperCase();
      } else {
        GlobalData.puntiUrtoA_List = _selectedSectors.toList();
        GlobalData.danni_visibili_A = _controllerDanni.text.toUpperCase();
        GlobalData.osservazioni_A = _controllerOsservazioni.text.toUpperCase();
      }
    });
    Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp12Screen()));
  }

  @override
  Widget build(BuildContext context) {
    Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgCol = isB ? const Color(0xFFFFF9C4) : const Color(0xFFE3F2FD);

    return GestureDetector(
      onTap: () => FocusScope.of(context).unfocus(),
      child: Scaffold(
        backgroundColor: bgCol,
        appBar: AppBar(
          title: Text("10, 11, 14. Dettagli (${GlobalData.latoCorrente})"),
          backgroundColor: mainCol,
          foregroundColor: isB ? Colors.black : Colors.white,
        ),

        // --- SLIVER LAYOUT ---
        body: SafeArea(
          child: CustomScrollView(
            physics: const BouncingScrollPhysics(),
            slivers: [
              SliverPadding(
                padding: const EdgeInsets.all(16),
                sliver: SliverList(
                  delegate: SliverChildListDelegate([
                    _buildTitle("10. PUNTO D'URTO INIZIALE (Seleziona anche più di uno)", mainCol),
                    const SizedBox(height: 10),
                    Center(
                      child: Card(
                        elevation: 4,
                        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
                        child: GestureDetector(
                          onTapUp: _handleTap,
                          child: Container(
                            width: _canvasWidth,
                            height: _canvasHeight,
                            decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15)),
                            child: Stack(
                              children: [
                                Center(child: Image.asset(
                                  isB ? 'assets/punti_danni_B.png' : 'assets/punti_danni_A.png',
                                  width: _canvasWidth, height: _canvasHeight, fit: BoxFit.contain,
                                )),
                                ..._selectedSectors.map((sectorId) {
                                  if (_hitboxes.containsKey(sectorId)) {
                                    return CustomPaint(
                                      painter: XPainter(_hitboxes[sectorId]!),
                                      size: Size(_canvasWidth, _canvasHeight),
                                    );
                                  }
                                  return Container();
                                }),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                    if (_selectedSectors.isNotEmpty)
                      Padding(
                        padding: const EdgeInsets.only(top: 8.0),
                        child: Text("Punti: ${_selectedSectors.join(', ')}",
                            style: TextStyle(color: mainCol, fontWeight: FontWeight.bold)),
                      ),

                    const Divider(height: 30),

                    _buildTitle("11. DANNI VISIBILI", mainCol),
                    TextField(
                      controller: _controllerDanni,
                      // Max 45 caratteri per stare nelle 2 righe del PDF (20+25)
                      maxLength: 45,
                      maxLines: 2,
                      keyboardType: TextInputType.multiline,
                      textCapitalization: TextCapitalization.characters,
                      decoration: _inputDeco("Es: Paraurti ant, Faro sx..."),
                    ),

                    const SizedBox(height: 10),

                    _buildTitle("14. OSSERVAZIONI", mainCol),
                    TextField(
                      controller: _controllerOsservazioni,
                      maxLength: 55,
                      maxLines: 2,
                      keyboardType: TextInputType.multiline,
                      textCapitalization: TextCapitalization.sentences,
                      decoration: _inputDeco("Es: Ho ragione io perché..."),
                    ),
                  ]),
                ),
              ),

              // --- STICKY FOOTER ---
              SliverFillRemaining(
                hasScrollBody: false,
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    padding: const EdgeInsets.all(16),
                    child: _navButtons(context, mainCol),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildTitle(String text, Color color) {
    return Align(alignment: Alignment.centerLeft, child: Padding(
      padding: const EdgeInsets.only(bottom: 8.0, top: 10.0),
      child: Text(text, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: color)),
    ));
  }

  InputDecoration _inputDeco(String hint) {
    return InputDecoration(
      hintText: hint,
      filled: true,
      fillColor: Colors.white,
      border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
      contentPadding: const EdgeInsets.all(15),
      // counterText: "",  <-- RIMOSSO: Ora il contatore si vede!
    );
  }

  Widget _navButtons(BuildContext context, Color color) {
    return Row(
      children: [
        Expanded(
            flex: 4,
            child: OutlinedButton(
                onPressed: () => Navigator.pop(context),
                style: OutlinedButton.styleFrom(
                  minimumSize: const Size(0, 55),
                  padding: const EdgeInsets.symmetric(horizontal: 5),
                ),
                child: const FittedBox(
                    child: Text("INDIETRO", style: TextStyle(fontWeight: FontWeight.bold))
                )
            )
        ),
        const SizedBox(width: 15),
        Expanded(
            flex: 6,
            child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                    backgroundColor: color,
                    foregroundColor: isB ? Colors.black : Colors.white,
                    minimumSize: const Size(0, 55)
                ),
                onPressed: _salvaEProsegui,
                child: const FittedBox(
                    child: Text("SALVA E PROSEGUI", style: TextStyle(fontWeight: FontWeight.bold))
                )
            )
        ),
      ],
    );
  }
}

class XPainter extends CustomPainter {
  final Rect targetRect;
  XPainter(this.targetRect);

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()..color = Colors.red..strokeWidth = 3.0..strokeCap = StrokeCap.round..style = PaintingStyle.stroke;
    double cx = targetRect.left + targetRect.width / 2;
    double cy = targetRect.top + targetRect.height / 2;
    double iconSize = 10.0;
    canvas.drawLine(Offset(cx - iconSize, cy - iconSize), Offset(cx + iconSize, cy + iconSize), paint);
    canvas.drawLine(Offset(cx + iconSize, cy - iconSize), Offset(cx - iconSize, cy + iconSize), paint);
  }
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
=== FILE: lib/comp_8.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'comp_9.dart';
import 'global_data.dart';

class DateInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var text = newValue.text.replaceAll('/', '');
    if (text.length > 8) text = text.substring(0, 8);
    var result = "";
    for (int i = 0; i < text.length; i++) {
      if (i == 2 || i == 4) result += "/";
      result += text[i];
    }
    return newValue.copyWith(
        text: result,
        selection: TextSelection.collapsed(offset: result.length)
    );
  }
}

class Comp8Screen extends StatefulWidget {
  const Comp8Screen({super.key});
  @override
  _Comp8ScreenState createState() => _Comp8ScreenState();
}

class _Comp8ScreenState extends State<Comp8Screen> {
  late TextEditingController _polizza, _cartaVerde, _validoDal, _validoAl;
  late TextEditingController _agenzia, _denomAgenzia, _indirizzoAgenzia, _statoAgenzia, _telAgenzia;
  late TextEditingController _compagniaManuale;
  String? _selectedAssicurazione;
  bool _isManuale = false;
  late bool _danniMaterialiAssicurati;
  bool get isB => GlobalData.latoCorrente == 'B';
  String? _erroreValidoDal;
  String? _erroreValidoAl;

  @override
  void initState() {
    super.initState();
    _initControllers();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_validoDal.text.isNotEmpty) _validaDataDal(_validoDal.text);
      if (_validoAl.text.isNotEmpty) _validaDataAl(_validoAl.text);

      // MOSTRA IL POPUP ANIMATO ALL'AVVIO
      _mostraInfoPopup(context);
    });
  }

  void _initControllers() {
    String denominazioneSalvata = isB ? GlobalData.Denominazione_B : GlobalData.Denominazione_A;
    _polizza = TextEditingController(text: isB ? GlobalData.Numero_Polizza_B : GlobalData.Numero_Polizza_A);
    _cartaVerde = TextEditingController(text: isB ? GlobalData.N_carta_verde_B : GlobalData.N_carta_verde_A);
    _validoDal = TextEditingController(text: isB ? GlobalData.Data_Inizio_Dal_B : GlobalData.Data_Inizio_Dal_A);
    _validoAl = TextEditingController(text: isB ? GlobalData.Data_Scadenza_Al_B : GlobalData.Data_Scadenza_Al_A);
    _agenzia = TextEditingController(text: isB ? GlobalData.Agenzia_B : GlobalData.Agenzia_A);
    _denomAgenzia = TextEditingController(text: isB ? GlobalData.Denominazione_agenzia_B : GlobalData.Denominazione_agenzia_A);
    _indirizzoAgenzia = TextEditingController(text: isB ? GlobalData.Indirizzo_agenzia_B : GlobalData.Indirizzo_agenzia_A);
    _statoAgenzia = TextEditingController(text: (isB ? GlobalData.Stato_agenzia_B : GlobalData.Stato_agenzia_A).isEmpty ? "ITALIA" : (isB ? GlobalData.Stato_agenzia_B : GlobalData.Stato_agenzia_A));
    _telAgenzia = TextEditingController(text: isB ? GlobalData.N_tel_mail_agenzia_B : GlobalData.N_tel_mail_agenzia_A);
    _danniMaterialiAssicurati = isB ? GlobalData.FLAG_danni_mat_assicurati_B : GlobalData.FLAG_danni_mat_assicurati_A;
    _compagniaManuale = TextEditingController();

    if (denominazioneSalvata.isNotEmpty) {
      if (GlobalData.assicurazioni.containsKey(denominazioneSalvata)) {
        _selectedAssicurazione = denominazioneSalvata;
        _isManuale = (denominazioneSalvata == "ALTRO (Inserimento manuale)");
      } else {
        _selectedAssicurazione = "ALTRO (Inserimento manuale)";
        _compagniaManuale.text = denominazioneSalvata;
        _isManuale = true;
      }
    } else {
      _selectedAssicurazione = null;
      _isManuale = false;
    }
  }

  // --- POPUP INFORMATIVO ANIMATO ---
  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.business, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Compagnia di Assicurazione", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("Recupera i dati assicurativi per il Veicolo ${GlobalData.latoCorrente}.", style: const TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.description, "Polizza", "Il numero di polizza e le date di validità sono obbligatorie."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.calendar_today, "Date", "Usa l'icona del calendario per inserire rapidamente la data o scrivila manualmente nel formato GG/MM/AAAA."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.store, "Agenzia", "I dati dell'Agenzia sono facoltativi ma aiutano a velocizzare la pratica."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOutBack,
          reverseCurve: Curves.easeInBack,
        );

        var curveOpacita = CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
          reverseCurve: Curves.easeIn,
        );

        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0.0, 0.4),
            end: Offset.zero,
          ).animate(curvePosizione),
          child: FadeTransition(
            opacity: curveOpacita,
            child: child,
          ),
        );
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  String? _calcolaErroreData(String data) {
    if (data.isEmpty) return null; // Se vuoto non diamo errore immediato (ci pensa il tasto Salva)
    if (data.length < 10) return "Formato: GG/MM/AAAA"; // Avvisa subito se mancano cifre

    List<String> parti = data.split('/');
    if (parti.length != 3) return "Formato errato";

    int? giorno = int.tryParse(parti[0]);
    int? mese = int.tryParse(parti[1]);
    int? anno = int.tryParse(parti[2]);

    if (giorno == null || mese == null || anno == null) return "Data non valida";
    if (mese < 1 || mese > 12) return "Mese errato";

    int giorniMax = _giorniInMese(mese, anno);
    if (giorno < 1 || giorno > giorniMax) return "Giorno errato per questo mese";

    if (anno < 1900 || anno > 2100) return "Anno non valido";

    return null; // La data è perfetta
  }

  Future<void> _selezionaData(BuildContext context, TextEditingController controller, Function(String) onChanged) async {
    DateTime initialDate = DateTime.now();

    if (controller.text.length == 10) {
      try {
        List<String> parti = controller.text.split('/');
        initialDate = DateTime(int.parse(parti[2]), int.parse(parti[1]), int.parse(parti[0]));
      } catch (_) {}
    }

    final DateTime? picked = await showDatePicker(
      context: context,
      initialDate: initialDate,
      firstDate: DateTime(1990),
      lastDate: DateTime(2100),
      locale: const Locale('it', 'IT'),
    );

    if (picked != null) {
      String dataFormattata = "${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}";
      setState(() {
        controller.text = dataFormattata;
        onChanged(dataFormattata);
      });
    }
  }

  void _validaDataDal(String val) => setState(() => _erroreValidoDal = _calcolaErroreData(val));
  void _validaDataAl(String val) => setState(() => _erroreValidoAl = _calcolaErroreData(val));

  int _giorniInMese(int mese, int anno) {
    if (mese == 2) {
      bool bisestile = (anno % 4 == 0 && anno % 100 != 0) || (anno % 400 == 0);
      return bisestile ? 29 : 28;
    }
    if ([4, 6, 9, 11].contains(mese)) return 30;
    return 31;
  }
  // ---------------------------------


  void _salvaTutto() {
    bool nomeCompagniaMancante = (_selectedAssicurazione == null ||
        (_selectedAssicurazione == "ALTRO (Inserimento manuale)" && _compagniaManuale.text.trim().isEmpty));

    // MODIFICA: Rimossi i controlli sui campi Agenzia, Denominazione, Indirizzo, Stato e Telefono
    if (nomeCompagniaMancante || _polizza.text.trim().isEmpty || _validoDal.text.trim().isEmpty ||
        _validoAl.text.trim().isEmpty) {
      // MODIFICA: Testo aggiornato
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Compagnia, Polizza e Date sono obbligatorie"), backgroundColor: Colors.red));
      return;
    }
    if (_erroreValidoDal != null || _erroreValidoAl != null) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Correggi le date prima di proseguire!"), backgroundColor: Colors.red));
      return;
    }
    if ((_validoDal.text.length < 10) || (_validoAl.text.length < 10)) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Le date devono essere complete (GG/MM/AAAA)"), backgroundColor: Colors.orange));
      return;
    }

    String denomFinale = (_selectedAssicurazione == "ALTRO (Inserimento manuale)") ? _compagniaManuale.text.toUpperCase() : (_selectedAssicurazione ?? "");

    if (isB) {
      GlobalData.Denominazione_B = denomFinale;
      GlobalData.Numero_Polizza_B = _polizza.text.toUpperCase();
      GlobalData.N_carta_verde_B = _cartaVerde.text.toUpperCase();
      GlobalData.Data_Inizio_Dal_B = _validoDal.text;
      GlobalData.Data_Scadenza_Al_B = _validoAl.text;
      GlobalData.Agenzia_B = _agenzia.text.toUpperCase();
      GlobalData.Denominazione_agenzia_B = _denomAgenzia.text.toUpperCase();
      GlobalData.Indirizzo_agenzia_B = _indirizzoAgenzia.text.toUpperCase();
      GlobalData.Stato_agenzia_B = _statoAgenzia.text.toUpperCase();
      GlobalData.N_tel_mail_agenzia_B = _telAgenzia.text.toUpperCase();
      GlobalData.FLAG_danni_mat_assicurati_B = _danniMaterialiAssicurati;
    } else {
      GlobalData.Denominazione_A = denomFinale;
      GlobalData.Numero_Polizza_A = _polizza.text.toUpperCase();
      GlobalData.N_carta_verde_A = _cartaVerde.text.toUpperCase();
      GlobalData.Data_Inizio_Dal_A = _validoDal.text;
      GlobalData.Data_Scadenza_Al_A = _validoAl.text;
      GlobalData.Agenzia_A = _agenzia.text.toUpperCase();
      GlobalData.Denominazione_agenzia_A = _denomAgenzia.text.toUpperCase();
      GlobalData.Indirizzo_agenzia_A = _indirizzoAgenzia.text.toUpperCase();
      GlobalData.Stato_agenzia_A = _statoAgenzia.text.toUpperCase();
      GlobalData.N_tel_mail_agenzia_A = _telAgenzia.text.toUpperCase();
      GlobalData.FLAG_danni_mat_assicurati_A = _danniMaterialiAssicurati;
    }
    Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp9Screen()));
  }

  @override
  Widget build(BuildContext context) {
    Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgCol = isB ? const Color(0xFFFFF9C4) : const Color(0xFFE3F2FD);

    return GestureDetector(
      onTap: () => FocusScope.of(context).unfocus(),
      child: Scaffold(
        backgroundColor: bgCol,
        resizeToAvoidBottomInset: true,
        appBar: AppBar(
          title: Text('8. Assicurazione (${GlobalData.latoCorrente})'),
          backgroundColor: mainCol,
          foregroundColor: isB ? Colors.black : Colors.white,
        ),

        // --- LAYOUT SLIVER ---
        body: SafeArea(
          child: CustomScrollView(
            physics: const BouncingScrollPhysics(),
            slivers: [
              // 1. Contenuto Scrollabile
              SliverPadding(
                padding: const EdgeInsets.all(16),
                sliver: SliverList(
                  delegate: SliverChildListDelegate([
                    _buildCard(
                      titolo: "8. IMPRESA DI ASSICURAZIONE",
                      accentColor: mainCol,
                      child: Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.only(bottom: 10),
                            child: DropdownButtonFormField<String>(
                              value: _selectedAssicurazione,
                              isExpanded: true,
                              decoration: InputDecoration(
                                labelText: "Seleziona Compagnia *",
                                prefixIcon: Icon(Icons.business, color: isB ? Colors.orange.shade800 : Colors.blue.shade700),
                                border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
                                filled: true, fillColor: Colors.white,
                              ),
                              items: GlobalData.assicurazioni.keys.map((String key) {
                                return DropdownMenuItem<String>(value: key, child: Text(key, style: const TextStyle(fontSize: 13)));
                              }).toList(),
                              onChanged: (val) {
                                setState(() {
                                  _selectedAssicurazione = val;
                                  _isManuale = (val == "ALTRO (Inserimento manuale)");
                                  if (!_isManuale) _compagniaManuale.clear();
                                });
                              },
                            ),
                          ),
                          if (_isManuale)
                            _buildField(_compagniaManuale, "Inserisci Nome Compagnia *", Icons.edit_note, mainCol),
                          _buildField(_polizza, "N. di polizza *", Icons.description, mainCol),
                          _buildField(_cartaVerde, "N. di Carta Verde (Opz)", Icons.language, mainCol),
                          Row(children: [
                            Expanded(
                              child: _buildField(_validoDal, "Valida dal *", Icons.date_range, mainCol,
                                isDate: true,
                                errorText: _erroreValidoDal,
                                onChanged: _validaDataDal,
                                // USIAMO INKWELL PER STRINGERE I MARGINI
                                customPrefix: InkWell(
                                  onTap: () => _selezionaData(context, _validoDal, _validaDataDal),
                                  borderRadius: BorderRadius.circular(20),
                                  child: Container(
                                    width: 38,
                                    alignment: Alignment.center,
                                    child: Icon(Icons.calendar_today, size: 20, color: isB ? Colors.orange.shade800 : Colors.blue.shade700),
                                  ),
                                ),
                              ),
                            ),
                            const SizedBox(width: 10),
                            Expanded(
                              child: _buildField(_validoAl, "Fino al *", Icons.event_available, mainCol,
                                isDate: true,
                                errorText: _erroreValidoAl,
                                onChanged: _validaDataAl,
                                // USIAMO INKWELL PER STRINGERE I MARGINI
                                customPrefix: InkWell(
                                  onTap: () => _selezionaData(context, _validoAl, _validaDataAl),
                                  borderRadius: BorderRadius.circular(20),
                                  child: Container(
                                    width: 38,
                                    alignment: Alignment.center,
                                    child: Icon(Icons.calendar_today, size: 20, color: isB ? Colors.orange.shade800 : Colors.blue.shade700),
                                  ),
                                ),
                              ),
                            ),
                          ]),
                        ],
                      ),
                    ),
                    _buildCard(
                      titolo: "AGENZIA (OPZIONALE)", // Modificato titolo per chiarezza
                      accentColor: mainCol,
                      child: Column(
                        children: [
                          // MODIFICA: Rimossi asterischi dalle label
                          _buildField(_agenzia, "Ufficio/Agenzia", Icons.store, mainCol),
                          _buildField(_denomAgenzia, "Denominazione", Icons.info_outline, mainCol),
                          _buildField(_indirizzoAgenzia, "Indirizzo", Icons.place, mainCol),
                          Row(children: [
                            Expanded(child: _buildField(_statoAgenzia, "Stato", Icons.flag, mainCol)),
                            const SizedBox(width: 10),
                            Expanded(child: _buildField(_telAgenzia, "Tel. / E-mail", Icons.contact_phone, mainCol)),
                          ]),
                        ],
                      ),
                    ),

                    _buildCard(
                      titolo: "DANNI PROPRI",
                      accentColor: mainCol,
                      child: _buildSwitch(
                          "La polizza copre anche i danni materiali al proprio veicolo?",
                          _danniMaterialiAssicurati,
                              (val) => setState(() => _danniMaterialiAssicurati = val),
                          mainCol
                      ),
                    ),
                  ]),
                ),
              ),

              // 2. Piè di pagina elastico
              SliverFillRemaining(
                hasScrollBody: false,
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child: _navButtons(context, mainCol),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  // --- NUOVO WIDGET SWITCH PERSONALIZZATO (NO / SÌ) ---
  Widget _buildSwitch(String label, bool value, Function(bool) onChanged, Color activeColor) {
    return InkWell(
      onTap: () => onChanged(!value),
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 8.0),
        child: Row(
          children: [
            Expanded(
              child: Text(
                label,
                style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
              ),
            ),
            const SizedBox(width: 8),
            Text(
              "NO",
              style: TextStyle(
                fontWeight: !value ? FontWeight.bold : FontWeight.normal,
                color: !value ? Colors.red.shade700 : Colors.grey.shade400,
                fontSize: 14,
              ),
            ),
            Switch(
              value: value,
              onChanged: onChanged,
              activeColor: activeColor,
              activeTrackColor: activeColor.withOpacity(0.4),
              inactiveThumbColor: Colors.grey,
              inactiveTrackColor: Colors.grey.shade300,
            ),
            Text(
              "SÌ",
              style: TextStyle(
                fontWeight: value ? FontWeight.bold : FontWeight.normal,
                color: value ? activeColor : Colors.grey.shade400,
                fontSize: 14,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildField(TextEditingController controller, String label, IconData icon, Color iconColor, {bool isDate = false, String? errorText, Function(String)? onChanged, Widget? customPrefix}) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: TextField(
        controller: controller,
        keyboardType: isDate ? TextInputType.number : TextInputType.text,
        inputFormatters: isDate ? [FilteringTextInputFormatter.digitsOnly, DateInputFormatter()] : [],
        textCapitalization: TextCapitalization.characters,
        onChanged: onChanged,
        // Rimpiccioliamo leggermente il testo se è una data per farlo stare più comodo
        style: TextStyle(fontSize: isDate ? 14 : 16),
        decoration: InputDecoration(
          labelText: label,
          hintText: isDate ? "GG/MM/AAAA" : null,
          errorText: errorText,
          errorStyle: const TextStyle(fontSize: 10), // Rende il testo di errore più compatto
          prefixIcon: customPrefix ?? Icon(icon, size: 20, color: isB ? Colors.orange.shade800 : Colors.blue.shade700),
          // --- IL TRUCCO È QUI: Diciamo all'icona di occupare meno spazio ---
          prefixIconConstraints: const BoxConstraints(minWidth: 38, minHeight: 38),
          contentPadding: const EdgeInsets.only(left: 0, right: 8, top: 15, bottom: 15),
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
          filled: true, fillColor: Colors.white,
        ),
      ),
    );
  }

  Widget _buildCard({required String titolo, required Widget child, required Color accentColor}) {
    return Card(
      elevation: 2,
      margin: const EdgeInsets.only(bottom: 16),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          Text(titolo, style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold, color: accentColor)),
          const Divider(height: 20),
          child,
        ]),
      ),
    );
  }

  Widget _navButtons(BuildContext context, Color color) {
    return Row(
      children: [
        Expanded(child: OutlinedButton(onPressed: () => Navigator.pop(context), style: OutlinedButton.styleFrom(minimumSize: const Size(0, 55)), child: const Text("INDIETRO"))),
        const SizedBox(width: 15),
        Expanded(flex: 2, child: ElevatedButton(
          style: ElevatedButton.styleFrom(backgroundColor: color, foregroundColor: isB ? Colors.black : Colors.white, minimumSize: const Size(0, 55)),
          onPressed: _salvaTutto,
          child: const Text("SALVA E PROSEGUI"),
        )),
      ],
    );
  }

  @override
  void dispose() {
    _polizza.dispose(); _cartaVerde.dispose();
    _validoDal.dispose(); _validoAl.dispose(); _agenzia.dispose();
    _denomAgenzia.dispose(); _indirizzoAgenzia.dispose();
    _statoAgenzia.dispose(); _telAgenzia.dispose();
    _compagniaManuale.dispose();
    super.dispose();
  }
}
=== FILE: lib/ps.dart ===
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // Fondamentale per leggere il JSON
import 'package:geolocator/geolocator.dart';
import 'package:url_launcher/url_launcher.dart';

class ProntoSoccorsoScreen extends StatefulWidget {
  const ProntoSoccorsoScreen({super.key});

  @override
  State<ProntoSoccorsoScreen> createState() => _ProntoSoccorsoScreenState();
}

class _ProntoSoccorsoScreenState extends State<ProntoSoccorsoScreen> {
  List<dynamic> _ospedali = [];
  bool _isLoading = true;
  String _statusMessage = "Caricamento archivio ospedali...";
  Position? _posizioneUtente;

  @override
  void initState() {
    super.initState();
    _inizializzaDati();
  }

  Future<void> _inizializzaDati() async {
    try {
      // 1. CARICA IL FILE JSON LOCALE
      // Assicurati che il nome del file in assets sia esattamente questo
      final String jsonString = await rootBundle.loadString('assets/ospedali_completo.json');
      List<dynamic> datiGrezzi = json.decode(jsonString);

      setState(() => _statusMessage = "Ricerca posizione GPS...");

      // 2. CHIEDI PERMESSI E TROVA POSIZIONE
      Position? posizione = await _determinaPosizione();

      if (posizione != null) {
        _posizioneUtente = posizione;

        // 3. CALCOLA DISTANZA PER OGNI OSPEDALE
        for (var ospedale in datiGrezzi) {
          // Gestione sicura dei numeri (a volte arrivano come stringhe o int)
          double lat = (ospedale['lat'] is String) ? double.parse(ospedale['lat']) : ospedale['lat'].toDouble();
          double lng = (ospedale['lng'] is String) ? double.parse(ospedale['lng']) : ospedale['lng'].toDouble();

          double distanzaInMetri = Geolocator.distanceBetween(
            posizione.latitude,
            posizione.longitude,
            lat,
            lng,
          );
          ospedale['distanza'] = distanzaInMetri;
          ospedale['lat_num'] = lat; // Salviamo il double pulito per dopo
          ospedale['lng_num'] = lng;
        }

        // 4. ORDINA DAL PIÙ VICINO
        datiGrezzi.sort((a, b) => (a['distanza'] as double).compareTo(b['distanza'] as double));

        // (Opzionale) Prendi solo i primi 50 per non appesantire la lista, o tienili tutti
        // datiGrezzi = datiGrezzi.take(50).toList();
      }

      if (mounted) {
        setState(() {
          _ospedali = datiGrezzi;
          _isLoading = false;
        });
      }
    } catch (e) {
      debugPrint("Errore: $e");
      if (mounted) {
        setState(() {
          _statusMessage = "Errore: Impossibile caricare gli ospedali.\n$e";
          _isLoading = false;
        });
      }
    }
  }

  Future<Position?> _determinaPosizione() async {
    bool serviceEnabled;
    LocationPermission permission;

    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) return null;

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) return null;
    }
    if (permission == LocationPermission.deniedForever) return null;

    return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
  }

  Future<void> _apriMappa(double lat, double lng) async {
    // URL universale che funziona su Android e iOS aprendo l'app di mappe predefinita
    final Uri url = Uri.parse("http://maps.google.com/maps?q=$lat,$lng");
    if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
      throw Exception('Could not launch $url');
    }
  }

  Future<void> _chiama112() async {
    final Uri url = Uri.parse("tel:112");
    if (await canLaunchUrl(url)) await launchUrl(url);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Pronto Soccorso Vicini"),
        backgroundColor: Colors.green.shade800,
        foregroundColor: Colors.white,
      ),
      body: Column(
        children: [
          // HEADER EMERGENZA
          Container(
            padding: const EdgeInsets.all(16),
            color: Colors.red.shade50,
            child: Row(
              children: [
                Icon(Icons.warning_amber_rounded, color: Colors.red.shade800, size: 30),
                const SizedBox(width: 10),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text("EMERGENZA GRAVE?", style: TextStyle(color: Colors.red.shade900, fontWeight: FontWeight.bold)),
                      const Text("Non andare da solo, chiama il 112."),
                    ],
                  ),
                ),
                ElevatedButton(
                  onPressed: _chiama112,
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.red, foregroundColor: Colors.white),
                  child: const Text("CHIAMA 112"),
                )
              ],
            ),
          ),

          Expanded(
            child: _isLoading
                ? Center(child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircularProgressIndicator(color: Colors.green.shade800),
                const SizedBox(height: 20),
                Text(_statusMessage, textAlign: TextAlign.center),
              ],
            ))
                : _ospedali.isEmpty
                ? const Center(child: Text("Nessun ospedale trovato nel database."))
                : ListView.builder(
              padding: const EdgeInsets.all(10),
              itemCount: _ospedali.length,
              itemBuilder: (context, index) {
                final ospedale = _ospedali[index];
                final double km = (ospedale['distanza'] ?? 0) / 1000;
                final String livello = ospedale['livello'] ?? "";

                // Colore badge livello
                Color badgeColor = Colors.grey;
                if (livello.contains("DEA2")) badgeColor = Colors.red.shade700;
                else if (livello.contains("DEA1")) badgeColor = Colors.orange.shade700;
                else if (livello.contains("PS")) badgeColor = Colors.green.shade700;

                return Card(
                  elevation: 3,
                  margin: const EdgeInsets.only(bottom: 12),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  child: ListTile(
                    contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    leading: Container(
                      padding: const EdgeInsets.all(8),
                      decoration: BoxDecoration(
                          color: Colors.green.shade50,
                          borderRadius: BorderRadius.circular(8),
                          border: Border.all(color: Colors.green.shade100)
                      ),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Icon(Icons.place, color: Colors.green, size: 20),
                          Text("${km.toStringAsFixed(1)} km", style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 11)),
                        ],
                      ),
                    ),
                    title: Text(
                      ospedale['nome'],
                      style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),
                    subtitle: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const SizedBox(height: 4),
                        Text("${ospedale['indirizzo']}, ${ospedale['citta']}", style: TextStyle(color: Colors.grey.shade700, fontSize: 13)),
                        const SizedBox(height: 6),
                        if (livello != "nan" && livello.isNotEmpty)
                          Container(
                            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
                            decoration: BoxDecoration(
                                color: badgeColor.withOpacity(0.1),
                                borderRadius: BorderRadius.circular(4),
                                border: Border.all(color: badgeColor.withOpacity(0.3))
                            ),
                            child: Text(
                              "Livello: $livello",
                              style: TextStyle(color: badgeColor, fontSize: 11, fontWeight: FontWeight.bold),
                            ),
                          )
                      ],
                    ),
                    trailing: const Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey),
                    onTap: () {
                      if (ospedale['lat_num'] != null && ospedale['lng_num'] != null) {
                        _apriMappa(ospedale['lat_num'], ospedale['lng_num']);
                      }
                    },
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
=== FILE: lib/scambio_dati_screen.dart ===
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'global_data.dart';
import 'cid_data_manager.dart';
import 'security_service.dart';

class ScambioDatiScreen extends StatefulWidget {
  const ScambioDatiScreen({super.key});

  @override
  State<ScambioDatiScreen> createState() => _ScambioDatiScreenState();
}

class _ScambioDatiScreenState extends State<ScambioDatiScreen> with SingleTickerProviderStateMixin {
  late TabController _tabController;
  final MobileScannerController _cameraController = MobileScannerController();
  final TextEditingController _manualCodeController = TextEditingController();

  String? _codiceSessione;
  String? _chiaveSegreta;
  String? _shortCode; // IL PIN DI 6 LETTERE
  StreamSubscription? _streamSubscription;

  bool _isLoading = false;
  bool _scambioConcluso = false;

  @override
  void initState() {
    super.initState();

    // LOGICA DI APERTURA INTELLIGENTE:
    // Lato A -> Inizia con la Fotocamera (Indice 1)
    // Lato B -> Inizia mostrando il QR (Indice 0)
    int initialIndex = (GlobalData.latoCorrente == 'A') ? 1 : 0;

    _tabController = TabController(length: 2, vsync: this, initialIndex: initialIndex);

    // Avvio automatico Host (prepara il QR in background a prescindere dalla Tab aperta)
    _avviaHost();
  }

  @override
  void dispose() {
    // Cancello la sessione se esco senza concludere, a meno che non sia l'ID della firma
    if (!_scambioConcluso && _codiceSessione != null && _codiceSessione != GlobalData.idSessione) {
      FirebaseFirestore.instance.collection('scambi_cid').doc(_codiceSessione).delete();
    }

    _streamSubscription?.cancel();
    _tabController.dispose();
    _cameraController.dispose();
    _manualCodeController.dispose();
    super.dispose();
  }

  // --- GENERATORE DI PIN A 6 LETTERE MAIUSCOLE ---
  String _generaShortCode() {
    const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    Random rnd = Random();
    return String.fromCharCodes(Iterable.generate(6, (_) => chars.codeUnitAt(rnd.nextInt(chars.length))));
  }

  // --- 1. LOGICA HOST (CHI MOSTRA IL QR) ---
  Future<void> _avviaHost() async {
    if (_codiceSessione != null) return;

    if ((GlobalData.latoCorrente == 'A' && GlobalData.puntiFirmaA.isEmpty) ||
        (GlobalData.latoCorrente == 'B' && GlobalData.puntiFirmaB.isEmpty)) {
      return;
    }

    setState(() => _isLoading = true);

    try {
      String sessionId = GlobalData.idSessione ?? "CID_${DateTime.now().millisecondsSinceEpoch}";
      String shortCode = _generaShortCode();

      GlobalData.idSessione = sessionId;
      GlobalData.idScambioTemporaneo = sessionId;

      String chiave = GlobalData.chiaveSegretaCorrente ?? SecurityService.generaChiaveSessione();
      GlobalData.chiaveSegretaCorrente = chiave;

      Map<String, dynamic> mieiDati = CidDataManager.estraiDatiPerExport();
      String payloadCriptato = SecurityService.criptaDati(mieiDati, chiave);

      await FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).set({
        "timestamp_scambio": FieldValue.serverTimestamp(),
        "host_lato": GlobalData.latoCorrente,
        "secure_payload_host": payloadCriptato,
        "secure_payload_guest": null,
        "status": "waiting_guest",
        "short_code": shortCode,
        "chiave_temporanea": chiave
      }, SetOptions(merge: true));

      if (mounted) {
        setState(() {
          _codiceSessione = sessionId;
          _chiaveSegreta = chiave;
          _shortCode = shortCode;
          _isLoading = false;
        });
      }

      // Ascolto risposta dell'altro telefono
      _streamSubscription = FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).snapshots().listen((snapshot) {
        if (!snapshot.exists) {
          if (mounted) setState(() => _codiceSessione = null);
          return;
        }
        var data = snapshot.data();
        if (data != null && data['secure_payload_guest'] != null) {
          _streamSubscription?.cancel();
          _completaSync(data['secure_payload_guest'], chiave);
        }
      });

    } catch (e) {
      debugPrint("Err Host: $e");
      if (mounted) setState(() => _isLoading = false);
    }
  }

  void _completaSync(String encryptedData, String chiave) {
    try {
      Map<String, dynamic> dati = SecurityService.decriptaDati(encryptedData, chiave);
      CidDataManager.importaDati(dati);
      _scambioConcluso = true;
      _showSuccessAndExit();
    } catch (e) {
      if (mounted) ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Errore decriptazione")));
    }
  }

  // --- 2. LOGICA GUEST: VIA FOTOCAMERA ---
  void _onDetect(BarcodeCapture capture) {
    if (_isLoading || _scambioConcluso) return;

    final List<Barcode> barcodes = capture.barcodes;
    for (final barcode in barcodes) {
      if (barcode.rawValue != null) {
        _partecipaGuestScansione(barcode.rawValue!);
        break;
      }
    }
  }

  Future<void> _partecipaGuestScansione(String qrRawData) async {
    if (qrRawData.isEmpty) return;

    setState(() => _isLoading = true);

    try {
      if (!qrRawData.contains('|')) throw Exception("QR non valido");
      var parts = qrRawData.split('|');
      String sessionId = parts[0];
      String chiave = parts[1];

      await _eseguiPartecipazione(sessionId, chiave);
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Errore Scansione: $e")));
        await Future.delayed(const Duration(seconds: 2));
        setState(() => _isLoading = false);
      }
    }
  }

  // --- 3. LOGICA GUEST: INSERIMENTO MANUALE ---
  Future<void> _partecipaGuestManuale() async {
    String codiceInserito = _manualCodeController.text.trim().toUpperCase();

    if (codiceInserito.length < 5) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Inserisci un codice valido!"), backgroundColor: Colors.orange));
      return;
    }

    setState(() => _isLoading = true);

    try {
      // 1. Cerca la sessione tramite codice corto su Firebase
      final querySnapshot = await FirebaseFirestore.instance
          .collection('scambi_cid')
          .where('short_code', isEqualTo: codiceInserito)
          .limit(1)
          .get();

      if (querySnapshot.docs.isEmpty) {
        throw Exception("Codice non trovato o scaduto.");
      }

      final doc = querySnapshot.docs.first;
      String sessionId = doc.id;
      String chiave = doc['chiave_temporanea'] ?? "CHIAVE_DI_BACKUP";

      await _eseguiPartecipazione(sessionId, chiave, manualHostData: doc.data());

    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Errore: $e"), backgroundColor: Colors.red));
        setState(() => _isLoading = false);
      }
    }
  }

  // --- FUNZIONE CENTRALE PER GUEST (USATA DA FOTOCAMERA E MANUALE) ---
  Future<void> _eseguiPartecipazione(String sessionId, String chiave, {Map<String, dynamic>? manualHostData}) async {
    if (GlobalData.idSessione != null && GlobalData.idSessione != sessionId) {
      debugPrint("🗑️ Cancello vecchio file firma orfano: ${GlobalData.idSessione}");
      await FirebaseFirestore.instance.collection('scambi_cid').doc(GlobalData.idSessione).delete();
      GlobalData.idSessione = null;
    }

    Map<String, dynamic> data;

    if (manualHostData != null) {
      data = manualHostData;
    } else {
      DocumentSnapshot doc = await FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).get();
      if (!doc.exists) throw Exception("Sessione scaduta.");
      data = doc.data() as Map<String, dynamic>;
    }

    String? hostDataEnc = data['secure_payload_host'];
    if (hostDataEnc == null) throw Exception("Dati host mancanti.");

    Map<String, dynamic> datiHost = SecurityService.decriptaDati(hostDataEnc, chiave);
    CidDataManager.importaDati(datiHost);

    Map<String, dynamic> mieiDati = CidDataManager.estraiDatiPerExport();
    String myDataEnc = SecurityService.criptaDati(mieiDati, chiave);

    await FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).update({
      "secure_payload_guest": myDataEnc,
      "status": "completed"
    });

    GlobalData.idSessione = sessionId;
    GlobalData.idScambioTemporaneo = sessionId;
    GlobalData.chiaveSegretaCorrente = chiave;
    _scambioConcluso = true;

    _showSuccessAndExit();
  }

  void _showSuccessAndExit() {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("SCAMBIO EFFETTUATO!"), backgroundColor: Colors.green, duration: Duration(seconds: 1))
    );
    Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    String qrString = "";
    if (_codiceSessione != null && _chiaveSegreta != null) {
      qrString = "$_codiceSessione|$_chiaveSegreta";
    }

    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: const Text("Scambio Dati"),
        backgroundColor: Colors.blue.shade900,
        foregroundColor: Colors.white,
        bottom: TabBar(
            controller: _tabController,
            indicatorColor: Colors.white,
            labelColor: Colors.white,
            unselectedLabelColor: Colors.white70,
            tabs: const [
              Tab(icon: Icon(Icons.qr_code), text: "IL TUO QR"),
              Tab(icon: Icon(Icons.camera_alt), text: "SCANSIONA / CODICE")
            ]
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        // Impedisce di strusciare accidentalmente e chiudere lo scanner
        physics: const NeverScrollableScrollPhysics(),
        children: [
          // ================= TAB 1: HOST (MOSTRA QR E PIN) =================
          Center(
              child: SingleChildScrollView(
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        if (_codiceSessione == null) ...[
                          const CircularProgressIndicator(),
                          const SizedBox(height: 20),
                          const Text("Generazione in corso...")
                        ] else ...[
                          const Text("Fai scansionare questo QR:", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
                          const SizedBox(height: 20),
                          Container(
                              padding: const EdgeInsets.all(10),
                              decoration: BoxDecoration(color: Colors.white, border: Border.all(color: Colors.black12)),
                              child: QrImageView(data: qrString, size: 240)
                          ),
                          const SizedBox(height: 30),

                          const Text("Oppure fai inserire questo PIN:", style: TextStyle(color: Colors.black54)),
                          const SizedBox(height: 5),
                          Container(
                            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
                            decoration: BoxDecoration(
                                color: Colors.orange.shade50,
                                borderRadius: BorderRadius.circular(10),
                                border: Border.all(color: Colors.orange.shade800, width: 2)
                            ),
                            child: Text(
                                _shortCode ?? "---",
                                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 32, letterSpacing: 6, color: Colors.orange.shade900)
                            ),
                          ),

                          const SizedBox(height: 30),
                          const CircularProgressIndicator(),
                          const SizedBox(height: 10),
                          const Text("In attesa dell'altro utente...", style: TextStyle(color: Colors.grey))
                        ]
                      ]
                  )
              )
          ),

          // ================= TAB 2: GUEST (SCANNER SPLIT SCREEN) =================
          Stack(
            children: [
              Column(
                children: [
                  // METÀ SUPERIORE: FOTOCAMERA
                  Expanded(
                    flex: 5,
                    child: Stack(
                      children: [
                        MobileScanner(
                          controller: _cameraController,
                          onDetect: _onDetect,
                        ),
                        // Overlay mirino per far capire all'utente dove inquadrare
                        Center(
                          child: Container(
                            width: 200, height: 200,
                            decoration: BoxDecoration(
                                border: Border.all(color: Colors.greenAccent, width: 3),
                                borderRadius: BorderRadius.circular(20)
                            ),
                          ),
                        ),
                        Positioned(
                            bottom: 10,
                            left: 0,
                            right: 0,
                            child: Container(
                              color: Colors.black54,
                              padding: const EdgeInsets.symmetric(vertical: 8),
                              child: const Text(
                                "Inquadra il QR Code",
                                textAlign: TextAlign.center,
                                style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
                              ),
                            )
                        )
                      ],
                    ),
                  ),

                  // DIVISORIO
                  Container(height: 5, color: Colors.blue.shade900),

                  // METÀ INFERIORE: INSERIMENTO MANUALE
                  Expanded(
                    flex: 5,
                    child: Container(
                      color: Colors.grey.shade100,
                      width: double.infinity,
                      child: SingleChildScrollView(
                        padding: const EdgeInsets.all(20),
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            const Icon(Icons.keyboard, size: 40, color: Colors.blueGrey),
                            const SizedBox(height: 10),
                            const Text(
                              "La fotocamera non funziona?\nInserisci qui il PIN a 6 lettere dell'altro utente:",
                              textAlign: TextAlign.center,
                              style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.black87),
                            ),
                            const SizedBox(height: 20),
                            TextField(
                              controller: _manualCodeController,
                              textCapitalization: TextCapitalization.characters,
                              maxLength: 6,
                              textAlign: TextAlign.center,
                              style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24, letterSpacing: 8),
                              decoration: InputDecoration(
                                hintText: "PIN",
                                counterText: "",
                                border: OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
                                filled: true,
                                fillColor: Colors.white,
                                prefixIcon: const Icon(Icons.password, color: Colors.blueGrey),
                              ),
                            ),
                            const SizedBox(height: 20),
                            SizedBox(
                              width: double.infinity,
                              child: ElevatedButton.icon(
                                style: ElevatedButton.styleFrom(
                                  backgroundColor: Colors.orange.shade800,
                                  foregroundColor: Colors.white,
                                  padding: const EdgeInsets.symmetric(vertical: 16),
                                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
                                ),
                                onPressed: _partecipaGuestManuale,
                                icon: const Icon(Icons.download),
                                label: const Text("SCARICA DATI", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                  )
                ],
              ),

              // OVERLAY CARICAMENTO
              if (_isLoading) const ColoredBox(color: Colors.black54, child: Center(child: CircularProgressIndicator(color: Colors.white))),
            ],
          )
        ],
      ),
    );
  }
}
=== FILE: lib/pdf_inspector.dart ===
import 'dart:io';
import 'package:syncfusion_flutter_pdf/pdf.dart';

void main() {
  // 1. Leggi il file PDF (Assicurati del percorso corretto!)
  // Se sei nella root del progetto, il percorso dovrebbe essere:
  final File file = File('assets/CAI.pdf');

  if (!file.existsSync()) {
    print('ERRORE: File non trovato in ${file.path}');
    return;
  }

  final List<int> bytes = file.readAsBytesSync();
  final PdfDocument document = PdfDocument(inputBytes: bytes);
  final PdfForm form = document.form;

  print('\n--- LISTA CAMPI TROVATI NEL PDF ---');
  print('Totale campi: ${form.fields.count}\n');

  for (int i = 0; i < form.fields.count; i++) {
    final field = form.fields[i];
    String tipo = 'Sconosciuto';
    if (field is PdfTextBoxField) tipo = 'TEXT';
    if (field is PdfCheckBoxField) tipo = 'CHECKBOX';

    // Stampa in formato facile da copiare
    print('Key: "${field.name}" \t Tipo: $tipo');
  }
  print('-----------------------------------\n');
  document.dispose();
}
=== FILE: lib/carro_attr.dart ===
import 'dart:convert';
import 'dart:async'; // Necessario per il Timeout
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';

class CarroAttrezziScreen extends StatefulWidget {
  const CarroAttrezziScreen({super.key});

  @override
  State<CarroAttrezziScreen> createState() => _CarroAttrezziScreenState();
}

class _CarroAttrezziScreenState extends State<CarroAttrezziScreen> {
  List<dynamic> _officine = [];
  bool _isLoading = true;
  String _statusMessage = "Attivazione GPS...";

  @override
  void initState() {
    super.initState();
    _avviaRicercaSicura();
  }

  Future<void> _avviaRicercaSicura() async {
    // Piccolo ritardo iniziale per dare tempo alla UI di disegnarsi
    await Future.delayed(const Duration(milliseconds: 500));
    if (!mounted) return;
    _cercaSoccorsiVicini();
  }

  Future<void> _cercaSoccorsiVicini() async {
    try {
      // 1. GESTIONE PERMESSI ROBUSTA
      bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
      if (!serviceEnabled) {
        if (!mounted) return;
        setState(() {
          _statusMessage = "Attiva il GPS per trovare i soccorsi.";
          _isLoading = false;
        });
        return;
      }

      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          if (!mounted) return;
          setState(() {
            _statusMessage = "Permesso GPS negato.";
            _isLoading = false;
          });
          return;
        }
      }

      if (permission == LocationPermission.deniedForever) {
        if (!mounted) return;
        setState(() {
          _statusMessage = "Permessi GPS bloccati permanentemente.";
          _isLoading = false;
        });
        return;
      }

      // 2. CICLO WHILE PER OTTENERE LA POSIZIONE (WAIT FOR GPS)
      if (mounted) setState(() => _statusMessage = "Ricerca posizione in corso...");

      Position? position;
      int tentativi = 0;
      const int maxTentativi = 3; // Prova 3 volte prima di arrendersi

      // FINCHÉ non ho la posizione E non ho superato i tentativi...
      while (position == null && tentativi < maxTentativi) {
        try {
          if (tentativi > 0) {
            if (mounted) setState(() => _statusMessage = "Aggancio satelliti (Tentativo ${tentativi + 1}/$maxTentativi)...");
          }

          // Prova a prendere la posizione con un timeout di 6 secondi per tentativo
          position = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.high,
            timeLimit: const Duration(seconds: 6),
          );
        } catch (e) {
          // Se fallisce, aspetta 1 secondo e riprova
          tentativi++;
          await Future.delayed(const Duration(seconds: 1));
        }
      }

      // Se dopo il ciclo while è ancora null, proviamo l'ultima posizione nota
      if (position == null) {
        if (mounted) setState(() => _statusMessage = "Segnale debole, uso ultima posizione...");
        position = await Geolocator.getLastKnownPosition();
      }

      // Se è ancora null, alziamo bandiera bianca
      if (position == null) {
        throw "Impossibile ottenere la posizione GPS dopo vari tentativi.";
      }

      // 3. RICERCA SU OVERPASS API (OSM)
      if (mounted) setState(() => _statusMessage = "Ricerca soccorsi nei paraggi...");

      String query = """
        [out:json][timeout:25];
        (
          node["craft"="car_repair"](around:15000,${position.latitude},${position.longitude});
          node["shop"="car_repair"](around:15000,${position.latitude},${position.longitude});
          node["service"="vehicle_recovery"](around:15000,${position.latitude},${position.longitude});
        );
        out body;
      """;

      final url = Uri.parse('https://overpass-api.de/api/interpreter?data=${Uri.encodeComponent(query)}');

      final response = await http.get(
        url,
        headers: {'User-Agent': 'CidApp_Flutter/1.0'},
      ).timeout(const Duration(seconds: 20));

      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        List<dynamic> elements = data['elements'];
        List<Map<String, dynamic>> listaElaborata = [];

        for (var element in elements) {
          if (element['tags'] != null && element['tags']['name'] != null) {

            double distanzaMetri = Geolocator.distanceBetween(
                position!.latitude, position.longitude, element['lat'], element['lon']
            );

            listaElaborata.add({
              'name': element['tags']['name'],
              'phone': element['tags']['phone'] ?? element['tags']['contact:phone'] ?? element['tags']['mobile'],
              'street': element['tags']['addr:street'] ?? "",
              'city': element['tags']['addr:city'] ?? "",
              'distance': distanzaMetri,
              'lat': element['lat'],
              'lon': element['lon'],
            });
          }
        }

        listaElaborata.sort((a, b) => (a['distance'] as double).compareTo(b['distance'] as double));

        if (mounted) {
          setState(() {
            _officine = listaElaborata;
            _isLoading = false;
          });
        }
      } else {
        throw "Errore server OSM: ${response.statusCode}";
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _statusMessage = "Nessun soccorso trovato o errore GPS.\nRiprova tra poco.";
          _isLoading = false;
        });
      }
    }
  }

  Future<void> _chiamaNumero(String? numero) async {
    if (numero == null) return;
    // Pulisce il numero da spazi o caratteri strani
    final pulito = numero.replaceAll(RegExp(r'[^0-9+]'), '');
    final Uri url = Uri.parse("tel:$pulito");
    if (await canLaunchUrl(url)) await launchUrl(url);
  }

  Future<void> _apriMappa(double lat, double lon) async {
    // Link universale per aprire la navigazione
    final Uri url = Uri.parse("https://www.google.com/maps/search/?api=1&query=$lat,$lon");

    try {
      if (await canLaunchUrl(url)) {
        await launchUrl(url, mode: LaunchMode.externalApplication);
      } else {
        throw 'Impossibile aprire la mappa';
      }
    } catch (e) {
      debugPrint("Errore apertura mappa: $e");
    }
  }

  Future<void> _cercaSuGoogle(String nome) async {
    final Uri url = Uri.parse("https://www.google.com/search?q=soccorso stradale $nome telefono");
    if (await canLaunchUrl(url)) await launchUrl(url, mode: LaunchMode.externalApplication);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Soccorso Stradale"),
        backgroundColor: Colors.red.shade800,
        foregroundColor: Colors.white,
      ),
      body: _isLoading
          ? Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const CircularProgressIndicator(color: Colors.red),
            const SizedBox(height: 20),
            Text(_statusMessage, style: const TextStyle(color: Colors.grey)),
          ],
        ),
      )
          : _officine.isEmpty
          ? Center(
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(Icons.car_crash, size: 60, color: Colors.grey),
              const SizedBox(height: 10),
              const Text("Nessun soccorso trovato nei paraggi (15km).", textAlign: TextAlign.center),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () => _cercaSuGoogle("vicino a me"),
                child: const Text("Cerca su Google"),
              )
            ],
          ),
        ),
      )
          : ListView.builder(
        padding: const EdgeInsets.all(10),
        itemCount: _officine.length,
        itemBuilder: (context, index) {
          final officina = _officine[index];
          double km = (officina['distance'] as double) / 1000;

          String indirizzo = officina['street'];
          if (officina['city'] != "") indirizzo += (indirizzo.isNotEmpty ? ", " : "") + officina['city'];
          if (indirizzo.isEmpty) indirizzo = "Posizione GPS";

          return Card(
            elevation: 3,
            margin: const EdgeInsets.only(bottom: 12),
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: ListTile(
                // KM a sinistra
                leading: Container(
                  width: 55,
                  height: 55,
                  decoration: BoxDecoration(
                      color: Colors.red.shade50,
                      borderRadius: BorderRadius.circular(8),
                      border: Border.all(color: Colors.red.shade100)
                  ),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(Icons.location_on, color: Colors.red.shade700, size: 24),
                      Text("${km.toStringAsFixed(1)} km", style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold), maxLines: 1),
                    ],
                  ),
                ),
                title: Text(officina['name'], style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
                subtitle: Text(indirizzo, style: const TextStyle(fontSize: 13), maxLines: 2, overflow: TextOverflow.ellipsis),

                // DUE TASTI A DESTRA: MAPPA e CHIAMA
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    // Tasto MAPPA
                    IconButton(
                      icon: const Icon(Icons.directions, color: Colors.blue, size: 32),
                      onPressed: () => _apriMappa(officina['lat'], officina['lon']),
                      tooltip: "Naviga",
                    ),
                    // Tasto CHIAMA
                    officina['phone'] != null
                        ? IconButton(
                      icon: const Icon(Icons.phone_in_talk, color: Colors.green, size: 32),
                      onPressed: () => _chiamaNumero(officina['phone']),
                    )
                        : IconButton(
                      icon: const Icon(Icons.search, color: Colors.orange, size: 32),
                      onPressed: () => _cercaSuGoogle(officina['name']),
                      tooltip: "Cerca Web",
                    ),
                  ],
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}
=== FILE: lib/comp_9.dart ===
// Versione: 2.3.5 - Popup Automatico + Calendari Cliccabili
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'global_data.dart';
import 'comp_10.dart';

class DateInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var text = newValue.text.replaceAll('/', '');
    if (text.length > 8) text = text.substring(0, 8);
    var result = "";
    for (int i = 0; i < text.length; i++) {
      if (i == 2 || i == 4) result += "/";
      result += text[i];
    }
    return newValue.copyWith(
        text: result,
        selection: TextSelection.collapsed(offset: result.length)
    );
  }
}

class Comp9Screen extends StatefulWidget {
  const Comp9Screen({super.key});
  @override
  _Comp9ScreenState createState() => _Comp9ScreenState();
}

class _Comp9ScreenState extends State<Comp9Screen> {
  late TextEditingController _cognome, _nome, _cf, _nascita, _indirizzo, _stato, _tel, _patente, _categoriaAltro, _scadenza;

  String _selectedCat = "B";

  String? _erroreNascita;
  String? _erroreScadenza;

  bool get isB => GlobalData.latoCorrente == 'B';

  @override
  void initState() {
    super.initState();
    _initControllers();

    // Appena la pagina è costruita, lancia il controllo per i popup
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // PRIMA mostra le info della pagina...
      _mostraInfoPopup(context);

      // ...POI controlla se ci sono date pre-compilate da validare
      if (_nascita.text.isNotEmpty) _validaNascita(_nascita.text);
      if (_scadenza.text.isNotEmpty) _validaScadenza(_scadenza.text);
    });
  }

  void _initControllers() {
    if (isB) {
      _cognome = TextEditingController(text: GlobalData.Cognome_cond_B);
      _nome = TextEditingController(text: GlobalData.Nome_cond_B);
      _cf = TextEditingController(text: GlobalData.Cod_fiscale_cond_B);
      _nascita = TextEditingController(text: GlobalData.Data_nascita_cond_B);
      _indirizzo = TextEditingController(text: GlobalData.Indirizzo_cond_B);
      _stato = TextEditingController(text: GlobalData.Stato_cond_B.isEmpty ? "ITALIA" : GlobalData.Stato_cond_B);
      _tel = TextEditingController(text: GlobalData.N_tel_mail_cond_B);
      _patente = TextEditingController(text: GlobalData.N_Patente_cond_B);
      _scadenza = TextEditingController(text: GlobalData.Scadenza_cond_B);
      _setupCategoria(GlobalData.Categoria_cond_B);
    } else {
      _cognome = TextEditingController(text: GlobalData.Cognome_cond_A);
      _nome = TextEditingController(text: GlobalData.Nome_cond_A);
      _cf = TextEditingController(text: GlobalData.Cod_fiscale_cond_A);
      _nascita = TextEditingController(text: GlobalData.Data_nascita_cond_A);
      _indirizzo = TextEditingController(text: GlobalData.Indirizzo_cond_A);
      _stato = TextEditingController(text: GlobalData.Stato_cond_A.isEmpty ? "ITALIA" : GlobalData.Stato_cond_A);
      _tel = TextEditingController(text: GlobalData.N_tel_mail_cond_A);
      _patente = TextEditingController(text: GlobalData.N_Patente_cond_A);
      _scadenza = TextEditingController(text: GlobalData.Scadenza_cond_A);
      _setupCategoria(GlobalData.Categoria_cond_A);
    }
  }

  // --- POPUP INFORMATIVO ANIMATO ---
  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.person_pin, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Dati Conducente", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("In questa sezione inseriremo i dati della persona che era alla guida del Veicolo ${GlobalData.latoCorrente}.", style: const TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.file_download, "Importazione", "Se il conducente è la stessa persona del contraente (l'assicurato), potrai importare i suoi dati in un tocco."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.badge, "Patente", "Assicurati di inserire correttamente il numero, la categoria e la data di scadenza della patente di guida."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: isB ? Colors.black87 : Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () {
                  Navigator.pop(context); // Chiude l'info popup
                  // Dopo aver chiuso questo, controlla se deve mostrare l'altro popup per l'importazione
                  _mostraDialogoImportazione();
                },
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(parent: animation, curve: Curves.easeOutBack, reverseCurve: Curves.easeInBack);
        var curveOpacita = CurvedAnimation(parent: animation, curve: Curves.easeOut, reverseCurve: Curves.easeIn);
        return SlideTransition(position: Tween<Offset>(begin: const Offset(0.0, 0.4), end: Offset.zero).animate(curvePosizione), child: FadeTransition(opacity: curveOpacita, child: child));
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  // LOGICA POPUP AUTOMATICO
  void _mostraDialogoImportazione() {
    // 1. Se i campi sono già compilati (es. torno indietro per modificare), NON mostrare nulla
    if (_cognome.text.trim().isNotEmpty && _nome.text.trim().isNotEmpty) return;

    // 2. Controllo se esistono i dati del contraente da importare
    String contraenteNome = isB ? GlobalData.Nome_contraente_B : GlobalData.Nome_contraente_A;
    String contraenteCognome = isB ? GlobalData.Cognome_contraente_B : GlobalData.Cognome_contraente_A;

    if (contraenteNome.isEmpty && contraenteCognome.isEmpty) return;

    // 3. Mostra il Popup
    showDialog(
      context: context,
      barrierDismissible: false, // L'utente deve fare una scelta
      builder: (ctx) => AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
        title: Row(
          children: [
            Icon(Icons.person_add_alt_1, color: isB ? Colors.amber[800] : Colors.blue[800]),
            const SizedBox(width: 10),
            const Text("Conducente"),
          ],
        ),
        content: Text(
          "Il conducente è la stessa persona del contraente ($contraenteNome $contraenteCognome)?\n\nVuoi usare i suoi dati?",
          style: const TextStyle(fontSize: 16),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx),
            child: Text("NO, scrivo a mano", style: TextStyle(color: Colors.grey[600])),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              backgroundColor: isB ? Colors.amber[700] : Colors.blue.shade900,
              foregroundColor: Colors.white,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
            ),
            onPressed: () {
              _importaDati();
              Navigator.pop(ctx);
            },
            child: const Text("SÌ, importa"),
          ),
        ],
      ),
    );
  }

  void _importaDati() {
    setState(() {
      if (isB) {
        _cognome.text = GlobalData.Cognome_contraente_B;
        _nome.text = GlobalData.Nome_contraente_B;
        _cf.text = GlobalData.Codice_Fiscale_contraente_B;

        String addr = GlobalData.Indirizzo_contraente_B;
        if (GlobalData.CAP_contraente_B.isNotEmpty) addr += " ${GlobalData.CAP_contraente_B}";
        _indirizzo.text = addr.trim();

        _stato.text = GlobalData.Stato_contraente_B.isNotEmpty ? GlobalData.Stato_contraente_B : "ITALIA";
        _tel.text = GlobalData.N_telefono_mail_contraente_B;
      } else {
        _cognome.text = GlobalData.Cognome_contraente_A;
        _nome.text = GlobalData.Nome_contraente_A;
        _cf.text = GlobalData.Codice_Fiscale_contraente_A;

        String addr = GlobalData.Indirizzo_contraente_A;
        if (GlobalData.CAP_contraente_A.isNotEmpty) addr += " ${GlobalData.CAP_contraente_A}";
        _indirizzo.text = addr.trim();

        _stato.text = GlobalData.Stato_contraente_A.isNotEmpty ? GlobalData.Stato_contraente_A : "ITALIA";
        _tel.text = GlobalData.N_telefono_mail_contraente_A;
      }
    });
  }

  void _setupCategoria(String catEsistente) {
    if (["A", "B", "C", "D", "E"].contains(catEsistente)) {
      _selectedCat = catEsistente;
      _categoriaAltro = TextEditingController();
    } else if (catEsistente.isNotEmpty) {
      _selectedCat = "Altro";
      _categoriaAltro = TextEditingController(text: catEsistente);
    } else {
      _selectedCat = "B";
      _categoriaAltro = TextEditingController();
    }
  }

  // --- LOGICA CALENDARIO ---
  Future<void> _selezionaData(BuildContext context, TextEditingController controller, Function(String) onChanged) async {
    DateTime initialDate = DateTime.now();

    if (controller.text.length == 10) {
      try {
        List<String> parti = controller.text.split('/');
        initialDate = DateTime(int.parse(parti[2]), int.parse(parti[1]), int.parse(parti[0]));
      } catch (_) {}
    }

    final DateTime? picked = await showDatePicker(
      context: context,
      initialDate: initialDate,
      firstDate: DateTime(1900), // Anno minimo sensato per la nascita
      lastDate: DateTime(2100),
      locale: const Locale('it', 'IT'),
    );

    if (picked != null) {
      String dataFormattata = "${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}";
      setState(() {
        controller.text = dataFormattata;
        onChanged(dataFormattata);
      });
    }
  }

  String? _calcolaErroreData(String data) {
    if (data.isEmpty) return null;
    if (data.length < 10) return "Formato: GG/MM/AAAA";

    List<String> parti = data.split('/');
    if (parti.length != 3) return "Formato errato";

    int? giorno = int.tryParse(parti[0]);
    int? mese = int.tryParse(parti[1]);
    int? anno = int.tryParse(parti[2]);

    if (giorno == null || mese == null || anno == null) return "Data non valida";
    if (giorno < 1 || giorno > 31) return "Giorno errato";
    if (mese < 1 || mese > 12) return "Mese errato";

    int giorniMax = _giorniInMese(mese, anno);
    if (giorno > giorniMax) {
      String nomeMese = _getNomeMese(mese);
      return "$nomeMese $anno ha solo $giorniMax gg";
    }
    return null;
  }

  int _giorniInMese(int mese, int anno) {
    if (mese == 2) {
      bool bisestile = (anno % 4 == 0 && anno % 100 != 0) || (anno % 400 == 0);
      return bisestile ? 29 : 28;
    }
    if ([4, 6, 9, 11].contains(mese)) return 30;
    return 31;
  }

  String _getNomeMese(int mese) {
    const mesi = ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"];
    if (mese >= 1 && mese <= 12) return mesi[mese - 1];
    return "Mese";
  }

  void _validaNascita(String val) => setState(() => _erroreNascita = _calcolaErroreData(val));
  void _validaScadenza(String val) => setState(() => _erroreScadenza = _calcolaErroreData(val));

  void _salvaEProsegui() {
    String catFinale = (_selectedCat == "Altro") ? _categoriaAltro.text.toUpperCase() : _selectedCat;
    bool categoriaMancante = (_selectedCat == "Altro" && _categoriaAltro.text.trim().isEmpty);

    if (_cognome.text.trim().isEmpty || _nome.text.trim().isEmpty || _cf.text.trim().isEmpty ||
        _nascita.text.trim().isEmpty || _indirizzo.text.trim().isEmpty || _stato.text.trim().isEmpty ||
        _patente.text.trim().isEmpty || _scadenza.text.trim().isEmpty || categoriaMancante) {
      _mostraErrore("Tutti i dati del conducente sono obbligatori!", Colors.red);
      return;
    }

    if (_erroreNascita != null || _erroreScadenza != null) {
      _mostraErrore("Correggi le date in rosso!", Colors.red);
      return;
    }

    if (_nascita.text.length < 10 || _scadenza.text.length < 10) {
      _mostraErrore("Formato data incompleto (GG/MM/AAAA)", Colors.orange);
      return;
    }

    if (isB) {
      GlobalData.Cognome_cond_B = _cognome.text.toUpperCase();
      GlobalData.Nome_cond_B = _nome.text.toUpperCase();
      GlobalData.Cod_fiscale_cond_B = _cf.text.toUpperCase();
      GlobalData.Data_nascita_cond_B = _nascita.text;
      GlobalData.Indirizzo_cond_B = _indirizzo.text.toUpperCase();
      GlobalData.Stato_cond_B = _stato.text.toUpperCase();
      GlobalData.N_tel_mail_cond_B = _tel.text.toUpperCase();
      GlobalData.N_Patente_cond_B = _patente.text.toUpperCase();
      GlobalData.Categoria_cond_B = catFinale;
      GlobalData.Scadenza_cond_B = _scadenza.text;
    } else {
      GlobalData.Cognome_cond_A = _cognome.text.toUpperCase();
      GlobalData.Nome_cond_A = _nome.text.toUpperCase();
      GlobalData.Cod_fiscale_cond_A = _cf.text.toUpperCase();
      GlobalData.Data_nascita_cond_A = _nascita.text;
      GlobalData.Indirizzo_cond_A = _indirizzo.text.toUpperCase();
      GlobalData.Stato_cond_A = _stato.text.toUpperCase();
      GlobalData.N_tel_mail_cond_A = _tel.text.toUpperCase();
      GlobalData.N_Patente_cond_A = _patente.text.toUpperCase();
      GlobalData.Categoria_cond_A = catFinale;
      GlobalData.Scadenza_cond_A = _scadenza.text;
    }

    Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp10Screen()));
  }

  void _mostraErrore(String msg, Color colore) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(msg), backgroundColor: colore, duration: const Duration(seconds: 3)),
    );
  }

  @override
  Widget build(BuildContext context) {
    Color accentColor = isB ? Colors.amber.shade700 : Colors.blue.shade900;
    Color bgColor = isB ? const Color(0xFFFFF9C4) : const Color(0xFFE3F2FD);

    return GestureDetector(
      onTap: () => FocusScope.of(context).unfocus(),
      child: Scaffold(
        backgroundColor: bgColor,
        resizeToAvoidBottomInset: true,
        appBar: AppBar(
          title: Text("9. Conducente (${GlobalData.latoCorrente})"),
          backgroundColor: accentColor,
          foregroundColor: isB ? Colors.black : Colors.white,
        ),
        body: SafeArea(
          child: SingleChildScrollView(
            physics: const BouncingScrollPhysics(),
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                _buildSectionCard(
                  titolo: "DATI PERSONALI",
                  accentColor: accentColor,
                  children: [
                    _buildTextField(_cognome, "Cognome *", Icons.person, accentColor),
                    _buildTextField(_nome, "Nome *", Icons.person_outline, accentColor),

                    // --- MODIFICATO: DATA DI NASCITA ---
                    _buildTextField(_nascita, "Data di Nascita *", Icons.cake, accentColor,
                      isDate: true, hint: "GG/MM/AAAA", errorText: _erroreNascita, onChanged: _validaNascita,
                      customPrefix: InkWell(
                        onTap: () => _selezionaData(context, _nascita, _validaNascita),
                        borderRadius: BorderRadius.circular(20),
                        child: Container(
                          width: 38,
                          alignment: Alignment.center,
                          child: Icon(Icons.cake, size: 20, color: accentColor),
                        ),
                      ),
                    ),

                    _buildTextField(_cf, "Codice Fiscale *", Icons.badge, accentColor, isUpper: true),
                    _buildTextField(_indirizzo, "Indirizzo (Via, Cap, Città) *", Icons.home, accentColor),
                    _buildTextField(_stato, "Stato *", Icons.flag, accentColor),
                    _buildTextField(_tel, "Tel/Email *", Icons.contact_mail, accentColor),
                  ],
                ),
                _buildSectionCard(
                  titolo: "PATENTE DI GUIDA",
                  accentColor: accentColor,
                  children: [
                    _buildTextField(_patente, "N. Patente *", Icons.credit_card, accentColor, isUpper: true),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 12),
                      child: DropdownButtonFormField<String>(
                        value: _selectedCat,
                        decoration: InputDecoration(
                          labelText: "Categoria *",
                          prefixIcon: Icon(Icons.category, color: accentColor),
                          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
                          filled: true, fillColor: Colors.white,
                        ),
                        items: ["A", "B", "C", "D", "E", "Altro"].map((c) => DropdownMenuItem(value: c, child: Text(c))).toList(),
                        onChanged: (v) => setState(() => _selectedCat = v!),
                      ),
                    ),
                    if (_selectedCat == "Altro")
                      _buildTextField(_categoriaAltro, "Specifica Categoria *", Icons.edit, accentColor, isUpper: true),

                    // --- MODIFICATO: SCADENZA PATENTE ---
                    _buildTextField(_scadenza, "Valida fino al *", Icons.event_available, accentColor,
                      isDate: true, hint: "GG/MM/AAAA", errorText: _erroreScadenza, onChanged: _validaScadenza,
                      customPrefix: InkWell(
                        onTap: () => _selezionaData(context, _scadenza, _validaScadenza),
                        borderRadius: BorderRadius.circular(20),
                        child: Container(
                          width: 38,
                          alignment: Alignment.center,
                          child: Icon(Icons.event_available, size: 20, color: accentColor),
                        ),
                      ),
                    ),
                  ],
                ),

                _navButtons(accentColor),
                const SizedBox(height: 10),
              ],
            ),
          ),
        ),
      ),
    );
  }

  // --- MODIFICATO IL METODO PER ACCETTARE customPrefix E RESTRINGERE LA UI ---
  Widget _buildTextField(TextEditingController c, String label, IconData icon, Color color,
      {bool isDate = false, bool isUpper = false, bool isNumeric = false, String? hint, String? errorText, Function(String)? onChanged, Widget? customPrefix}) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: TextField(
        controller: c,
        keyboardType: isDate || isNumeric ? TextInputType.number : TextInputType.text,
        textCapitalization: isUpper ? TextCapitalization.characters : TextCapitalization.sentences,
        onChanged: onChanged,
        style: TextStyle(fontSize: isDate ? 14 : 16), // Rimpicciolisce un po' le date
        inputFormatters: [
          if (isDate) DateInputFormatter(),
          if (isDate) LengthLimitingTextInputFormatter(10),
          if (isNumeric) FilteringTextInputFormatter.digitsOnly,
          if (isNumeric) LengthLimitingTextInputFormatter(5),
        ],
        decoration: InputDecoration(
          labelText: label,
          hintText: hint,
          errorText: errorText,
          errorStyle: const TextStyle(fontSize: 10),
          prefixIcon: customPrefix ?? Icon(icon, color: color),
          prefixIconConstraints: isDate ? const BoxConstraints(minWidth: 38, minHeight: 38) : null,
          contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 15),
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
          filled: true, fillColor: Colors.white,
        ),
      ),
    );
  }

  Widget _buildSectionCard({required String titolo, required List<Widget> children, required Color accentColor}) => Container(
    width: double.infinity, margin: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.all(16),
    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)]),
    child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
      Text(titolo, style: TextStyle(fontWeight: FontWeight.bold, color: accentColor, fontSize: 17)),
      const Divider(height: 25), ...children,
    ]),
  );

  Widget _navButtons(Color btnColor) => Row(children: [
    Expanded(flex: 4, child: OutlinedButton(onPressed: () => Navigator.pop(context), style: OutlinedButton.styleFrom(minimumSize: const Size(0, 55), side: BorderSide(color: btnColor, width: 1.5), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))), child: const FittedBox(child: Text("INDIETRO", style: TextStyle(fontWeight: FontWeight.bold))))),
    const SizedBox(width: 15),
    Expanded(flex: 7, child: ElevatedButton(style: ElevatedButton.styleFrom(backgroundColor: btnColor, foregroundColor: isB ? Colors.black : Colors.white, minimumSize: const Size(0, 55), elevation: 5, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))), onPressed: _salvaEProsegui, child: const FittedBox(child: Text("SALVA E PROSEGUI", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))))),
  ]);

  @override
  void dispose() {
    _cognome.dispose(); _nome.dispose(); _cf.dispose(); _nascita.dispose();
    _indirizzo.dispose(); _stato.dispose(); _tel.dispose();
    _patente.dispose(); _categoriaAltro.dispose(); _scadenza.dispose();
    super.dispose();
  }
}
=== FILE: lib/scelta_lato.dart ===
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; // <-- AGGIUNTA LIBRERIA PER IL DEBUG
import 'global_data.dart';
import 'comp_1-5.dart';
import 'comp_6-7.dart';

class SceltaLatoScreen extends StatefulWidget {
  const SceltaLatoScreen({super.key});

  @override
  State<SceltaLatoScreen> createState() => _SceltaLatoScreenState();
}

class _SceltaLatoScreenState extends State<SceltaLatoScreen> {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _mostraGuidaSicurezza(context);
    });
  }

  void _mostraGuidaSicurezza(BuildContext context) {
    showDialog(
      context: context,
      builder: (ctx) => AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
        title: Row(
          children: [
            Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(color: Colors.red.shade50, borderRadius: BorderRadius.circular(10)),
              child: const Icon(Icons.health_and_safety, color: Colors.red),
            ),
            const SizedBox(width: 10),
            const Text("GUIDA RAPIDA", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
          ],
        ),
        content: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: const [
              _StepGuida(icon: Icons.back_hand, text: "FERMATI in sicurezza e non intralciare il traffico."),
              Divider(),
              _StepGuida(icon: Icons.engineering, text: "Se sei fuori dal centro abitato indossa il GILET arancione e posiziona il TRIANGOLO."),
              Divider(),
              _StepGuida(icon: Icons.local_hospital, text: "Ci sono feriti? NON muoverli e chiama il 118."),
              Divider(),
              _StepGuida(icon: Icons.file_copy, text: "Prepara la patente e i dati della polizza, ti serviranno per compilare il modulo."),
              Divider(),
              _StepGuida(
                  icon: Icons.camera_alt,
                  text: "FAI LE FOTO ORA! 📸\n1. Targhe veicoli.\n2. Danni da vicino e lontano.\n3. Posizione auto sulla strada.\n\nLe allegherai alla fine nella mail!",
                  isBold: true
              ),
            ],
          ),
        ),
        actions: [
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.blue.shade800,
                  foregroundColor: Colors.white,
                  padding: const EdgeInsets.symmetric(vertical: 12),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))
              ),
              onPressed: () => Navigator.pop(ctx),
              child: const Text("HO CAPITO, INIZIAMO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
            ),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Compilazione CAI", style: TextStyle(fontWeight: FontWeight.bold)),
        backgroundColor: Colors.blue.shade900,
        foregroundColor: Colors.white,
        elevation: 0,
        actions: [

          if (kDebugMode) // <-- AGGIUNTO: NASCONDE IL TASTO NEGLI STORE
            IconButton(
              icon: const Icon(Icons.flash_on, color: Colors.orangeAccent),
              tooltip: "POPOLA DATI TEST",
              onPressed: () {
                GlobalData.popolaDatiDiTest();
                ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text("⚡ Dati di test caricati! Vai a generare il PDF."),
                      backgroundColor: Colors.green,
                      duration: Duration(seconds: 2),
                    )
                );
              },
            ),

          IconButton(
            icon: const Icon(Icons.help_outline, color: Colors.yellowAccent, size: 28),
            onPressed: () => _mostraGuidaSicurezza(context),
            tooltip: "Guida Rapida Sicurezza",
          )
        ],
      ),
      body: Stack(
        children: [
          // 1. BASE CROMATICA DIVISA (Blu/Giallo)
          Row(
            children: [
              Expanded(child: Container(color: const Color(0xFFE3F2FD))), // Blu chiaro
              Expanded(child: Container(color: const Color(0xFFFFFDE7))), // Giallo chiaro
            ],
          ),

          // 2. FILIGRANA STILIZZATA (Sfondo CID)
          Positioned.fill(
            child: Opacity(
              opacity: 0.12,
              child: Image.asset(
                'assets/sfondo_cid.jpg',
                width: double.infinity,
                height: double.infinity,
                fit: BoxFit.cover,
                errorBuilder: (c, e, s) => const SizedBox(),
              ),
            ),
          ),

          // 3. CONTENUTO ATTIVO (SEMPLIFICATO E OTTIMIZZATO)
          SafeArea(
            child: SingleChildScrollView(
              // Aggiungiamo un po' di padding per non attaccare il tutto ai bordi dello schermo
              padding: const EdgeInsets.all(16.0),
              child: Column(
                children: [
                  // Il box informativo ora è diretto figlio della colonna
                  _buildInfoBox(context),

                  const SizedBox(height: 20), // Spazio ridotto tra box e bottoni

                  // PULSANTI AFFIANCATI (Responsive)
                  IntrinsicHeight(
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        // LATO A (BLU)
                        Expanded(
                          child: _buildBtnConRilievo(
                            context,
                            "VEICOLO A",
                            "LATO BLU",
                            Colors.blue.shade800,
                            'A',
                            Icons.directions_car_rounded,
                          ),
                        ),
                        const SizedBox(width: 20),
                        // LATO B (GIALLO)
                        Expanded(
                          child: _buildBtnConRilievo(
                            context,
                            "VEICOLO B",
                            "LATO GIALLO",
                            Colors.amber.shade600,
                            'B',
                            Icons.directions_car_filled_rounded,
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 20), // Un po' di spazio extra in fondo
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  // FUNZIONE AGGIORNATA PER EFFETTO 3D POTENZIATO
  Widget _buildBtnConRilievo(BuildContext context, String titolo, String sottotitolo, Color color, String lato, IconData icon) {
    bool isB = lato == 'B';

    // Definiamo i colori per il gradiente (luce in alto a sx, ombra in basso a dx)
    Color colorLight, colorDark;
    if (isB) {
      // Per il giallo
      colorLight = Colors.amber.shade400; // Luce
      colorDark = Colors.amber.shade700; // Ombra
    } else {
      // Per il blu
      colorLight = Colors.blue.shade600; // Luce
      colorDark = Colors.blue.shade900; // Ombra
    }

    return Container(
      // Decorazione complessa del Container per l'effetto 3D
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(24), // Arrotondamento leggermente aumentato

        // 1. GRADIENTE DI SUPERFICIE (Simula la luce che colpisce un oggetto curvo)
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [colorLight, colorDark],
          stops: const [0.1, 0.9], // Regola i punti di luce e ombra
        ),

        // 2. OMBRE STRATIFICATE (Doppia ombra per profondità realistica)
        boxShadow: [
          // Ombra 1: "Spessore" (scura, nitida, vicina)
          BoxShadow(
            color: colorDark.withOpacity(0.6),
            blurRadius: 8,
            offset: const Offset(0, 8),
            spreadRadius: 1, // Espande leggermente l'ombra scura
          ),
          // Ombra 2: "Sollevamento" (morbida, ampia, lontana)
          BoxShadow(
            color: colorDark.withOpacity(0.3),
            blurRadius: 25,
            offset: const Offset(0, 18),
            spreadRadius: -5, // Contrae l'ombra diffusa per non sporcare troppo
          ),
        ],
      ),
      child: Material(
        color: Colors.transparent, // Necessario per far vedere il gradiente sottostante
        child: InkWell(
          // L'InkWell gestisce il tocco e l'effetto "splash"
          borderRadius: BorderRadius.circular(24),
          onTap: () {
            GlobalData.latoCorrente = lato;
            if (lato == 'B') {
              Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
            } else {
              Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
            }
          },
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 30),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // Aggiunto un leggero effetto ombra anche all'icona per farla "uscire"
                Icon(
                  icon,
                  size: 48,
                  color: isB ? Colors.black87 : Colors.white,
                  shadows: [
                    Shadow(
                      color: Colors.black.withOpacity(0.3),
                      offset: const Offset(2, 2),
                      blurRadius: 4,
                    )
                  ],
                ),
                const SizedBox(height: 15),
                Text(
                    titolo,
                    style: TextStyle(
                        fontSize: 20, // Leggermente più grande
                        fontWeight: FontWeight.w800, // Più grassetto
                        color: isB ? Colors.black87 : Colors.white,
                        // Leggera ombra sul testo per contrasto
                        shadows: [
                          Shadow(color: Colors.black.withOpacity(0.2), offset: const Offset(1, 1), blurRadius: 2)
                        ]
                    )
                ),
                const SizedBox(height: 5),
                Text(
                    sottotitolo,
                    style: TextStyle(
                        fontSize: 13,
                        fontWeight: FontWeight.w600,
                        color: isB ? Colors.black54 : Colors.white70
                    )
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildInfoBox(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      // Rimosso il margine verticale che creava spazio extra inutile
      decoration: BoxDecoration(
        color: Colors.blue.shade50,
        borderRadius: BorderRadius.circular(15),
        border: Border.all(color: Colors.blue.shade200, width: 1.5),
        // Aggiunta una leggera ombra per staccarlo dallo sfondo
        boxShadow: [
          BoxShadow(color: Colors.blue.shade100.withOpacity(0.5), blurRadius: 8, offset: const Offset(0, 4))
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Icon(Icons.lightbulb_outline, color: Colors.blue.shade800),
              const SizedBox(width: 10),
              Expanded(
                child: Text(
                  "Come funziona la scelta del lato?",
                  style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                      color: Colors.blue.shade900
                  ),
                ),
              ),
            ],
          ),
          const SizedBox(height: 12),
          const Text(
            "Nel modulo CAI, i veicoli vengono chiamati A e B. La lettera non indica chi ha ragione o torto, serve solo per distinguere le due auto.",
            style: TextStyle(fontSize: 14, height: 1.4),
          ),
          const SizedBox(height: 16),
          _buildInfoRow("🤝", "1. Accordati", "Scegli con l'altro conducente chi sarà il Veicolo A e chi il B."),
          const SizedBox(height: 12),
          _buildInfoRow("✍️", "2. Compila", "Seleziona il tuo lato e inserisci i dati con attenzione per non dover ricominciare."),
          const SizedBox(height: 12),
          _buildInfoRow("📱", "3. Scambia e Genera", "Firma e scambia i dati con la controparte per ottenere il PDF per l'assicurazione."),
        ],
      ),
    );
  }

  Widget _buildInfoRow(String emoji, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(emoji, style: const TextStyle(fontSize: 18)),
        const SizedBox(width: 10),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title\n", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

// Widget Helper interno
class _StepGuida extends StatelessWidget {
  final IconData icon;
  final String text;
  final bool isBold;

  const _StepGuida({required this.icon, required this.text, this.isBold = false});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Icon(icon, color: isBold ? Colors.red : Colors.blueGrey, size: 24),
          const SizedBox(width: 15),
          Expanded(
            child: Text(
              text,
              style: TextStyle(
                fontSize: 15,
                height: 1.4,
                fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
                color: isBold ? Colors.red.shade900 : Colors.black87,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
=== FILE: lib/comp_16.dart ===
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:path_provider/path_provider.dart';
import 'package:printing/printing.dart';
import 'package:share_plus/share_plus.dart';

import 'scambio_dati_screen.dart';
import 'pdf_engine.dart';
import 'global_data.dart';
import 'main.dart';
import 'comp_6-7.dart';
import 'comp_1-5.dart';

class Comp16Screen extends StatefulWidget {
  const Comp16Screen({super.key});

  @override
  State<Comp16Screen> createState() => _Comp16ScreenState();
}

class _Comp16ScreenState extends State<Comp16Screen> with WidgetsBindingObserver {
  bool _scambioEffettuato = false;
  bool _datiPresenti = false;
  bool _ioHoApprovato = false;
  bool _tuttiHannoApprovato = false;

  bool _staCancellando = false;
  bool _cancellazioneAvviataDaMe = false;

  String _statusText = "Esegui lo Scambio Dati per iniziare.";
  Color _statusColor = Colors.orange.shade800;
  IconData _statusIcon = Icons.warning_amber_rounded;

  File? _filePdfReale;
  Uint8List? _immagineAnteprima;
  bool _isLoading = false;
  StreamSubscription? _roomSubscription;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    _puliziaIngresso();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _mostraInfoPopup(context);
    });
  }

  void _mostraInfoPopup(BuildContext context) {
    Color activeColor = Colors.blue.shade900;

    showGeneralDialog(
      context: context,
      barrierDismissible: false,
      barrierLabel: "Popup",
      barrierColor: Colors.black.withOpacity(0.5),
      transitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) {
        return AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
          title: Row(
            children: [
              Icon(Icons.sync_alt, color: activeColor, size: 28),
              const SizedBox(width: 10),
              const Expanded(child: Text("Scambio e Invio", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18))),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text("Questa è la fase finale. Segui questi tre passaggi per concludere il modulo:", style: TextStyle(fontSize: 15)),
                const SizedBox(height: 16),
                _buildPopupRow(Icons.qr_code_scanner, "1. Scambio Dati", "Inquadra il QR Code dell'altro conducente oppure inserisci a mano il suo codice PIN."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.visibility, "2. Anteprima", "Apri l'anteprima per verificare che i dati di entrambi siano impaginati correttamente sul documento."),
                const SizedBox(height: 12),
                _buildPopupRow(Icons.check_circle, "3. Approvazione", "Se tutto è esatto, clicca su Approva. Quando entrambi avrete approvato, il file sarà pronto per l'invio."),
              ],
            ),
          ),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: activeColor,
                  foregroundColor: Colors.white,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                onPressed: () => Navigator.pop(context),
                child: const Text("HO CAPITO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
          ],
        );
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        var curvePosizione = CurvedAnimation(parent: animation, curve: Curves.easeOutBack, reverseCurve: Curves.easeInBack);
        var curveOpacita = CurvedAnimation(parent: animation, curve: Curves.easeOut, reverseCurve: Curves.easeIn);
        return SlideTransition(position: Tween<Offset>(begin: const Offset(0.0, 0.4), end: Offset.zero).animate(curvePosizione), child: FadeTransition(opacity: curveOpacita, child: child));
      },
    );
  }

  Widget _buildPopupRow(IconData icon, String title, String desc) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, size: 24, color: Colors.blueGrey),
        const SizedBox(width: 12),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
              children: [
                TextSpan(text: "$title: ", style: const TextStyle(fontWeight: FontWeight.bold)),
                TextSpan(text: desc),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Future<void> _puliziaIngresso() async {
    if (GlobalData.idScambioTemporaneo == null && GlobalData.idSessione != null) {
      GlobalData.idScambioTemporaneo = GlobalData.idSessione;
    }
    if (GlobalData.idScambioTemporaneo == null) {
      if (GlobalData.latoCorrente == 'A') GlobalData.resetB(); else GlobalData.resetA();
    }
    if (mounted) _verificaStatoPostScambio();
  }

  void _verificaStatoPostScambio() {
    bool datiOk = false;
    if (GlobalData.latoCorrente == 'A') {
      datiOk = GlobalData.Cognome_contraente_B.trim().isNotEmpty && GlobalData.Targa_B.trim().isNotEmpty;
    } else {
      datiOk = GlobalData.Cognome_contraente_A.trim().isNotEmpty && GlobalData.Targa_A.trim().isNotEmpty;
    }

    if (mounted) {
      setState(() {
        if (datiOk) {
          _scambioEffettuato = true;
          _datiPresenti = true;
          _statusText = "Dati ricevuti. Generazione anteprima...";
          _statusColor = Colors.blue.shade800;
          _statusIcon = Icons.pending_actions;
          _generaDocumenti();
          _attivaAscoltoStanza();
        } else {
          _resetStatiUI();
        }
      });
    }
  }

  void _resetStatiUI() {
    _scambioEffettuato = false;
    _datiPresenti = false;
    _ioHoApprovato = false;
    _tuttiHannoApprovato = false;
    _statusText = "Esegui lo Scambio Dati per iniziare.";
    _statusColor = Colors.orange.shade800;
    _statusIcon = Icons.warning_amber_rounded;
    _filePdfReale = null;
    _immagineAnteprima = null;
  }

  void _attivaAscoltoStanza() {
    String? idDaAscoltare = GlobalData.idScambioTemporaneo ?? GlobalData.idSessione;
    if (idDaAscoltare == null || _roomSubscription != null) return;

    _roomSubscription = FirebaseFirestore.instance
        .collection('scambi_cid')
        .doc(idDaAscoltare)
        .snapshots()
        .listen((snapshot) async {

      if (!snapshot.exists) {
        if (_ioHoApprovato) {
          _roomSubscription?.cancel();
          _roomSubscription = null;
          return;
        }
        if (!_staCancellando && !_cancellazioneAvviataDaMe && mounted) {
          _gestisciCancellazioneAltrui();
        }
        return;
      }

      final data = snapshot.data();
      if (data == null) return;

      if (data['status'] == 'retry') {
        if (!_cancellazioneAvviataDaMe) _gestisciCancellazioneAltrui();
        return;
      }

      bool appA = data['approved_A'] == true;
      bool appB = data['approved_B'] == true;

      if (appA && appB) {
        if (mounted) {
          setState(() {
            _tuttiHannoApprovato = true;
            _ioHoApprovato = true;
            _statusText = "DATI APPROVATI!\nPDF creato, procedi con il salvataggio o l'invio";
            _statusColor = Colors.green.shade800;
            _statusIcon = Icons.check_circle;
          });
          String? id = GlobalData.idSessione ?? GlobalData.idScambioTemporaneo;
          if (id != null) FirebaseFirestore.instance.collection('scambi_cid').doc(id).delete().catchError((_){});
        }
      }
      else if (_ioHoApprovato) {
        if (mounted) {
          setState(() {
            _statusText = "Hai approvato. In attesa dell'altro utente...";
            _statusColor = Colors.amber.shade800;
            _statusIcon = Icons.hourglass_top;
          });
        }
      }
    });
  }

  Future<void> _eseguiPuliziaFirebase({required bool notificaAltri}) async {
    setState(() {
      _isLoading = true;
      _cancellazioneAvviataDaMe = true;
    });

    await _roomSubscription?.cancel();
    _roomSubscription = null;

    Set<String> idsDaCancellare = {};
    if (GlobalData.idScambioTemporaneo != null) idsDaCancellare.add(GlobalData.idScambioTemporaneo!);
    if (GlobalData.idSessione != null) idsDaCancellare.add(GlobalData.idSessione!);

    for (String id in idsDaCancellare) {
      if (notificaAltri) {
        try {
          await FirebaseFirestore.instance.collection('scambi_cid').doc(id).update({'status': 'retry'})
              .timeout(const Duration(seconds: 2));
          await Future.delayed(const Duration(milliseconds: 300));
        } catch (_) {}
      }
      try {
        await FirebaseFirestore.instance.collection('scambi_cid').doc(id).delete();
      } catch (_) {}
    }
  }

  Future<void> _tornaIndietroConPulizia() async {
    await _eseguiPuliziaFirebase(notificaAltri: true);
    _resetDatiLocali();

    if (mounted) {
      setState(() => _isLoading = false);
      if (GlobalData.latoCorrente == 'A') {
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
      } else {
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
      }
    }
  }

  Future<void> _abbandonaScambioEHome() async {
    await _eseguiPuliziaFirebase(notificaAltri: true);
    GlobalData.reset();

    if (mounted) {
      setState(() => _isLoading = false);
      Navigator.pushAndRemoveUntil(
          context,
          MaterialPageRoute(builder: (c) => const HomeScreen()),
              (route) => false
      );
    }
  }

  Future<void> _ioApprovo() async {
    String? id = GlobalData.idSessione ?? GlobalData.idScambioTemporaneo;
    if (id != null) {
      try {
        String field = (GlobalData.latoCorrente == 'A') ? 'approved_A' : 'approved_B';
        await FirebaseFirestore.instance.collection('scambi_cid').doc(id).update({field: true});
      } catch (_) {}
    }

    if (mounted) {
      setState(() {
        _ioHoApprovato = true;
      });
    }
  }

  Future<void> _concludiEHome() async {
    await _eseguiPuliziaFirebase(notificaAltri: false);
    GlobalData.reset();
    if (mounted) {
      Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (c) => const HomeScreen()), (r) => false);
    }
  }

  void _resetDatiLocali() {
    if (GlobalData.latoCorrente == 'A') GlobalData.resetB(); else GlobalData.resetA();
    GlobalData.idScambioTemporaneo = null;
    GlobalData.idSessione = null;
  }

  void _gestisciCancellazioneAltrui() {
    _roomSubscription?.cancel();
    _roomSubscription = null;

    if (mounted) {
      Navigator.of(context).popUntil((route) => route.isFirst || route.settings.name == null);

      showDialog(
        context: context,
        barrierDismissible: false,
        builder: (ctx) => AlertDialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
          backgroundColor: Colors.white,
          surfaceTintColor: Colors.transparent,
          icon: Icon(Icons.warning_amber_rounded, size: 60, color: Colors.amber.shade800),
          iconPadding: const EdgeInsets.only(top: 24, bottom: 16),
          title: Text("Attenzione", textAlign: TextAlign.center, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22, color: Colors.amber.shade900)),
          content: const Padding(
            padding: EdgeInsets.symmetric(vertical: 8.0),
            child: Text(
              "L'altro utente ha deciso di modificare i propri dati o non ha accettato i tuoi.\n\nSarai riportato alla schermata iniziale dove potrai eventualmente apporre modifiche.",
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 16, height: 1.4, color: Colors.black87),
            ),
          ),
          actionsPadding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
          actions: [
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                  onPressed: () {
                    Navigator.pop(ctx);
                    _resetDatiLocali();
                    if (GlobalData.latoCorrente == 'A') {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
                    } else {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
                    }
                  },
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.amber.shade800, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), elevation: 0),
                  child: const Text("HO CAPITO", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))
              ),
            )
          ],
        ),
      );
    }
  }

  Future<void> _generaDocumenti() async {
    if (!mounted) return;
    setState(() => _isLoading = true);
    try {
      final List<int> pdfBytes = await PdfEngine.generaDocumentoCai();
      if (pdfBytes.isEmpty) throw Exception("PDF vuoto");

      final appDocDir = await getApplicationDocumentsDirectory();
      final file = File('${appDocDir.path}/CID_${DateTime.now().millisecondsSinceEpoch}.pdf');

      await file.writeAsBytes(pdfBytes, flush: true);

      Uint8List? anteprima;
      await for (final page in Printing.raster(Uint8List.fromList(pdfBytes), pages: [0], dpi: 150)) {
        anteprima = await page.toPng(); break;
      }
      if (mounted) {
        setState(() { _filePdfReale = file; _immagineAnteprima = anteprima; _isLoading = false; });
      }
    } catch (e) {
      if (mounted) setState(() => _isLoading = false);
    }
  }

  Future<void> _vaiAScambioDati() async {
    await Navigator.push(context, MaterialPageRoute(builder: (context) => const ScambioDatiScreen()));
    _verificaStatoPostScambio();
  }

  void _apriAnteprimaSchermoIntero() {
    if (!_scambioEffettuato || !_datiPresenti || _immagineAnteprima == null || _filePdfReale == null) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Dati non pronti!")));
      return;
    }
    Navigator.push(context, MaterialPageRoute(builder: (context) => ImageViewerScreen(
        imageBytes: _immagineAnteprima!,
        pdfFile: _filePdfReale!,
        isAlreadyApproved: _ioHoApprovato,
        onConfirmCorrection: _tornaIndietroConPulizia,
        onConfirmApproval: _ioApprovo
    )));
  }

  Future<void> _inviaMailConAllegato(BuildContext context) async {
    if (_filePdfReale == null) return;

    try {
      bool isA = GlobalData.latoCorrente == 'A';
      String polizzaChiScrive = (isA ? GlobalData.Numero_Polizza_A : GlobalData.Numero_Polizza_B).trim();
      String targaChiScrive = (isA ? GlobalData.Targa_A : GlobalData.Targa_B).trim();
      String firmaChiScrive = "${isA ? GlobalData.Nome_contraente_A : GlobalData.Nome_contraente_B} ${isA ? GlobalData.Cognome_contraente_A : GlobalData.Cognome_contraente_B}";
      String contattoChiScrive = (isA ? GlobalData.N_telefono_mail_contraente_A : GlobalData.N_telefono_mail_contraente_B).trim();

      String compagniaUtente = (isA ? GlobalData.Denominazione_A : GlobalData.Denominazione_B).trim().toUpperCase();
      String emailDestinatario = "";

      if (GlobalData.assicurazioni.containsKey(compagniaUtente)) {
        emailDestinatario = GlobalData.assicurazioni[compagniaUtente]!;
      } else {
        for (var key in GlobalData.assicurazioni.keys) {
          if (key.isNotEmpty && (compagniaUtente.contains(key) || key.contains(compagniaUtente))) {
            emailDestinatario = GlobalData.assicurazioni[key]!;
            break;
          }
        }
      }

      List<String> listaCC = [];
      if (contattoChiScrive.contains("@")) listaCC.add(contattoChiScrive);

      String oggetto = "DENUNCIA SINISTRO - Polizza n. $polizzaChiScrive - Targa $targaChiScrive";
      String corpo = "Spett.le Compagnia,\n\n"
          "Con la presente inoltro in allegato il modulo CAI relativo al sinistro avvenuto in data ${GlobalData.data_incidente} alle ore ${GlobalData.ora} nel comune di ${GlobalData.luogo}.\n\n"
          "Rimaniamo in attesa dell'apertura del fascicolo.\n\n"
          "Cordiali saluti,\n$firmaChiScrive\nContatto: $contattoChiScrive";

      final Email email = Email(
        subject: oggetto,
        body: corpo,
        recipients: emailDestinatario.isNotEmpty ? [emailDestinatario] : [],
        cc: listaCC,
        attachmentPaths: [_filePdfReale!.path],
        isHTML: false,
      );

      await FlutterEmailSender.send(email);

    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Nessuna app Mail predefinita trovata. Apro la condivisione..."), duration: Duration(seconds: 3), backgroundColor: Colors.orange));
        _apriCondivisione(context);
      }
    }
  }

  Future<void> _apriCondivisione(BuildContext context) async {
    if (_filePdfReale == null) return;
    final box = context.findRenderObject() as RenderBox?;
    await Share.shareXFiles(
      [XFile(_filePdfReale!.path, mimeType: 'application/pdf')],
      subject: 'Modulo CAI',
      text: 'Ecco il modulo CAI compilato.',
      sharePositionOrigin: box != null ? (box.localToGlobal(Offset.zero) & box.size) : null,
    );
  }

  Future<void> _salvaPdfLocale(BuildContext context) async {
    await _apriCondivisione(context);
  }

  @override
  void dispose() {
    _roomSubscription?.cancel();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool pdfPronto = !_isLoading && _filePdfReale != null && _immagineAnteprima != null;
    bool abilitaAnteprima = _scambioEffettuato && _datiPresenti && pdfPronto;
    bool abilitaFinali = _tuttiHannoApprovato && pdfPronto;

    String testoAnteprima = !_scambioEffettuato ? "2. ANTEPRIMA (Prima fai Scambio)" :
    (_ioHoApprovato ? "ANTEPRIMA (IN ATTESA...)" : "2. APRI ANTEPRIMA E APPROVA");
    if (_tuttiHannoApprovato) testoAnteprima = "ANTEPRIMA (COMPLETATA)";

    return Container(
      width: double.infinity,
      height: double.infinity,
      decoration: BoxDecoration(
        color: const Color(0xFFF0F4F8),
        image: DecorationImage(
          image: const AssetImage('assets/sfondo_mappa.jpg'),
          fit: BoxFit.cover,
          colorFilter: ColorFilter.mode(
            const Color(0xFFF0F4F8).withOpacity(0.6),
            BlendMode.lighten,
          ),
        ),
      ),
      child: PopScope(
        canPop: false,
        onPopInvoked: (didPop) async {
          if (didPop) return;
          if (_ioHoApprovato) _concludiEHome(); else _tornaIndietroConPulizia();
        },
        child: Scaffold(
          backgroundColor: Colors.transparent,
          extendBodyBehindAppBar: true,
          appBar: AppBar(
            title: const Text("Invio e Salvataggio", style: TextStyle(fontWeight: FontWeight.w800, fontSize: 20)),
            centerTitle: true,
            backgroundColor: Colors.blue.shade900.withOpacity(0.95),
            foregroundColor: Colors.white,
            elevation: 10,
            leading: IconButton(
                icon: const Icon(Icons.arrow_back),
                onPressed: _ioHoApprovato ? _concludiEHome : _tornaIndietroConPulizia
            ),
            shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(20))),
          ),
          body: Stack(children: [
            SafeArea(
                child: SingleChildScrollView(
                    padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
                    child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [

                      _buildStatusCard(),

                      const SizedBox(height: 20),

                      // VA DIRETTO ALLA PAGINA DI SCAMBIO
                      _btn("1. SCAMBIO DATI", Icons.sync_alt, Colors.orange.shade800, onTap: _vaiAScambioDati, disabled: _ioHoApprovato),

                      const SizedBox(height: 20),

                      _btn(testoAnteprima, Icons.visibility, _statusColor, onTap: abilitaAnteprima ? _apriAnteprimaSchermoIntero : null, disabled: !abilitaAnteprima),

                      const SizedBox(height: 8),
                      Divider(color: Colors.white.withOpacity(0.5), thickness: 1),
                      const SizedBox(height: 8),

                      Builder(builder: (ctx) => _btn("SALVA SUL DISPOSITIVO", Icons.save_alt, Colors.green.shade700, onTap: abilitaFinali ? () => _salvaPdfLocale(ctx) : null, disabled: !abilitaFinali)),

                      const SizedBox(height: 20),

                      Builder(builder: (ctx) => _btn("INVIA ALL'ASSICURAZIONE", Icons.send_rounded, Colors.green.shade700, onTap: abilitaFinali ? () => _inviaMailConAllegato(ctx) : null, disabled: !abilitaFinali)),

                      const SizedBox(height: 40),

                      _btn(
                          _tuttiHannoApprovato ? "TORNA ALLA HOME" : "CANCELLA TUTTO E ESCI",
                          _tuttiHannoApprovato ? Icons.home : Icons.delete_sweep,
                          _tuttiHannoApprovato ? Colors.green.shade800 : Colors.red.shade900,
                          onTap: _tuttiHannoApprovato ? _concludiEHome : _abbandonaScambioEHome,
                          disabled: false
                      ),

                      const SizedBox(height: 30)
                    ]))),

            if (_isLoading)
              Container(color: Colors.black54, child: const Center(child: Column(mainAxisSize: MainAxisSize.min, children: [CircularProgressIndicator(color: Colors.white), SizedBox(height: 20), Text("Elaborazione in corso...", style: TextStyle(color: Colors.white))]))),
          ]),
        ),
      ),
    );
  }

  Widget _btn(String label, IconData icon, Color color, {VoidCallback? onTap, bool disabled = false}) {
    bool on = onTap != null && !disabled;
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        boxShadow: on ? [BoxShadow(color: Colors.black.withOpacity(0.3), offset: const Offset(0, 4), blurRadius: 5)] : [],
      ),
      child: ElevatedButton(
          onPressed: on ? onTap : null,
          style: ElevatedButton.styleFrom(
            backgroundColor: on ? color : Colors.grey,
            foregroundColor: Colors.white,
            padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20),
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          ),
          child: Row(children: [
            Icon(icon, size: 28), const SizedBox(width: 20),
            Expanded(child: Text(label, textAlign: TextAlign.center, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
            const Icon(Icons.lock, size: 20, color: Colors.transparent)
          ])
      ),
    );
  }

  Widget _buildStatusCard() {
    return Container(
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(16), border: Border.all(color: _statusColor, width: 2), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 6, offset: const Offset(0, 3))]),
        child: Row(children: [
          Icon(_statusIcon, color: _statusColor, size: 36), const SizedBox(width: 15),
          Expanded(child: Text(_statusText, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: _statusColor)))
        ])
    );
  }
}

class ImageViewerScreen extends StatelessWidget {
  final Uint8List imageBytes;
  final File pdfFile;
  final bool isAlreadyApproved;
  final Function onConfirmCorrection;
  final Function onConfirmApproval;

  const ImageViewerScreen({super.key, required this.imageBytes, required this.pdfFile, required this.isAlreadyApproved, required this.onConfirmCorrection, required this.onConfirmApproval});

  Future<void> _askCorrection(BuildContext context) async {
    String titolo = isAlreadyApproved ? "Chiudere?" : "Richiedere correzione?";
    String testo = isAlreadyApproved
        ? "Hai già approvato. Uscendo tornerai alla schermata precedente in attesa dell'altro utente."
        : "Questo annullerà lo scambio per entrambi e vi riporterà alla modifica.";
    String tasto = isAlreadyApproved ? "CHIUDI" : "CORREGGI";

    bool? conf = await showDialog(context: context, builder: (c) => AlertDialog(
        title: Text(titolo),
        content: Text(testo),
        actions: [
          TextButton(onPressed: () => Navigator.pop(c, false), child: const Text("ANNULLA")),
          ElevatedButton(onPressed: () => Navigator.pop(c, true), child: Text(tasto))
        ]
    ));
    if (conf == true) {
      Navigator.pop(context);
      if (!isAlreadyApproved) onConfirmCorrection();
    }
  }

  Future<void> _askApproval(BuildContext context) async { Navigator.pop(context); onConfirmApproval(); }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: const Text("Verifica Dati"), backgroundColor: Colors.black, foregroundColor: Colors.white),
      body: Column(children: [
        Expanded(child: InteractiveViewer(minScale: 0.5, maxScale: 4.0, child: Center(child: Container(color: Colors.white, child: Image.memory(imageBytes, fit: BoxFit.contain))))),
        Container(
          padding: const EdgeInsets.all(16.0),
          decoration: BoxDecoration(color: Colors.white, boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10, offset: const Offset(0, -2))]),
          child: SafeArea(
            child: Row(children: [
              Expanded(
                child: ElevatedButton.icon(
                  onPressed: () => _askCorrection(context),
                  icon: Icon(isAlreadyApproved ? Icons.arrow_back : Icons.edit),
                  label: Text(isAlreadyApproved ? "INDIETRO" : "CORREGGI"),
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.orange.shade800, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: ElevatedButton.icon(
                  onPressed: isAlreadyApproved ? null : () => _askApproval(context),
                  icon: isAlreadyApproved ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.check_circle),
                  label: Text(isAlreadyApproved ? "IN ATTESA..." : "APPROVA"),
                  style: ElevatedButton.styleFrom(backgroundColor: isAlreadyApproved ? Colors.grey : Colors.green.shade700, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
                ),
              ),
            ]),
          ),
        )
      ]),
    );
  }
}
=== FILE: lib/models.dart ===
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'dart:math' as math; // Serve per i calcoli della freccia

// --- PAINTER PER IL DISEGNO (A SCHERMO E SU PDF) ---
class PainterV40 extends CustomPainter {
  final List<TrattoPenna> tr;
  final List<ElementoGrafico> el;

  PainterV40(this.tr, this.el);

  @override
  void paint(Canvas canvas, Size size) {
    // Stile della penna (Strada/Linee)
    Paint pStrada = Paint()
      ..color = Colors.black
      ..strokeWidth = 3.0
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    // 1. DISEGNO TRATTI (PENNA E FRECCE)
    for (var t in tr) {
      if (t.punti.length > 1) {
        Path path = Path()..moveTo(t.punti[0].dx, t.punti[0].dy);
        for (var pt in t.punti) path.lineTo(pt.dx, pt.dy);

        canvas.drawPath(path, pStrada);

        // Se è una freccia, disegna la punta alla fine
        if (t.tipo == 'freccia') {
          // Prendi gli ultimi due punti per calcolare l'angolazione
          _disegnaPunta(canvas, t.punti[t.punti.length - 2], t.punti.last, pStrada);
        }
      }
    }

    // 2. DISEGNO ELEMENTI (AUTO E TESTO)
    for (var e in el) {
      canvas.save();
      // Sposta e ruota il canvas nella posizione dell'elemento
      canvas.translate(e.posizione.dx, e.posizione.dy);
      canvas.rotate(e.rotazione);

      if (e.tipo == 'testo') {
        _disegnaTesto(canvas, e.label ?? "");
      } else {
        _disegnaAuto(canvas, e.tipo == 'autoA' ? 'A' : 'B', e.tipo == 'autoA' ? Colors.blue : Colors.orange);
      }
      canvas.restore();
    }
  }

  // Disegna il rettangolo dell'auto con la lettera
  void _disegnaAuto(Canvas canvas, String lettera, Color colore) {
    Paint p = Paint()..color = colore;
    // Auto centrata (70x40 px)
    Rect r = Rect.fromCenter(center: Offset.zero, width: 70, height: 40);
    canvas.drawRect(r, p);

    // Bordo nero auto
    canvas.drawRect(r, Paint()..color = Colors.black..style = PaintingStyle.stroke..strokeWidth = 2);

    // Lettera centrata
    final tp = TextPainter(
        text: TextSpan(text: lettera, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16)),
        textDirection: TextDirection.ltr
    )..layout();

    tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2));
  }

  // Disegna etichette di testo
  void _disegnaTesto(Canvas canvas, String txt) {
    final tp = TextPainter(
        text: TextSpan(text: txt, style: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold, backgroundColor: Colors.white70)),
        textDirection: TextDirection.ltr
    )..layout();
    tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2));
  }

  // Calcola e disegna la punta della freccia
  void _disegnaPunta(Canvas canvas, Offset p1, Offset p2, Paint paint) {
    double angle = (p2 - p1).direction;
    // Disegna due linee inclinate rispetto alla direzione finale
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle - 0.5, 15), paint);
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle + 0.5, 15), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

// --- MODELLO DATI: TRATTO PENNA ---
class TrattoPenna {
  List<Offset> punti;
  String tipo; // 'penna' o 'freccia'

  TrattoPenna(this.punti, {this.tipo = 'penna'});

  // Metodo utile per la cancellazione (hit test)
  bool contiene(Offset p) {
    for (var punto in punti) {
      if ((p - punto).distance < 20.0) return true;
    }
    return false;
  }

  Map<String, dynamic> toMap() => {
    'punti': punti.map((p) => {'dx': p.dx, 'dy': p.dy}).toList(),
    'tipo': tipo,
  };

  factory TrattoPenna.fromMap(Map<String, dynamic> map) => TrattoPenna(
    (map['punti'] as List).map((p) => Offset(p['dx'], p['dy'])).toList(),
    tipo: map['tipo'] ?? 'penna',
  );
}

// --- MODELLO DATI: ELEMENTO GRAFICO (AUTO/TESTO) ---
class ElementoGrafico {
  Offset posizione;
  String tipo; // 'autoA', 'autoB', 'testo'
  double rotazione;
  String? label;

  ElementoGrafico(this.posizione, this.tipo, {this.rotazione = 0, this.label});

  Map<String, dynamic> toMap() => {
    'pos': {'dx': posizione.dx, 'dy': posizione.dy},
    'tipo': tipo,
    'rot': rotazione,
    'label': label,
  };

  factory ElementoGrafico.fromMap(Map<String, dynamic> map) => ElementoGrafico(
    Offset(map['pos']['dx'], map['pos']['dy']),
    map['tipo'],
    rotazione: (map['rot'] as num?)?.toDouble() ?? 0,
    label: map['label'],
  );

  bool contiene(Offset p) => (p - posizione).distance < 35;

  // --- METODO CRUCIALE PER IL PDF ---
  // Genera un'immagine PNG ritagliata e ottimizzata del grafico
  static Future<Uint8List?> fondiGraficoDinamica(List<dynamic> trattiRaw, List<dynamic> elementiRaw) async {
    // Conversione sicura dei tipi (nel caso arrivino come dynamic da GlobalData)
    List<TrattoPenna> tratti = trattiRaw.cast<TrattoPenna>();
    List<ElementoGrafico> elementi = elementiRaw.cast<ElementoGrafico>();

    if (tratti.isEmpty && elementi.isEmpty) return null;

    // 1. Calcolo Bounding Box (i confini del disegno)
    double minX = double.infinity, minY = double.infinity;
    double maxX = double.negativeInfinity, maxY = double.negativeInfinity;

    void checkPoint(Offset p) {
      if (p.dx < minX) minX = p.dx;
      if (p.dx > maxX) maxX = p.dx;
      if (p.dy < minY) minY = p.dy;
      if (p.dy > maxY) maxY = p.dy;
    }

    for (var t in tratti) { for (var p in t.punti) checkPoint(p); }
    for (var e in elementi) checkPoint(e.posizione);

    // Se non ci sono dimensioni valide, esci
    if (minX == double.infinity) return null;

    // Aggiungiamo margine (padding) bianco intorno
    const double pad = 40.0;
    double width = (maxX - minX) + (pad * 2);
    double height = (maxY - minY) + (pad * 2);

    // 2. Disegno su Canvas off-screen
    final recorder = ui.PictureRecorder();
    // Crea canvas delle dimensioni esatte
    final canvas = ui.Canvas(recorder, Rect.fromLTWH(0, 0, width, height));

    // Sfondo Bianco (Copre la griglia del modulo sottostante)
    canvas.drawRect(Rect.fromLTWH(0, 0, width, height), Paint()..color = Colors.white);

    // Sposta l'origine del canvas per centrare il disegno ed eliminare lo spazio vuoto in alto/sinistra
    canvas.translate(-minX + pad, -minY + pad);

    // Usa il painter esistente per ridisegnare tutto
    final painter = PainterV40(tratti, elementi);
    painter.paint(canvas, Size(width, height));

    // 3. Conversione in PNG
    final picture = recorder.endRecording();
    final img = await picture.toImage(width.toInt(), height.toInt());
    final pngBytes = await img.toByteData(format: ui.ImageByteFormat.png);

    return pngBytes?.buffer.asUint8List();
  }
}