haz que la primera letra de la primera palabra de dentro de las listas de "actividades disponibles" y "compañía" empiecen por mayúscula:

import random
import tkinter as tk
from tkinter import messagebox
import ttkbootstrap as ttkb
import requests
import webbrowser
import json
import os
from dotenv import load_dotenv
from datetime import datetime

# --- Configuración Inicial ---
load_dotenv()
API_KEY = os.getenv("OPENTRIPMAP_API_KEY")
DESTINOS_FILE = "destinos.json"
SAVED_PLAN_FILE = "plan_vacaciones.json"

# --- Datos Globales ---
destinos_data = []
continentes_disponibles = []
actividades_disponibles = []
duraciones_disponibles = []
companias_disponibles = []

# --- Funciones de Carga y Procesamiento ---

def cargar_datos_destinos():
    global destinos_data
    try:
        with open(DESTINOS_FILE, "r", encoding="utf-8") as file:
            destinos_data = json.load(file)
        
        if not destinos_data:
            messagebox.showerror("Error", "El archivo de destinos está vacío.")
            return False
        
        print(f"Cargados {len(destinos_data)} destinos desde {DESTINOS_FILE}")
        return True
    
    except FileNotFoundError:
        messagebox.showerror("Archivo no encontrado",
                           f"No se encontró '{DESTINOS_FILE}'.\nAsegúrate de que esté en la carpeta actual.")
        return False
    except json.JSONDecodeError:
        messagebox.showerror("Formato inválido",
                           f"El archivo '{DESTINOS_FILE}' no tiene un formato JSON válido.")
        return False
    except Exception as e:
        messagebox.showerror("Error inesperado", f"Error al cargar datos: {str(e)}")
        return False

def inicializar_opciones_seleccion():
    global continentes_disponibles, actividades_disponibles, duraciones_disponibles, companias_disponibles
    continentes_set = set()
    actividades_set = set()
    duraciones_set = set()
    companias_set = set()

    for destino in destinos_data:
        if continente := destino.get("continente", "").strip():
            continentes_set.add(continente)
        
        for actividad in destino.get("actividades", []):
            if act_clean := actividad.strip():
                actividades_set.add(act_clean)
        
        if duracion := destino.get("duracion", "").strip():
            duraciones_set.add(duracion)
        
        if compania := destino.get("compañia", "").strip():
            companias_set.add(compania)

    continentes_disponibles = ["Todos"] + sorted(continentes_set)
    actividades_disponibles = ["Cualquiera"] + sorted(actividades_set)
    duraciones_disponibles = ["Cualquiera"] + sorted(duraciones_set)
    companias_disponibles = ["Cualquiera"] + sorted(companias_set)

def validar_destino(destino):
    campos_requeridos = ["nombre", "continente", "actividades", "duracion", "compañia", "latitude", "longitude"]
    return all(campo in destino and destino[campo] for campo in campos_requeridos)

def filtrar_destinos(selected_continent, selected_activity, selected_duration, selected_company):
    matches = []
    for destino in destinos_data:
        if not validar_destino(destino):
            continue
        if selected_continent != "Todos" and destino["continente"].lower() != selected_continent.lower():
            continue
        if selected_activity != "Cualquiera" and selected_activity not in destino["actividades"]:
            continue
        if selected_duration != "Cualquiera" and destino["duracion"] != selected_duration:
            continue
        if selected_company != "Cualquiera" and destino["compañia"] != selected_company:
            continue
        matches.append(destino)
    return matches

def generar_plan_aleatorio(matching):
    return random.choice(matching) if matching else None

def obtener_puntos_interes(lat, lon, radius=5000, limit=5):
    if not API_KEY:
        return []
    
    url = f"https://api.opentripmap.com/0.1/en/places/radius?radius={radius}&lon={lon}&lat={lat}&apikey={API_KEY}&limit={limit}"
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        data = response.json()
        return [
            {"name": feature["properties"].get("name", "").strip(), "xid": feature["properties"].get("xid")}
            for feature in data.get("features", []) 
            if feature["properties"].get("name", "").strip()
        ]
    except:
        return []

def limpiar_resultados():
    for widget in frame_resultados.winfo_children():
        if widget != label_estado:
            widget.destroy()

def crear_link_clickeable(parent, texto, url):
    link = ttkb.Label(parent, text=texto, cursor="hand2", 
                     foreground="#1E88E5", font=("Helvetica", 10, "underline"))
    link.bind("<Button-1>", lambda e: webbrowser.open(url))
    return link

def mostrar_plan_en_gui(plan, actividad_seleccionada):
    limpiar_resultados()

    # --- Frame principal de 3 columnas ---
    columns_frame = ttkb.Frame(frame_resultados, padding=10)
    columns_frame.pack(fill="both", expand=True, padx=10, pady=10)

    # --- Columna 1: Actividades disponibles ---
    col1 = ttkb.Frame(columns_frame)
    col1.grid(row=0, column=0, sticky="nsew", padx=10, pady=5)
    
    actividades_frame = ttkb.LabelFrame(col1, text="🎪 Actividades disponibles", padding=10)
    actividades_frame.pack(fill="both", expand=True)
    
    actividades = plan.get("actividades", [])
    if actividades:
        for act in sorted(actividades):
            ttkb.Label(actividades_frame, text=f"• {act}", font=("Helvetica", 11)).pack(anchor="w", padx=10, pady=2)
    else:
        ttkb.Label(actividades_frame, text="No hay actividades registradas", 
                  font=("Helvetica", 10, "italic")).pack()

    # --- Columna 2: Info principal ---
    col2 = ttkb.Frame(columns_frame)
    col2.grid(row=0, column=1, sticky="nsew", padx=10, pady=5)
    
    ttkb.Label(col2, text=f"🌴 {plan['nombre']}", 
              font=("Helvetica", 18, "bold")).pack(pady=(0, 10))
    
    info_frame = ttkb.Frame(col2)
    info_frame.pack(anchor="w", pady=5)
    
    ttkb.Label(info_frame, text="🌍 Continente:", font=("Helvetica", 11, "bold")).grid(row=0, column=0, sticky="w")
    ttkb.Label(info_frame, text=plan.get('continente', 'N/A'), 
              font=("Helvetica", 11)).grid(row=0, column=1, sticky="w", padx=(5, 15))
    
    ttkb.Label(info_frame, text="⏱️ Duración:", font=("Helvetica", 11, "bold")).grid(row=1, column=0, sticky="w")
    ttkb.Label(info_frame, text=plan.get('duracion', 'N/A'), 
              font=("Helvetica", 11)).grid(row=1, column=1, sticky="w", padx=5)
    
    ttkb.Label(info_frame, text="👥 Compañía:", font=("Helvetica", 11, "bold")).grid(row=2, column=0, sticky="w")
    ttkb.Label(info_frame, text=plan.get('compañia', 'N/A'), 
              font=("Helvetica", 11)).grid(row=2, column=1, sticky="w", padx=5)
    
    # Actividad destacada
    actividad_frame = ttkb.Frame(col2, padding=(0, 15, 0, 0))
    actividad_frame.pack(fill="x", pady=10)
    
    if actividad_seleccionada != "Cualquiera":
        ttkb.Label(actividad_frame, text="🎯 Actividad solicitada:", 
                  font=("Helvetica", 12, "bold")).pack(anchor="w")
        ttkb.Label(actividad_frame, text=actividad_seleccionada, 
                  font=("Helvetica", 11)).pack(anchor="w", padx=20)
    elif actividades:
        ttkb.Label(actividad_frame, text="🎯 Actividad destacada:", 
                  font=("Helvetica", 12, "bold")).pack(anchor="w")
        ttkb.Label(actividad_frame, text=actividades[0], 
                  font=("Helvetica", 11)).pack(anchor="w", padx=20)

    # --- Columna 3: Mapa y puntos de interés ---
    col3 = ttkb.Frame(columns_frame)
    col3.grid(row=0, column=2, sticky="nsew", padx=10, pady=5)
    
    # Ubicación
    ubicacion_frame = ttkb.Frame(col3)
    ubicacion_frame.pack(fill="x", pady=(0, 15))
    
    ttkb.Label(ubicacion_frame, text="🗺️ Ubicación:", 
              font=("Helvetica", 12, "bold")).pack(anchor="w")
    
    mapa_url = f"https://www.google.com/maps?q={plan['latitude']},{plan['longitude']}"
    crear_link_clickeable(ubicacion_frame, "📍 Abrir en Google Maps", mapa_url).pack(anchor="w", pady=5)
    
    # Puntos de interés
    if API_KEY:
        puntos = obtener_puntos_interes(plan["latitude"], plan["longitude"])
        if puntos:
            poi_frame = ttkb.Frame(col3)
            poi_frame.pack(fill="x")
            
            ttkb.Label(poi_frame, text="🏛️ Lugares de interés:", 
                      font=("Helvetica", 12, "bold")).pack(anchor="w")
            
            for punto in puntos:
                if punto["xid"]:
                    url_poi = f"https://opentripmap.com/en/card/{punto['xid']}"
                    crear_link_clickeable(poi_frame, f"• {punto['name']}", url_poi).pack(anchor="w", padx=20, pady=2)
                else:
                    ttkb.Label(poi_frame, text=f"• {punto['name']}").pack(anchor="w", padx=20, pady=2)
        else:
            ttkb.Label(col3, text="No se encontraron puntos de interés", 
                      font=("Helvetica", 10, "italic")).pack(anchor="w")
    else:
        ttkb.Label(col3, text="🔑 API Key no configurada para lugares de interés", 
                  font=("Helvetica", 10, "italic"), foreground="#F44336").pack(anchor="w")

    # Configurar pesos de columnas
    columns_frame.columnconfigure(0, weight=1, uniform="cols")
    columns_frame.columnconfigure(1, weight=1, uniform="cols")
    columns_frame.columnconfigure(2, weight=1, uniform="cols")
    
    # --- Botones de acción ---
    button_frame = ttkb.Frame(frame_resultados)
    button_frame.pack(pady=20)
    
    ttkb.Button(button_frame, text="💾 Guardar Plan", command=lambda: guardar_plan(plan),
                bootstyle="success", width=18).pack(side="left", padx=10)
    ttkb.Button(button_frame, text="🔄 Nuevo Plan", command=generar_y_mostrar,
                bootstyle="info", width=18).pack(side="left", padx=10)
    ttkb.Button(button_frame, text="❌ Salir", command=root.destroy,
                bootstyle="danger", width=18).pack(side="left", padx=10)

def guardar_plan(plan):
    if not plan:
        messagebox.showerror("Error", "No hay plan para guardar.")
        return
    
    try:
        planes_existentes = []
        if os.path.exists(SAVED_PLAN_FILE):
            try:
                with open(SAVED_PLAN_FILE, "r", encoding="utf-8") as f:
                    planes_existentes = json.load(f)
            except json.JSONDecodeError:
                planes_existentes = []
        
        plan_con_fecha = plan.copy()
        plan_con_fecha["fecha_guardado"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        # Evitar duplicados por nombre
        if any(p.get("nombre") == plan["nombre"] for p in planes_existentes):
            messagebox.showinfo("Información", "Este plan ya fue guardado anteriormente.")
            return
        
        planes_existentes.append(plan_con_fecha)
        with open(SAVED_PLAN_FILE, "w", encoding="utf-8") as f:
            json.dump(planes_existentes, f, indent=4, ensure_ascii=False)
        
        messagebox.showinfo("Guardado", f"Plan guardado en '{SAVED_PLAN_FILE}'.")
    
    except Exception as e:
        messagebox.showerror("Error", f"No se pudo guardar el plan: {str(e)}")

def generar_y_mostrar():
    selected_continent = combo_continente.get()
    selected_activity = combo_actividad.get()
    selected_duration = combo_duracion.get()
    selected_company = combo_compania.get()
    
    if not all([selected_continent, selected_activity, selected_duration, selected_company]):
        messagebox.showwarning("Selección incompleta", "Por favor completa todas las opciones.")
        return
    
    matching = filtrar_destinos(selected_continent, selected_activity, selected_duration, selected_company)
    
    if not matching:
        messagebox.showinfo("Sin resultados",
                          "No se encontraron destinos con estos criterios.\nPrueba con otras opciones.")
        label_estado.config(text="")
        return
    
    plan = generar_plan_aleatorio(matching)
    mostrar_plan_en_gui(plan, selected_activity)
    label_estado.config(text="✅ Plan generado exitosamente!", foreground="#4CAF50")

def setup_gui():
    global root, combo_continente, combo_actividad, combo_duracion, combo_compania, frame_resultados, label_estado
    
    root = ttkb.Window(themename="morph")
    root.title("🌍 Generador de Planes Vacacionales")
    root.state('zoomed')  # Maximize window
    root.resizable(True, True)
    
    main_frame = ttkb.Frame(root)
    main_frame.grid(row=0, column=0, sticky="nsew")
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)
    
    # Configure grid layout for main_frame
    main_frame.columnconfigure(0, weight=1)
    main_frame.rowconfigure(0, weight=0)  # Header
    main_frame.rowconfigure(1, weight=1)  # Controls
    main_frame.rowconfigure(2, weight=1)  # Results

    # Cabecera
    header_frame = ttkb.Frame(main_frame)
    header_frame.grid(row=0, column=0, sticky="ew", pady=(15, 20))
    
    ttkb.Label(header_frame, text="🌴 Planificador de Vacaciones 🌴", 
              font=("Helvetica", 24, "bold"), foreground="#2E7D32").pack()
    ttkb.Label(header_frame, text="Descubre tu próximo destino ideal", 
              font=("Helvetica", 12)).pack(pady=(5, 0))
    
    # Wrapper para centrar controles
    controls_wrapper = ttkb.Frame(main_frame)
    controls_wrapper.grid(row=1, column=0, sticky="nsew")
    controls_wrapper.columnconfigure(0, weight=1)
    controls_wrapper.rowconfigure(0, weight=1)
    
    # Controles
    frame_controles = ttkb.LabelFrame(controls_wrapper, text="⚙️ Configura tu Viaje Ideal", padding=20, bootstyle="primary")
    frame_controles.pack(anchor="center", padx=20, pady=20)
    
    # Formulario en grid
    ttkb.Label(frame_controles, text="🌍 Continente:", font=("Helvetica", 11, "bold")).grid(row=0, column=0, sticky="w", padx=10, pady=8)
    combo_continente = ttkb.Combobox(frame_controles, values=continentes_disponibles, state="readonly", width=25)
    combo_continente.set("Todos")
    combo_continente.grid(row=0, column=1, sticky="ew", padx=10, pady=8)
    
    ttkb.Label(frame_controles, text="🎯 Actividad:", font=("Helvetica", 11, "bold")).grid(row=1, column=0, sticky="w", padx=10, pady=8)
    combo_actividad = ttkb.Combobox(frame_controles, values=actividades_disponibles, state="readonly", width=25)
    combo_actividad.set("Cualquiera")
    combo_actividad.grid(row=1, column=1, sticky="ew", padx=10, pady=8)
    
    ttkb.Label(frame_controles, text="⏱️ Duración:", font=("Helvetica", 11, "bold")).grid(row=2, column=0, sticky="w", padx=10, pady=8)
    combo_duracion = ttkb.Combobox(frame_controles, values=duraciones_disponibles, state="readonly", width=25)
    combo_duracion.set("Cualquiera")
    combo_duracion.grid(row=2, column=1, sticky="ew", padx=10, pady=8)
    
    ttkb.Label(frame_controles, text="👥 Compañía:", font=("Helvetica", 11, "bold")).grid(row=3, column=0, sticky="w", padx=10, pady=8)
    combo_compania = ttkb.Combobox(frame_controles, values=companias_disponibles, state="readonly", width=25)
    combo_compania.set("Cualquiera")
    combo_compania.grid(row=3, column=1, sticky="ew", padx=10, pady=8)
    
    # Botón centrado
    btn_frame = ttkb.Frame(frame_controles)
    btn_frame.grid(row=4, column=0, columnspan=2, pady=15)
    ttkb.Button(btn_frame, text="✨ Generar Plan", command=generar_y_mostrar,
                bootstyle="success", width=20).pack()
    
    # Resultados
    frame_resultados = ttkb.LabelFrame(main_frame, text="🎯 Tu Plan de Vacaciones", padding=10, bootstyle="info")
    frame_resultados.grid(row=2, column=0, sticky="nsew")
    
    label_estado = ttkb.Label(frame_resultados, text="👆 Completa tus preferencias y haz clic en 'Generar Plan'",
                              font=("Helvetica", 12, "italic"), anchor="center", bootstyle="secondary")
    label_estado.pack(pady=20)

if __name__ == "__main__":
    if cargar_datos_destinos():
        inicializar_opciones_seleccion()
        setup_gui()
        root.mainloop()