<?php

require_once __DIR__ . '/db/auth.php';
require_once __DIR__ . '/db/scstatsitem.php';
require_once __DIR__ . '/db/scitemcustom.php';
require_once __DIR__ . '/db/sccharacters.php';

auth_start_session();
auth_bootstrap();
auth_handle_page_access_post('sccharacters.php', 'Personnages');
auth_require_page_access('sccharacters.php', 'Personnages');
scstatsitem_bootstrap();
scitemcustom_bootstrap();
sccharacters_bootstrap();

function sccharacters_current_owner_auth_id(PDO $db): int
{
    $session_user = auth_current_user();
    if ($session_user === '') {
        return 0;
    }

    $stmt = $db->prepare(
        'SELECT cl_auth_id
         FROM tbl_auth
         WHERE cl_auth_user = :user
         LIMIT 1'
    );
    $stmt->execute(['user' => $session_user]);

    return (int) $stmt->fetchColumn();
}

function sccharacters_clean_text(?string $value): string
{
    return trim((string) $value);
}

function sccharacters_normalize_item_quantity($value): ?int
{
    if ($value === null) {
        return null;
    }

    $value = trim((string) $value);
    if ($value === '' || !preg_match('/^\d+$/', $value)) {
        return null;
    }

    $quantity = (int) $value;

    if ($quantity <= 0) {
        return null;
    }

    return min($quantity, 999999);
}

function sccharacters_is_valid_url(string $value): bool
{
    if ($value === '') {
        return true;
    }

    return filter_var($value, FILTER_VALIDATE_URL) !== false;
}

function sccharacters_excerpt(string $value, int $limit = 120): string
{
    $value = trim($value);
    if ($value === '') {
        return '';
    }

    if (function_exists('mb_strimwidth')) {
        return mb_strimwidth($value, 0, $limit, '…', 'UTF-8');
    }

    if (strlen($value) <= $limit) {
        return $value;
    }

    return rtrim(substr($value, 0, max(0, $limit - 1))) . '…';
}

function sccharacters_display_stat_value($value): string
{
    if (!is_numeric((string) $value)) {
        return '0';
    }

    $formatted = number_format((float) $value, 2, '.', '');
    $formatted = rtrim(rtrim($formatted, '0'), '.');

    return $formatted === '' ? '0' : $formatted;
}

function sccharacters_custom_stat_preview(array $stat_row): string
{
    $sign = (string) ($stat_row['cl_scitemcustomstat_sign'] ?? '');
    $prefix = $sign === '-' ? '-' : ($sign === '+' ? '+' : '');
    $value = sccharacters_display_stat_value($stat_row['cl_scitemcustomstat_value'] ?? 0);
    $unit = trim((string) ($stat_row['cl_scstatsitem_unit'] ?? ''));

    return trim((string) ($stat_row['cl_scstatsitem_name'] ?? '') . ' : ' . $prefix . $value . ($unit !== '' ? ' ' . $unit : ''));
}

function sccharacters_share_url(string $token): string
{
    $is_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
        || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
        || ((string) ($_SERVER['SERVER_PORT'] ?? '') === '443');

    $scheme = $is_https ? 'https' : 'http';
    $host = trim((string) ($_SERVER['HTTP_HOST'] ?? ''));

    if ($host === '') {
        $host = '127.0.0.1';
    }

    return $scheme . '://' . $host . '/sccharacter.php?share=' . rawurlencode($token);
}

function sccharacters_find_owned_character(PDO $db, int $character_id, int $owner_auth_id): ?array
{
    if ($character_id <= 0 || $owner_auth_id <= 0) {
        return null;
    }

    $stmt = $db->prepare(
        'SELECT *
         FROM tbl_sccharacters
         WHERE cl_sccharacter_id = :id
           AND cl_sccharacter_owner_auth_id = :owner_auth_id
         LIMIT 1'
    );
    $stmt->execute([
        'id' => $character_id,
        'owner_auth_id' => $owner_auth_id,
    ]);

    $row = $stmt->fetch();

    return $row ?: null;
}

function sccharacters_allowed_item_per_page(): array
{
    return [25, 50, 100, 200];
}

function sccharacters_normalize_item_per_page($value): int
{
    $per_page = (int) $value;
    $allowed = sccharacters_allowed_item_per_page();

    return in_array($per_page, $allowed, true) ? $per_page : 50;
}

function sccharacters_build_return_url(
    int $character_id = 0,
    string $item_source = '',
    string $item_search = '',
    bool $keep_item_panel = false,
    int $item_page = 1,
    int $item_per_page = 50
): string {
    $params = [];

    if ($character_id > 0) {
        $params['character'] = $character_id;
    }

    if (in_array($item_source, ['base', 'custom'], true)) {
        $params['item_source'] = $item_source;
    }

    if ($item_search !== '') {
        $params['item_search'] = $item_search;
    }

    $item_page = max(1, $item_page);
    if ($item_page > 1) {
        $params['item_page'] = $item_page;
    }

    $item_per_page = sccharacters_normalize_item_per_page($item_per_page);
    if ($item_per_page !== 50) {
        $params['item_per_page'] = $item_per_page;
    }

    if ($keep_item_panel) {
        $params['item_panel'] = '1';
    }

    return 'sccharacters.php' . ($params !== [] ? '?' . http_build_query($params) : '');
}

function sccharacters_staged_items_session_key(int $owner_auth_id, int $character_id): string
{
    return $owner_auth_id . ':' . $character_id;
}

function sccharacters_get_staged_items(int $owner_auth_id, int $character_id): array
{
    if ($owner_auth_id <= 0 || $character_id <= 0) {
        return [];
    }

    if (!isset($_SESSION['sccharacters_staged_items']) || !is_array($_SESSION['sccharacters_staged_items'])) {
        $_SESSION['sccharacters_staged_items'] = [];
    }

    $session_key = sccharacters_staged_items_session_key($owner_auth_id, $character_id);
    $items = $_SESSION['sccharacters_staged_items'][$session_key] ?? [];

    return is_array($items) ? $items : [];
}

function sccharacters_save_staged_items(int $owner_auth_id, int $character_id, array $items): void
{
    if (!isset($_SESSION['sccharacters_staged_items']) || !is_array($_SESSION['sccharacters_staged_items'])) {
        $_SESSION['sccharacters_staged_items'] = [];
    }

    $session_key = sccharacters_staged_items_session_key($owner_auth_id, $character_id);

    if ($owner_auth_id <= 0 || $character_id <= 0 || $items === []) {
        unset($_SESSION['sccharacters_staged_items'][$session_key]);
        return;
    }

    $_SESSION['sccharacters_staged_items'][$session_key] = $items;
}

function sccharacters_parse_item_key(string $item_key): ?array
{
    if (!preg_match('/^(base|custom):(\d+)$/', $item_key, $matches)) {
        return null;
    }

    return [
        'source' => (string) $matches[1],
        'source_id' => (int) $matches[2],
    ];
}

function sccharacters_merge_selected_items(array $staged_items, array $selected_items, array $item_slots, array $item_notes, array $item_quantities = []): array
{
    $selected_items = array_values(array_unique(array_map('strval', $selected_items)));
    $staged_count = 0;
    $error_count = 0;

    foreach ($selected_items as $item_key) {
        $parsed = sccharacters_parse_item_key($item_key);
        if (!$parsed) {
            $error_count++;
            continue;
        }

        $staged_items[$item_key] = [
            'source' => $parsed['source'],
            'source_id' => $parsed['source_id'],
            'category' => sccharacters_clean_text($item_slots[$item_key] ?? ''),
            'note' => sccharacters_clean_text($item_notes[$item_key] ?? ''),
            'quantity' => sccharacters_normalize_item_quantity($item_quantities[$item_key] ?? null),
        ];
        $staged_count++;
    }

    return [
        'items' => $staged_items,
        'staged_count' => $staged_count,
        'error_count' => $error_count,
    ];
}

function sccharacters_fetch_staged_item_details(PDO $db, int $owner_auth_id, array $staged_items): array
{
    $details = [];
    $base_ids = [];
    $custom_ids = [];

    foreach ($staged_items as $item_key => $item_data) {
        $parsed = sccharacters_parse_item_key((string) $item_key);
        if (!$parsed) {
            continue;
        }

        if ($parsed['source'] === 'custom') {
            $custom_ids[] = $parsed['source_id'];
        } else {
            $base_ids[] = $parsed['source_id'];
        }
    }

    $base_ids = array_values(array_unique(array_filter($base_ids)));
    $custom_ids = array_values(array_unique(array_filter($custom_ids)));

    if ($base_ids !== []) {
        $placeholders = implode(',', array_fill(0, count($base_ids), '?'));
        $stmt = $db->prepare(
            "SELECT cl_scobjs_id, cl_scobjs_name, cl_scobjs_type, cl_scobjs_subtype, cl_scobjs_uuid
             FROM tbl_scobjs
             WHERE cl_scobjs_id IN ({$placeholders})"
        );
        $stmt->execute($base_ids);

        foreach ($stmt->fetchAll() as $row) {
            $item_key = 'base:' . (int) $row['cl_scobjs_id'];
            $details[$item_key] = [
                'item_key' => $item_key,
                'source' => 'base',
                'source_id' => (int) $row['cl_scobjs_id'],
                'name' => (string) ($row['cl_scobjs_name'] ?? ''),
                'type' => (string) ($row['cl_scobjs_type'] ?? ''),
                'subtype' => (string) ($row['cl_scobjs_subtype'] ?? ''),
                'uuid' => (string) ($row['cl_scobjs_uuid'] ?? ''),
                'is_custom' => false,
                'stat_count' => null,
            ];
        }
    }

    if ($custom_ids !== []) {
        $placeholders = implode(',', array_fill(0, count($custom_ids), '?'));
        $stmt = $db->prepare(
            "SELECT c.cl_scitemcustom_id,
                    o.cl_scobjs_name,
                    o.cl_scobjs_type,
                    o.cl_scobjs_subtype,
                    o.cl_scobjs_uuid,
                    COUNT(cs.cl_scitemcustomstat_id) AS cl_scitemcustom_stat_count
             FROM tbl_scitemcustom c
             INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
             LEFT JOIN tbl_scitemcustomstat cs ON cs.cl_scitemcustomstat_itemcustom_id = c.cl_scitemcustom_id
             WHERE c.cl_scitemcustom_owner_auth_id = ?
               AND c.cl_scitemcustom_id IN ({$placeholders})
             GROUP BY c.cl_scitemcustom_id"
        );
        $stmt->execute(array_merge([$owner_auth_id], $custom_ids));

        foreach ($stmt->fetchAll() as $row) {
            $item_key = 'custom:' . (int) $row['cl_scitemcustom_id'];
            $details[$item_key] = [
                'item_key' => $item_key,
                'source' => 'custom',
                'source_id' => (int) $row['cl_scitemcustom_id'],
                'name' => (string) ($row['cl_scobjs_name'] ?? ''),
                'type' => (string) ($row['cl_scobjs_type'] ?? ''),
                'subtype' => (string) ($row['cl_scobjs_subtype'] ?? ''),
                'uuid' => (string) ($row['cl_scobjs_uuid'] ?? ''),
                'is_custom' => true,
                'stat_count' => (int) ($row['cl_scitemcustom_stat_count'] ?? 0),
            ];
        }
    }

    return $details;
}

function sccharacters_fetch_owned_character_item_ids(PDO $db, int $owner_auth_id, int $character_id): array
{
    if ($character_id <= 0 || $owner_auth_id <= 0) {
        return [];
    }

    sccharacters_reindex_character_items($db, $character_id);

    $stmt = $db->prepare(
        'SELECT ci.cl_sccharacteritem_id
         FROM tbl_sccharacteritems ci
         INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
         WHERE ci.cl_sccharacteritem_character_id = :character_id
           AND c.cl_sccharacter_owner_auth_id = :owner_auth_id
         ORDER BY ci.cl_sccharacteritem_sort_order ASC, ci.cl_sccharacteritem_id ASC'
    );
    $stmt->execute([
        'character_id' => $character_id,
        'owner_auth_id' => $owner_auth_id,
    ]);

    return array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
}

function sccharacters_save_character_item_order(PDO $db, int $character_id, array $ordered_item_ids): void
{
    if ($character_id <= 0 || $ordered_item_ids === []) {
        return;
    }

    $stmt = $db->prepare(
        'UPDATE tbl_sccharacteritems
         SET cl_sccharacteritem_sort_order = :sort_order
         WHERE cl_sccharacteritem_character_id = :character_id
           AND cl_sccharacteritem_id = :item_id'
    );

    $db->beginTransaction();

    try {
        $position = 1;
        foreach ($ordered_item_ids as $item_id) {
            $stmt->execute([
                'sort_order' => $position,
                'character_id' => $character_id,
                'item_id' => (int) $item_id,
            ]);
            $position++;
        }

        $db->commit();
    } catch (Throwable $exception) {
        if ($db->inTransaction()) {
            $db->rollBack();
        }

        throw $exception;
    }
}

function sccharacters_move_owned_character_item(
    PDO $db,
    int $owner_auth_id,
    int $character_id,
    int $character_item_id,
    string $direction
): bool {
    $ordered_item_ids = sccharacters_fetch_owned_character_item_ids($db, $owner_auth_id, $character_id);
    if ($ordered_item_ids === []) {
        return false;
    }

    $current_index = array_search($character_item_id, $ordered_item_ids, true);
    if ($current_index === false) {
        return false;
    }

    $target_index = $current_index;
    $last_index = count($ordered_item_ids) - 1;

    switch ($direction) {
        case 'top':
            $target_index = 0;
            break;
        case 'up':
            $target_index = max(0, $current_index - 1);
            break;
        case 'down':
            $target_index = min($last_index, $current_index + 1);
            break;
        case 'bottom':
            $target_index = $last_index;
            break;
        default:
            return false;
    }

    if ($target_index === $current_index) {
        return true;
    }

    $moving_item_id = $ordered_item_ids[$current_index];
    array_splice($ordered_item_ids, $current_index, 1);
    array_splice($ordered_item_ids, $target_index, 0, [$moving_item_id]);

    sccharacters_save_character_item_order($db, $character_id, $ordered_item_ids);

    return true;
}

function sccharacters_fetch_owned_character_item_rows(PDO $db, int $owner_auth_id, int $character_id): array
{
    if ($character_id <= 0 || $owner_auth_id <= 0) {
        return [];
    }

    sccharacters_reindex_character_items($db, $character_id);

    $stmt = $db->prepare(
        "SELECT
            ci.cl_sccharacteritem_id,
            ci.cl_sccharacteritem_slot,
            ci.cl_sccharacteritem_source,
            bo.cl_scobjs_type AS cl_sccharacteritem_base_type,
            bo.cl_scobjs_subtype AS cl_sccharacteritem_base_subtype,
            oo.cl_scobjs_type AS cl_sccharacteritem_custom_type,
            oo.cl_scobjs_subtype AS cl_sccharacteritem_custom_subtype
         FROM tbl_sccharacteritems ci
         INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
         LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = ci.cl_sccharacteritem_scobjs_id
         LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
         LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
         WHERE ci.cl_sccharacteritem_character_id = :character_id
           AND c.cl_sccharacter_owner_auth_id = :owner_auth_id
         ORDER BY ci.cl_sccharacteritem_sort_order ASC, ci.cl_sccharacteritem_id ASC"
    );
    $stmt->execute([
        'character_id' => $character_id,
        'owner_auth_id' => $owner_auth_id,
    ]);

    return $stmt->fetchAll();
}

function sccharacters_group_item_ids_by_category(array $item_rows): array
{
    $grouped = [];

    foreach ($item_rows as $item_row) {
        $is_custom = ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
        $item_type = $is_custom
            ? (string) ($item_row['cl_sccharacteritem_custom_type'] ?? '')
            : (string) ($item_row['cl_sccharacteritem_base_type'] ?? '');
        $item_subtype = $is_custom
            ? (string) ($item_row['cl_sccharacteritem_custom_subtype'] ?? '')
            : (string) ($item_row['cl_sccharacteritem_base_subtype'] ?? '');
        $category_key = sccharacters_resolve_item_category(
            (string) ($item_row['cl_sccharacteritem_slot'] ?? ''),
            $item_type,
            $item_subtype
        );

        if (!isset($grouped[$category_key])) {
            $grouped[$category_key] = [];
        }

        $grouped[$category_key][] = (int) ($item_row['cl_sccharacteritem_id'] ?? 0);
    }

    return $grouped;
}

function sccharacters_flatten_grouped_item_ids(array $grouped_item_ids, array $category_order): array
{
    $ordered_ids = [];
    $sorted_groups = sccharacters_sort_items_by_category_order($grouped_item_ids, $category_order);

    foreach ($sorted_groups as $category_item_ids) {
        foreach ($category_item_ids as $item_id) {
            $item_id = (int) $item_id;
            if ($item_id > 0) {
                $ordered_ids[] = $item_id;
            }
        }
    }

    return $ordered_ids;
}

function sccharacters_move_owned_character_category(
    PDO $db,
    int $owner_auth_id,
    int $character_id,
    string $category_key,
    string $direction
): bool {
    $character = sccharacters_find_owned_character($db, $character_id, $owner_auth_id);
    if (!$character) {
        return false;
    }

    $grouped_item_ids = sccharacters_group_item_ids_by_category(
        sccharacters_fetch_owned_character_item_rows($db, $owner_auth_id, $character_id)
    );
    if (!isset($grouped_item_ids[$category_key])) {
        return false;
    }

    $category_order = sccharacters_character_category_order($character);
    $visible_order = [];
    foreach ($category_order as $ordered_category_key) {
        if (isset($grouped_item_ids[$ordered_category_key])) {
            $visible_order[] = $ordered_category_key;
        }
    }

    if ($visible_order === []) {
        return false;
    }

    $current_index = array_search($category_key, $visible_order, true);
    if ($current_index === false) {
        return false;
    }

    $target_index = $current_index;
    if ($direction === 'up') {
        $target_index = max(0, $current_index - 1);
    } elseif ($direction === 'down') {
        $target_index = min(count($visible_order) - 1, $current_index + 1);
    } else {
        return false;
    }

    if ($target_index === $current_index) {
        return true;
    }

    $moving_category_key = $visible_order[$current_index];
    array_splice($visible_order, $current_index, 1);
    array_splice($visible_order, $target_index, 0, [$moving_category_key]);

    $visible_lookup = array_fill_keys(array_keys($grouped_item_ids), true);
    $visible_pointer = 0;
    $rebuilt_order = [];
    foreach ($category_order as $ordered_category_key) {
        if (isset($visible_lookup[$ordered_category_key])) {
            $rebuilt_order[] = $visible_order[$visible_pointer] ?? $ordered_category_key;
            $visible_pointer++;
        } else {
            $rebuilt_order[] = $ordered_category_key;
        }
    }

    sccharacters_save_character_category_order($db, $character_id, $rebuilt_order);
    sccharacters_save_character_item_order(
        $db,
        $character_id,
        sccharacters_flatten_grouped_item_ids($grouped_item_ids, $rebuilt_order)
    );

    return true;
}

function sccharacters_reorder_owned_character_items(
    PDO $db,
    int $owner_auth_id,
    int $character_id,
    string $category_key,
    array $ordered_item_ids
): bool {
    $character = sccharacters_find_owned_character($db, $character_id, $owner_auth_id);
    if (!$character) {
        return false;
    }

    $grouped_item_ids = sccharacters_group_item_ids_by_category(
        sccharacters_fetch_owned_character_item_rows($db, $owner_auth_id, $character_id)
    );
    if (!isset($grouped_item_ids[$category_key])) {
        return false;
    }

    $current_item_ids = array_map('intval', $grouped_item_ids[$category_key]);
    $posted_item_ids = array_values(array_filter(array_map('intval', $ordered_item_ids), static fn ($item_id) => $item_id > 0));

    sort($current_item_ids);
    $sorted_posted = $posted_item_ids;
    sort($sorted_posted);

    if ($posted_item_ids === [] || $sorted_posted !== $current_item_ids) {
        return false;
    }

    $grouped_item_ids[$category_key] = $posted_item_ids;
    sccharacters_save_character_item_order(
        $db,
        $character_id,
        sccharacters_flatten_grouped_item_ids($grouped_item_ids, sccharacters_character_category_order($character))
    );

    return true;
}

function sccharacters_attach_item(
    PDO $db,
    int $owner_auth_id,
    int $character_id,
    string $source,
    int $source_id,
    string $requested_category,
    ?int $quantity,
    string $note,
    ?string &$error_message = null
): bool {
    if ($character_id <= 0 || $owner_auth_id <= 0 || $source_id <= 0) {
        $error_message = 'Paramètres d’ajout invalides.';
        return false;
    }

    $character = sccharacters_find_owned_character($db, $character_id, $owner_auth_id);
    if (!$character) {
        $error_message = 'Personnage introuvable.';
        return false;
    }

    $sort_order = sccharacters_next_item_sort_order($db, $character_id);

    if ($source === 'base') {
        $stmt_source = $db->prepare(
            'SELECT cl_scobjs_id AS item_id, cl_scobjs_type, cl_scobjs_subtype
             FROM tbl_scobjs
             WHERE cl_scobjs_id = :id
             LIMIT 1'
        );
        $stmt_source->execute(['id' => $source_id]);
        $item_row = $stmt_source->fetch();

        if (!$item_row) {
            $error_message = 'Objet de base introuvable.';
            return false;
        }

        $category = sccharacters_resolve_item_category(
            $requested_category,
            (string) ($item_row['cl_scobjs_type'] ?? ''),
            (string) ($item_row['cl_scobjs_subtype'] ?? '')
        );

        $stmt_insert = $db->prepare(
            'INSERT INTO tbl_sccharacteritems (
                cl_sccharacteritem_character_id,
                cl_sccharacteritem_source,
                cl_sccharacteritem_scobjs_id,
                cl_sccharacteritem_scitemcustom_id,
                cl_sccharacteritem_slot,
                cl_sccharacteritem_quantity,
                cl_sccharacteritem_note,
                cl_sccharacteritem_sort_order
            ) VALUES (
                :character_id,
                :source,
                :scobjs_id,
                NULL,
                :slot,
                :quantity,
                :note,
                :sort_order
            )'
        );
        $stmt_insert->execute([
            'character_id' => $character_id,
            'source' => 'base',
            'scobjs_id' => $source_id,
            'slot' => $category,
            'quantity' => $quantity,
            'note' => $note !== '' ? $note : null,
            'sort_order' => $sort_order,
        ]);

        return true;
    }

    if ($source === 'custom') {
        $stmt_source = $db->prepare(
            'SELECT c.cl_scitemcustom_id AS item_id, o.cl_scobjs_type, o.cl_scobjs_subtype
             FROM tbl_scitemcustom c
             INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
             WHERE c.cl_scitemcustom_id = :id
               AND c.cl_scitemcustom_owner_auth_id = :owner_auth_id
             LIMIT 1'
        );
        $stmt_source->execute([
            'id' => $source_id,
            'owner_auth_id' => $owner_auth_id,
        ]);
        $item_row = $stmt_source->fetch();

        if (!$item_row) {
            $error_message = 'Objet personnalisé introuvable ou non autorisé.';
            return false;
        }

        $category = sccharacters_resolve_item_category(
            $requested_category,
            (string) ($item_row['cl_scobjs_type'] ?? ''),
            (string) ($item_row['cl_scobjs_subtype'] ?? '')
        );

        $stmt_insert = $db->prepare(
            'INSERT INTO tbl_sccharacteritems (
                cl_sccharacteritem_character_id,
                cl_sccharacteritem_source,
                cl_sccharacteritem_scobjs_id,
                cl_sccharacteritem_scitemcustom_id,
                cl_sccharacteritem_slot,
                cl_sccharacteritem_quantity,
                cl_sccharacteritem_note,
                cl_sccharacteritem_sort_order
            ) VALUES (
                :character_id,
                :source,
                NULL,
                :scitemcustom_id,
                :slot,
                :quantity,
                :note,
                :sort_order
            )'
        );
        $stmt_insert->execute([
            'character_id' => $character_id,
            'source' => 'custom',
            'scitemcustom_id' => $source_id,
            'slot' => $category,
            'quantity' => $quantity,
            'note' => $note !== '' ? $note : null,
            'sort_order' => $sort_order,
        ]);

        return true;
    }

    $error_message = 'Source d’objet invalide.';
    return false;
}

function sccharacters_update_character_item(
    PDO $db,
    int $owner_auth_id,
    int $character_id,
    int $character_item_id,
    string $requested_category,
    ?int $quantity,
    string $note,
    ?string &$error_message = null
): bool {
    if ($character_id <= 0 || $owner_auth_id <= 0 || $character_item_id <= 0) {
        $error_message = 'Paramètres de mise à jour invalides.';
        return false;
    }

    $stmt_item = $db->prepare(
        "SELECT
            ci.cl_sccharacteritem_id,
            ci.cl_sccharacteritem_source,
            bo.cl_scobjs_type AS cl_sccharacteritem_base_type,
            bo.cl_scobjs_subtype AS cl_sccharacteritem_base_subtype,
            oo.cl_scobjs_type AS cl_sccharacteritem_custom_type,
            oo.cl_scobjs_subtype AS cl_sccharacteritem_custom_subtype
         FROM tbl_sccharacteritems ci
         INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
         LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = ci.cl_sccharacteritem_scobjs_id
         LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
         LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
         WHERE ci.cl_sccharacteritem_id = :character_item_id
           AND c.cl_sccharacter_id = :character_id
           AND c.cl_sccharacter_owner_auth_id = :owner_auth_id
         LIMIT 1"
    );
    $stmt_item->execute([
        'character_item_id' => $character_item_id,
        'character_id' => $character_id,
        'owner_auth_id' => $owner_auth_id,
    ]);
    $item_row = $stmt_item->fetch();

    if (!$item_row) {
        $error_message = 'Objet introuvable ou non autorisé.';
        return false;
    }

    $is_custom = (string) ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
    $item_type = $is_custom
        ? (string) ($item_row['cl_sccharacteritem_custom_type'] ?? '')
        : (string) ($item_row['cl_sccharacteritem_base_type'] ?? '');
    $item_subtype = $is_custom
        ? (string) ($item_row['cl_sccharacteritem_custom_subtype'] ?? '')
        : (string) ($item_row['cl_sccharacteritem_base_subtype'] ?? '');
    $category = sccharacters_resolve_item_category($requested_category, $item_type, $item_subtype);

    $stmt_update = $db->prepare(
        'UPDATE tbl_sccharacteritems
         SET cl_sccharacteritem_slot = :slot,
             cl_sccharacteritem_quantity = :quantity,
             cl_sccharacteritem_note = :note
         WHERE cl_sccharacteritem_id = :character_item_id
           AND cl_sccharacteritem_character_id = :character_id'
    );
    $stmt_update->execute([
        'slot' => $category,
        'quantity' => $quantity,
        'note' => $note !== '' ? $note : null,
        'character_item_id' => $character_item_id,
        'character_id' => $character_id,
    ]);

    return true;
}

$flash = auth_flash_get();
$flash_type = $flash['type'] ?? '';
$flash_message = $flash['message'] ?? '';
$db = db();
$csrf_token = auth_csrf_token();
$current_owner_auth_id = sccharacters_current_owner_auth_id($db);
$current_session_user = auth_current_user();
$current_session_role = auth_current_role();
$role_label = auth_role_label($current_session_role);

if ($current_owner_auth_id <= 0) {
    auth_flash_set('error', 'Impossible d’identifier le compte connecté.');
    header('Location: index.php');
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $submitted_csrf = (string) ($_POST['csrf_token'] ?? '');
    if (!auth_validate_csrf($submitted_csrf)) {
        auth_flash_set('error', 'Jeton CSRF invalide.');
        header('Location: sccharacters.php');
        exit;
    }

    $action = (string) ($_POST['action'] ?? '');

    if ($action === 'create_character') {
        $name = sccharacters_clean_text($_POST['character_name'] ?? '');
        $role = sccharacters_clean_text($_POST['character_role'] ?? '');
        $faction = '';
        $org_rsi_url = sccharacters_clean_text($_POST['character_org_rsi_url'] ?? '');
        $player_handle = sccharacters_clean_text($_POST['character_player_handle'] ?? '');
        $avatar_url = sccharacters_clean_text($_POST['character_avatar_url'] ?? '');
        $description = sccharacters_clean_text($_POST['character_description'] ?? '');
        $notes = sccharacters_clean_text($_POST['character_notes'] ?? '');
        $share_enabled = isset($_POST['character_share_enabled']) ? 1 : 0;
        $is_pinned = isset($_POST['character_is_pinned']) ? 1 : 0;
        $posted_category_order_state = sccharacters_clean_text($_POST['category_order_state'] ?? '');
        $posted_item_order_state_raw = trim((string) ($_POST['item_order_state'] ?? ''));

        if ($name === '') {
            auth_flash_set('error', 'Le nom du personnage est obligatoire.');
            header('Location: sccharacters.php?mode=create');
            exit;
        }

        if (!sccharacters_is_valid_url($avatar_url)) {
            auth_flash_set('error', 'L’URL de l’avatar n’est pas valide.');
            header('Location: sccharacters.php?mode=create');
            exit;
        }

        if (!sccharacters_is_valid_url($org_rsi_url)) {
            auth_flash_set('error', 'L’URL RSI de l’organisation n’est pas valide.');
            header('Location: sccharacters.php?mode=create');
            exit;
        }

        $stmt = $db->prepare(
            'INSERT INTO tbl_sccharacters (
                cl_sccharacter_owner_auth_id,
                cl_sccharacter_name,
                cl_sccharacter_role,
                cl_sccharacter_faction,
                cl_sccharacter_org_rsi_url,
                cl_sccharacter_player_handle,
                cl_sccharacter_avatar_url,
                cl_sccharacter_description,
                cl_sccharacter_notes,
                cl_sccharacter_share_token,
                cl_sccharacter_share_enabled,
                cl_sccharacter_is_pinned
            ) VALUES (
                :owner_auth_id,
                :name,
                :role,
                :faction,
                :org_rsi_url,
                :player_handle,
                :avatar_url,
                :description,
                :notes,
                :share_token,
                :share_enabled,
                :is_pinned
            )'
        );
        $stmt->execute([
            'owner_auth_id' => $current_owner_auth_id,
            'name' => $name,
            'role' => $role,
            'faction' => $faction,
            'org_rsi_url' => $org_rsi_url,
            'player_handle' => $player_handle,
            'avatar_url' => $avatar_url,
            'description' => $description !== '' ? $description : null,
            'notes' => $notes !== '' ? $notes : null,
            'share_token' => sccharacters_generate_share_token($db),
            'share_enabled' => $share_enabled,
            'is_pinned' => $is_pinned,
        ]);

        $new_character_id = (int) $db->lastInsertId();
        auth_flash_set('success', 'Personnage créé avec succès.');
        header('Location: sccharacters.php?character=' . $new_character_id);
        exit;
    }

    if ($action === 'update_character') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $character = sccharacters_find_owned_character($db, $character_id, $current_owner_auth_id);

        if (!$character) {
            auth_flash_set('error', 'Personnage introuvable.');
            header('Location: sccharacters.php');
            exit;
        }

        $name = sccharacters_clean_text($_POST['character_name'] ?? '');
        $role = sccharacters_clean_text($_POST['character_role'] ?? '');
        $faction = '';
        $org_rsi_url = sccharacters_clean_text($_POST['character_org_rsi_url'] ?? '');
        $player_handle = sccharacters_clean_text($_POST['character_player_handle'] ?? '');
        $avatar_url = sccharacters_clean_text($_POST['character_avatar_url'] ?? '');
        $description = sccharacters_clean_text($_POST['character_description'] ?? '');
        $notes = sccharacters_clean_text($_POST['character_notes'] ?? '');
        $share_enabled = isset($_POST['character_share_enabled']) ? 1 : 0;
        $is_pinned = isset($_POST['character_is_pinned']) ? 1 : 0;
        $posted_category_order_state = sccharacters_clean_text($_POST['category_order_state'] ?? '');
        $posted_item_order_state_raw = trim((string) ($_POST['item_order_state'] ?? ''));

        if ($name === '') {
            auth_flash_set('error', 'Le nom du personnage est obligatoire.');
            header('Location: sccharacters.php?character=' . $character_id);
            exit;
        }

        if (!sccharacters_is_valid_url($avatar_url)) {
            auth_flash_set('error', 'L’URL de l’avatar n’est pas valide.');
            header('Location: sccharacters.php?character=' . $character_id);
            exit;
        }

        if (!sccharacters_is_valid_url($org_rsi_url)) {
            auth_flash_set('error', 'L’URL RSI de l’organisation n’est pas valide.');
            header('Location: sccharacters.php?character=' . $character_id);
            exit;
        }

        $stmt = $db->prepare(
            'UPDATE tbl_sccharacters
             SET cl_sccharacter_name = :name,
                 cl_sccharacter_role = :role,
                 cl_sccharacter_faction = :faction,
                 cl_sccharacter_org_rsi_url = :org_rsi_url,
                 cl_sccharacter_player_handle = :player_handle,
                 cl_sccharacter_avatar_url = :avatar_url,
                 cl_sccharacter_description = :description,
                 cl_sccharacter_notes = :notes,
                 cl_sccharacter_share_enabled = :share_enabled,
                 cl_sccharacter_is_pinned = :is_pinned
             WHERE cl_sccharacter_id = :id
               AND cl_sccharacter_owner_auth_id = :owner_auth_id'
        );
        $stmt->execute([
            'name' => $name,
            'role' => $role,
            'faction' => $faction,
            'org_rsi_url' => $org_rsi_url,
            'player_handle' => $player_handle,
            'avatar_url' => $avatar_url,
            'description' => $description !== '' ? $description : null,
            'notes' => $notes !== '' ? $notes : null,
            'share_enabled' => $share_enabled,
            'is_pinned' => $is_pinned,
            'id' => $character_id,
            'owner_auth_id' => $current_owner_auth_id,
        ]);

        $current_item_rows = sccharacters_fetch_owned_character_item_rows($db, $current_owner_auth_id, $character_id);
        $grouped_item_ids = sccharacters_group_item_ids_by_category($current_item_rows);
        $current_visible_category_keys = array_keys(
            sccharacters_sort_items_by_category_order($grouped_item_ids, sccharacters_character_category_order($character))
        );

        $submitted_visible_category_order = $current_visible_category_keys;
        if ($posted_category_order_state !== '') {
            $candidate_category_order = array_values(array_filter(
                array_map('sccharacters_clean_text', preg_split('/\s*,\s*/', $posted_category_order_state, -1, PREG_SPLIT_NO_EMPTY) ?: []),
                static fn (string $category_key): bool => $category_key !== ''
            ));

            if ($candidate_category_order !== []) {
                $candidate_sorted = $candidate_category_order;
                $current_sorted = $current_visible_category_keys;
                sort($candidate_sorted);
                sort($current_sorted);

                if ($candidate_sorted === $current_sorted) {
                    $submitted_visible_category_order = $candidate_category_order;
                }
            }
        }

        $submitted_item_order_state = [];
        if ($posted_item_order_state_raw !== '') {
            $decoded_item_order_state = json_decode($posted_item_order_state_raw, true);
            if (is_array($decoded_item_order_state)) {
                $submitted_item_order_state = $decoded_item_order_state;
            }
        }

        foreach ($grouped_item_ids as $category_key => $current_category_item_ids) {
            $current_category_item_ids = array_values(array_map('intval', $current_category_item_ids));
            $candidate_category_item_ids = $submitted_item_order_state[$category_key] ?? null;
            if (!is_array($candidate_category_item_ids)) {
                $grouped_item_ids[$category_key] = $current_category_item_ids;
                continue;
            }

            $candidate_category_item_ids = array_values(array_filter(
                array_map('intval', $candidate_category_item_ids),
                static fn (int $item_id): bool => $item_id > 0
            ));

            $sorted_candidate_item_ids = $candidate_category_item_ids;
            $sorted_current_category_item_ids = $current_category_item_ids;
            sort($sorted_candidate_item_ids);
            sort($sorted_current_category_item_ids);

            if ($candidate_category_item_ids !== [] && $sorted_candidate_item_ids === $sorted_current_category_item_ids) {
                $grouped_item_ids[$category_key] = $candidate_category_item_ids;
            } else {
                $grouped_item_ids[$category_key] = $current_category_item_ids;
            }
        }

        $persisted_category_order = sccharacters_character_category_order($character);
        $visible_category_lookup = array_fill_keys(array_keys($grouped_item_ids), true);
        $visible_pointer = 0;
        $rebuilt_category_order = [];
        foreach ($persisted_category_order as $ordered_category_key) {
            if (isset($visible_category_lookup[$ordered_category_key])) {
                $rebuilt_category_order[] = $submitted_visible_category_order[$visible_pointer] ?? $ordered_category_key;
                $visible_pointer++;
            } else {
                $rebuilt_category_order[] = $ordered_category_key;
            }
        }

        sccharacters_save_character_category_order($db, $character_id, $rebuilt_category_order);
        sccharacters_save_character_item_order(
            $db,
            $character_id,
            sccharacters_flatten_grouped_item_ids($grouped_item_ids, $rebuilt_category_order)
        );

        auth_flash_set('success', 'Personnage mis à jour.');
        header('Location: sccharacters.php?character=' . $character_id);
        exit;
    }

    if ($action === 'delete_character') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $character = sccharacters_find_owned_character($db, $character_id, $current_owner_auth_id);

        if (!$character) {
            auth_flash_set('error', 'Personnage introuvable.');
            header('Location: sccharacters.php');
            exit;
        }

        $stmt = $db->prepare(
            'DELETE FROM tbl_sccharacters
             WHERE cl_sccharacter_id = :id
               AND cl_sccharacter_owner_auth_id = :owner_auth_id'
        );
        $stmt->execute([
            'id' => $character_id,
            'owner_auth_id' => $current_owner_auth_id,
        ]);

        auth_flash_set('success', 'Personnage supprimé.');
        header('Location: sccharacters.php');
        exit;
    }

    if ($action === 'regenerate_share_token') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $character = sccharacters_find_owned_character($db, $character_id, $current_owner_auth_id);

        if (!$character) {
            auth_flash_set('error', 'Personnage introuvable.');
            header('Location: sccharacters.php');
            exit;
        }

        $stmt = $db->prepare(
            'UPDATE tbl_sccharacters
             SET cl_sccharacter_share_token = :token
             WHERE cl_sccharacter_id = :id
               AND cl_sccharacter_owner_auth_id = :owner_auth_id'
        );
        $stmt->execute([
            'token' => sccharacters_generate_share_token($db),
            'id' => $character_id,
            'owner_auth_id' => $current_owner_auth_id,
        ]);

        auth_flash_set('success', 'Lien public régénéré.');
        header('Location: sccharacters.php?character=' . $character_id);
        exit;
    }

    if ($action === 'add_base_item') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $obj_id = (int) ($_POST['base_obj_id'] ?? 0);
        $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
        $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
        $note = sccharacters_clean_text($_POST['item_note'] ?? '');
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $error_message = null;

        if (!sccharacters_attach_item(
            $db,
            $current_owner_auth_id,
            $character_id,
            'base',
            $obj_id,
            $requested_category,
            $quantity,
            $note,
            $error_message
        )) {
            auth_flash_set('error', $error_message ?? 'Impossible d’ajouter l’objet.');
            header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
            exit;
        }

        auth_flash_set('success', 'Objet de la base ajouté au personnage.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
        exit;
    }

    if ($action === 'add_custom_item') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $itemcustom_id = (int) ($_POST['custom_item_id'] ?? 0);
        $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
        $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
        $note = sccharacters_clean_text($_POST['item_note'] ?? '');
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'custom');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $error_message = null;

        if (!sccharacters_attach_item(
            $db,
            $current_owner_auth_id,
            $character_id,
            'custom',
            $itemcustom_id,
            $requested_category,
            $quantity,
            $note,
            $error_message
        )) {
            auth_flash_set('error', $error_message ?? 'Impossible d’ajouter l’objet.');
            header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
            exit;
        }

        auth_flash_set('success', 'Objet personnalisé ajouté au personnage.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
        exit;
    }

    if ($action === 'update_character_item') {
        $character_item_id = (int) ($_POST['character_item_id'] ?? 0);
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
        $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
        $note = sccharacters_clean_text($_POST['item_note'] ?? '');
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';
        $error_message = null;

        if (!sccharacters_update_character_item(
            $db,
            $current_owner_auth_id,
            $character_id,
            $character_item_id,
            $requested_category,
            $quantity,
            $note,
            $error_message
        )) {
            auth_flash_set('error', $error_message ?? 'Impossible de mettre à jour cet objet.');
            header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
            exit;
        }

        auth_flash_set('success', 'Objet mis à jour.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
        exit;
    }

    if ($action === 'move_character_category') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $category_key = sccharacters_clean_text($_POST['category_key'] ?? '');
        $move_direction = sccharacters_clean_text($_POST['move_direction'] ?? '');
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';

        if (!sccharacters_move_owned_character_category($db, $current_owner_auth_id, $character_id, $category_key, $move_direction)) {
            auth_flash_set('error', 'Impossible de déplacer cette catégorie.');
            header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
            exit;
        }

        auth_flash_set('success', 'Ordre des catégories mis à jour.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
        exit;
    }

    if ($action === 'reorder_character_items') {
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $category_key = sccharacters_clean_text($_POST['category_key'] ?? '');
        $ordered_item_ids = preg_split('/\s*,\s*/', (string) ($_POST['ordered_item_ids'] ?? ''), -1, PREG_SPLIT_NO_EMPTY) ?: [];
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';

        if (!sccharacters_reorder_owned_character_items($db, $current_owner_auth_id, $character_id, $category_key, $ordered_item_ids)) {
            auth_flash_set('error', 'Impossible de réordonner les objets.');
            header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
            exit;
        }

        auth_flash_set('success', 'Ordre des objets mis à jour.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
        exit;
    }

    if ($action === 'delete_character_item') {
        $character_item_id = (int) ($_POST['character_item_id'] ?? 0);
        $character_id = (int) ($_POST['character_id'] ?? 0);
        $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
        $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
        $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
        $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
        $item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';

        $stmt = $db->prepare(
            'DELETE ci
             FROM tbl_sccharacteritems ci
             INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
             WHERE ci.cl_sccharacteritem_id = :character_item_id
               AND c.cl_sccharacter_id = :character_id
               AND c.cl_sccharacter_owner_auth_id = :owner_auth_id'
        );
        $stmt->execute([
            'character_item_id' => $character_item_id,
            'character_id' => $character_id,
            'owner_auth_id' => $current_owner_auth_id,
        ]);

        sccharacters_reindex_character_items($db, $character_id);

        auth_flash_set('success', 'Objet retiré du personnage.');
        header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
        exit;
    }
}

$stmt_characters = $db->prepare(
    'SELECT c.*, COUNT(ci.cl_sccharacteritem_id) AS cl_sccharacter_item_count
     FROM tbl_sccharacters c
     LEFT JOIN tbl_sccharacteritems ci ON ci.cl_sccharacteritem_character_id = c.cl_sccharacter_id
     WHERE c.cl_sccharacter_owner_auth_id = :owner_auth_id
     GROUP BY c.cl_sccharacter_id
     ORDER BY c.cl_sccharacter_is_pinned DESC, c.cl_sccharacter_updated_at DESC, c.cl_sccharacter_name ASC'
);
$stmt_characters->execute(['owner_auth_id' => $current_owner_auth_id]);
$characters = $stmt_characters->fetchAll();

$character_lookup = [];
foreach ($characters as $character_row) {
    $character_lookup[(int) $character_row['cl_sccharacter_id']] = $character_row;
}

$mode = (string) ($_GET['mode'] ?? '');
$selected_character_id = (int) ($_GET['character'] ?? 0);
$selected_character = null;

if ($selected_character_id > 0 && isset($character_lookup[$selected_character_id])) {
    $selected_character = $character_lookup[$selected_character_id];
} elseif ($characters !== []) {
    $selected_character = $characters[0];
    $selected_character_id = (int) $selected_character['cl_sccharacter_id'];
}

$create_panel_open = ($mode === 'create') || ($characters === []);
$item_source = sccharacters_clean_text($_GET['item_source'] ?? 'base');
if (!in_array($item_source, ['base', 'custom'], true)) {
    $item_source = 'base';
}

$item_search = sccharacters_clean_text($_GET['item_search'] ?? '');
$item_panel_open = (string) ($_GET['item_panel'] ?? '') === '1';
$item_page = max(1, (int) ($_GET['item_page'] ?? 1));
$item_per_page = sccharacters_normalize_item_per_page($_GET['item_per_page'] ?? 50);
$item_results = [];
$item_result_custom_stats = [];
$item_total_results = 0;
$item_total_pages = 1;
$item_result_offset_start = 0;
$item_result_offset_end = 0;

if ($selected_character) {
    if ($item_source === 'custom') {
        $count_sql = "SELECT COUNT(DISTINCT c.cl_scitemcustom_id)
                      FROM tbl_scitemcustom c
                      INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
                      WHERE c.cl_scitemcustom_owner_auth_id = :owner_auth_id";
        $params = ['owner_auth_id' => $current_owner_auth_id];

        if ($item_search !== '') {
            $count_sql .= " AND (
                o.cl_scobjs_name LIKE :search
                OR o.cl_scobjs_type LIKE :search
                OR o.cl_scobjs_subtype LIKE :search
                OR o.cl_scobjs_uuid LIKE :search
            )";
            $params['search'] = '%' . $item_search . '%';
        }

        $stmt_item_count = $db->prepare($count_sql);
        $stmt_item_count->execute($params);
        $item_total_results = (int) $stmt_item_count->fetchColumn();
        $item_total_pages = max(1, (int) ceil($item_total_results / $item_per_page));
        $item_page = min($item_page, $item_total_pages);
        $item_offset = max(0, ($item_page - 1) * $item_per_page);

        $sql = "SELECT c.cl_scitemcustom_id,
                       o.cl_scobjs_name,
                       o.cl_scobjs_type,
                       o.cl_scobjs_subtype,
                       o.cl_scobjs_uuid,
                       COUNT(cs.cl_scitemcustomstat_id) AS cl_scitemcustom_stat_count
                FROM tbl_scitemcustom c
                INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
                LEFT JOIN tbl_scitemcustomstat cs ON cs.cl_scitemcustomstat_itemcustom_id = c.cl_scitemcustom_id
                WHERE c.cl_scitemcustom_owner_auth_id = :owner_auth_id";

        if ($item_search !== '') {
            $sql .= " AND (
                o.cl_scobjs_name LIKE :search
                OR o.cl_scobjs_type LIKE :search
                OR o.cl_scobjs_subtype LIKE :search
                OR o.cl_scobjs_uuid LIKE :search
            )";
        }

        $sql .= "
            GROUP BY c.cl_scitemcustom_id
            ORDER BY o.cl_scobjs_name ASC, c.cl_scitemcustom_id ASC
            LIMIT " . (int) $item_per_page . " OFFSET " . (int) $item_offset;

        $stmt_item_results = $db->prepare($sql);
        $stmt_item_results->execute($params);
        $item_results = $stmt_item_results->fetchAll();

        $item_result_custom_ids = [];
        foreach ($item_results as $item_result_row) {
            $itemcustom_id = (int) ($item_result_row['cl_scitemcustom_id'] ?? 0);
            if ($itemcustom_id > 0) {
                $item_result_custom_ids[] = $itemcustom_id;
            }
        }
        $item_result_custom_ids = array_values(array_unique($item_result_custom_ids));

        if ($item_result_custom_ids !== []) {
            $placeholders = implode(',', array_fill(0, count($item_result_custom_ids), '?'));
            $stmt_item_stats = $db->prepare(
                "SELECT
                    cs.cl_scitemcustomstat_itemcustom_id,
                    st.cl_scstatsitem_name,
                    st.cl_scstatsitem_unit,
                    cs.cl_scitemcustomstat_sign,
                    cs.cl_scitemcustomstat_value
                 FROM tbl_scitemcustomstat cs
                 INNER JOIN tbl_scstatsitem st ON st.cl_scstatsitem_id = cs.cl_scitemcustomstat_stat_id
                 WHERE cs.cl_scitemcustomstat_itemcustom_id IN ({$placeholders})
                 ORDER BY st.cl_scstatsitem_name ASC, cs.cl_scitemcustomstat_id ASC"
            );
            $stmt_item_stats->execute($item_result_custom_ids);

            foreach ($stmt_item_stats->fetchAll() as $item_stat_row) {
                $itemcustom_id = (int) ($item_stat_row['cl_scitemcustomstat_itemcustom_id'] ?? 0);
                if (!isset($item_result_custom_stats[$itemcustom_id])) {
                    $item_result_custom_stats[$itemcustom_id] = [];
                }
                $item_result_custom_stats[$itemcustom_id][] = $item_stat_row;
            }
        }
    } else {
        $count_sql = "SELECT COUNT(*)
                      FROM tbl_scobjs
                      WHERE 1 = 1";
        $params = [];

        if ($item_search !== '') {
            $count_sql .= " AND (
                cl_scobjs_name LIKE :search
                OR cl_scobjs_type LIKE :search
                OR cl_scobjs_subtype LIKE :search
                OR cl_scobjs_uuid LIKE :search
            )";
            $params['search'] = '%' . $item_search . '%';
        }

        $stmt_item_count = $db->prepare($count_sql);
        $stmt_item_count->execute($params);
        $item_total_results = (int) $stmt_item_count->fetchColumn();
        $item_total_pages = max(1, (int) ceil($item_total_results / $item_per_page));
        $item_page = min($item_page, $item_total_pages);
        $item_offset = max(0, ($item_page - 1) * $item_per_page);

        $sql = "SELECT cl_scobjs_id, cl_scobjs_name, cl_scobjs_type, cl_scobjs_subtype, cl_scobjs_uuid
                FROM tbl_scobjs
                WHERE 1 = 1";

        if ($item_search !== '') {
            $sql .= " AND (
                cl_scobjs_name LIKE :search
                OR cl_scobjs_type LIKE :search
                OR cl_scobjs_subtype LIKE :search
                OR cl_scobjs_uuid LIKE :search
            )";
        }

        $sql .= "
            ORDER BY cl_scobjs_name ASC
            LIMIT " . (int) $item_per_page . " OFFSET " . (int) $item_offset;

        $stmt_item_results = $db->prepare($sql);
        $stmt_item_results->execute($params);
        $item_results = $stmt_item_results->fetchAll();
    }

    if ($item_total_results > 0) {
        $item_result_offset_start = (($item_page - 1) * $item_per_page) + 1;
        $item_result_offset_end = min($item_total_results, $item_result_offset_start + count($item_results) - 1);
    }

}

$selected_character_items = [];
$custom_stats_by_itemcustom = [];
if ($selected_character) {
    sccharacters_reindex_character_items($db, (int) $selected_character['cl_sccharacter_id']);

    $stmt_character_items = $db->prepare(
        "SELECT
            ci.*,
            bo.cl_scobjs_name AS cl_sccharacteritem_base_name,
            bo.cl_scobjs_type AS cl_sccharacteritem_base_type,
            bo.cl_scobjs_subtype AS cl_sccharacteritem_base_subtype,
            bo.cl_scobjs_uuid AS cl_sccharacteritem_base_uuid,
            co.cl_scitemcustom_id AS cl_sccharacteritem_custom_ref_id,
            oo.cl_scobjs_name AS cl_sccharacteritem_custom_name,
            oo.cl_scobjs_type AS cl_sccharacteritem_custom_type,
            oo.cl_scobjs_subtype AS cl_sccharacteritem_custom_subtype,
            oo.cl_scobjs_uuid AS cl_sccharacteritem_custom_uuid
         FROM tbl_sccharacteritems ci
         LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = ci.cl_sccharacteritem_scobjs_id
         LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
         LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
         WHERE ci.cl_sccharacteritem_character_id = :character_id
         ORDER BY ci.cl_sccharacteritem_sort_order ASC, ci.cl_sccharacteritem_id ASC"
    );
    $stmt_character_items->execute(['character_id' => (int) $selected_character['cl_sccharacter_id']]);
    $selected_character_items = $stmt_character_items->fetchAll();

    $custom_item_ids = [];
    foreach ($selected_character_items as $character_item_row) {
        if (($character_item_row['cl_sccharacteritem_source'] ?? '') === 'custom' && !empty($character_item_row['cl_sccharacteritem_scitemcustom_id'])) {
            $custom_item_ids[] = (int) $character_item_row['cl_sccharacteritem_scitemcustom_id'];
        }
    }
    $custom_item_ids = array_values(array_unique(array_filter($custom_item_ids)));

    if ($custom_item_ids !== []) {
        $placeholders = implode(',', array_fill(0, count($custom_item_ids), '?'));
        $stmt_custom_stats = $db->prepare(
            "SELECT
                cs.cl_scitemcustomstat_itemcustom_id,
                st.cl_scstatsitem_name,
                st.cl_scstatsitem_unit,
                cs.cl_scitemcustomstat_sign,
                cs.cl_scitemcustomstat_value
             FROM tbl_scitemcustomstat cs
             INNER JOIN tbl_scstatsitem st ON st.cl_scstatsitem_id = cs.cl_scitemcustomstat_stat_id
             WHERE cs.cl_scitemcustomstat_itemcustom_id IN ({$placeholders})
             ORDER BY st.cl_scstatsitem_name ASC, cs.cl_scitemcustomstat_id ASC"
        );
        $stmt_custom_stats->execute($custom_item_ids);

        foreach ($stmt_custom_stats->fetchAll() as $custom_stat_row) {
            $itemcustom_id = (int) $custom_stat_row['cl_scitemcustomstat_itemcustom_id'];
            if (!isset($custom_stats_by_itemcustom[$itemcustom_id])) {
                $custom_stats_by_itemcustom[$itemcustom_id] = [];
            }
            $custom_stats_by_itemcustom[$itemcustom_id][] = $custom_stat_row;
        }
    }
}

$item_category_options = sccharacters_item_category_options();
$selected_character_category_order = $selected_character
    ? sccharacters_character_category_order($selected_character)
    : sccharacters_default_category_order();
$selected_character_items_by_category = [];
foreach ($selected_character_items as $character_item_row) {
    $is_custom = ($character_item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
    $item_type = $is_custom
        ? (string) ($character_item_row['cl_sccharacteritem_custom_type'] ?? '')
        : (string) ($character_item_row['cl_sccharacteritem_base_type'] ?? '');
    $item_subtype = $is_custom
        ? (string) ($character_item_row['cl_sccharacteritem_custom_subtype'] ?? '')
        : (string) ($character_item_row['cl_sccharacteritem_base_subtype'] ?? '');
    $category_key = sccharacters_resolve_item_category(
        (string) ($character_item_row['cl_sccharacteritem_slot'] ?? ''),
        $item_type,
        $item_subtype
    );
    if (!isset($selected_character_items_by_category[$category_key])) {
        $selected_character_items_by_category[$category_key] = [];
    }
    $selected_character_items_by_category[$category_key][] = $character_item_row;
}
$selected_character_items_by_category = sccharacters_sort_items_by_category_order(
    $selected_character_items_by_category,
    $selected_character_category_order
);
$selected_character_category_order_meta = [];
$visible_category_keys = array_keys($selected_character_items_by_category);
$visible_category_count = count($visible_category_keys);
foreach ($visible_category_keys as $visible_category_index => $visible_category_key) {
    $selected_character_category_order_meta[$visible_category_key] = [
        'is_first' => $visible_category_index === 0,
        'is_last' => $visible_category_index === ($visible_category_count - 1),
    ];
}
$selected_character_visible_category_order_state = implode(',', $visible_category_keys);
$selected_character_item_order_state = [];
foreach ($selected_character_items_by_category as $category_key => $category_items) {
    $selected_character_item_order_state[$category_key] = array_values(array_map(
        static fn (array $item_row): int => (int) ($item_row['cl_sccharacteritem_id'] ?? 0),
        $category_items
    ));
}
$selected_character_item_order_state_json = json_encode(
    $selected_character_item_order_state,
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
if (!is_string($selected_character_item_order_state_json)) {
    $selected_character_item_order_state_json = '{}';
}
$create_character = [
    'cl_sccharacter_name' => '',
    'cl_sccharacter_role' => '',
    'cl_sccharacter_faction' => '',
    'cl_sccharacter_org_rsi_url' => '',
    'cl_sccharacter_player_handle' => '',
    'cl_sccharacter_avatar_url' => '',
    'cl_sccharacter_description' => '',
    'cl_sccharacter_notes' => '',
    'cl_sccharacter_share_enabled' => 0,
    'cl_sccharacter_is_pinned' => 0,
];
$selected_character_org_tag = $selected_character ? sccharacters_resolve_org_tag($selected_character) : '';
$selected_character_has_player_handle = $selected_character ? sccharacters_has_player_handle($selected_character) : false;
$item_has_previous_page = $item_page > 1;
$item_has_next_page = $item_page < $item_total_pages;
$item_query_base_params = [];
if ($selected_character) {
    $item_query_base_params = [
        'character' => (int) $selected_character['cl_sccharacter_id'],
        'item_panel' => 1,
        'item_source' => $item_source,
    ];

    if ($item_search !== '') {
        $item_query_base_params['item_search'] = $item_search;
    }

    if ($item_per_page !== 50) {
        $item_query_base_params['item_per_page'] = $item_per_page;
    }
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PERSONNAGES | R.E.A.C.T. Admin</title>
    <link rel="stylesheet" type="text/css" href="css/styles.css">
    <link rel="stylesheet" type="text/css" href="css/default.css">
    <style>
        :root {
            --primary: #a29b78;
            --primary-soft: rgba(162, 155, 120, 0.18);
            --primary-border: rgba(162, 155, 120, 0.34);
            --bg-dark: #080a0f;
            --card-bg: rgba(16, 20, 29, 0.86);
            --card-bg-strong: rgba(20, 25, 37, 0.95);
            --text-main: #ece9df;
            --text-soft: rgba(236, 233, 223, 0.74);
            --danger: #ff6b6b;
            --success: #49d17d;
        }

        @font-face {
            font-family: 'Electrolize';
            src: url('fonts/Electrolize-Regular.ttf') format('truetype');
        }

        * { box-sizing: border-box; }

        body {
            margin: 0;
            min-height: 100vh;
            background: radial-gradient(circle at top right, #1d2234 0%, #0a0d13 55%, #050608 100%);
            color: var(--text-main);
            font-family: 'Electrolize', sans-serif;
        }

        .admin-layout {
            display: flex;
            flex-direction: column;
            max-width: 1480px;
            margin: 0 auto;
            padding: 2rem;
            gap: 1.5rem;
        }

        .admin-topbar,
        .panel,
        .character-card,
        .equip-card,
        .search-result,
        .empty-state {
            background: var(--card-bg);
            border: 1px solid var(--primary-border);
            border-radius: 18px;
            box-shadow: 0 18px 45px rgba(0, 0, 0, 0.28);
            backdrop-filter: blur(10px);
        }
        .admin-topbar {
            padding: 1.5rem 2rem;
            display: flex;
            gap: 1rem;
            justify-content: space-between;
            align-items: center;
            flex-wrap: wrap;
        }

        .topbar-info h1 {
            margin: 0;
            font-size: 1.5rem;
            letter-spacing: 2px;
            text-transform: uppercase;
            background: linear-gradient(90deg, #fff, var(--primary));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }

        .topbar-info p {
            margin: 0.25rem 0 0;
            font-size: 0.85rem;
            color: var(--primary);
            opacity: 0.8;
        }

        .topbar-actions {
            display: flex;
            gap: 1rem;
            flex-wrap: wrap;
            align-items: center;
        }

        .session-user {
            opacity: 0.85;
        }

        .btn-modern {
            padding: 0.65rem 1.2rem;
            border: 1px solid var(--primary-border);
            background: rgba(255, 255, 255, 0.02);
            color: #fff;
            font-family: 'Electrolize', sans-serif;
            font-size: 0.88rem;
            text-transform: uppercase;
            cursor: pointer;
            transition: all 0.25s ease;
            border-radius: 10px;
            text-decoration: none;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 0.4rem;
            min-height: 44px;
        }

        .btn-modern:hover {
            background: rgba(106, 208, 255, 0.16);
            border-color: rgba(106, 208, 255, 0.65);
            box-shadow: 0 0 16px rgba(106, 208, 255, 0.18);
            transform: translateY(-1px);
        }

        .btn-modern.danger {
            border-color: rgba(255, 123, 123, 0.35);
            color: #ffb3b3;
        }

        .btn-modern.danger:hover {
            background: rgba(255, 107, 107, 0.16);
            border-color: rgba(255, 107, 107, 0.6);
            box-shadow: 0 0 16px rgba(255, 107, 107, 0.2);
        }

        .flash {
            padding: 1rem 1.1rem;
            border-radius: 14px;
            border: 1px solid transparent;
            font-size: 0.95rem;
        }

        .flash.success { background: rgba(73, 209, 125, 0.14); border-color: rgba(73, 209, 125, 0.3); color: #d6ffe4; }
        .flash.error { background: rgba(255, 107, 107, 0.12); border-color: rgba(255, 107, 107, 0.28); color: #ffd7d7; }

        .main-grid {
            display: grid;
            grid-template-columns: 390px minmax(0, 1fr);
            gap: 1.5rem;
            align-items: start;
        }

        .sidebar-column,
        .right-column {
            display: flex;
            flex-direction: column;
            gap: 1.2rem;
        }

        .panel { padding: 1.3rem; }

        .panel-soft {
            background: rgba(255,255,255,0.03);
            border: 1px solid rgba(255,255,255,0.08);
            border-radius: 16px;
        }

        .panel-title {
            margin: 0 0 0.35rem;
            font-size: 1.05rem;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--primary);
        }

        .panel-subtitle {
            margin: 0;
            color: var(--text-soft);
            font-size: 0.9rem;
            line-height: 1.45;
        }

        .list-panel {
            padding-bottom: 1rem;
        }

        .list-panel-header {
            display: flex;
            justify-content: space-between;
            gap: 1rem;
            align-items: flex-start;
            margin-bottom: 1rem;
        }

        .accordion-panel {
            padding: 0;
            overflow: hidden;
        }

        .accordion-summary {
            list-style: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 1rem;
            padding: 1.15rem 1.3rem;
            cursor: pointer;
        }

        .accordion-summary::-webkit-details-marker { display: none; }
        .accordion-panel[open] .accordion-summary {
            border-bottom: 1px solid rgba(255,255,255,0.08);
            background: rgba(255,255,255,0.02);
        }

        .accordion-indicator {
            width: 34px;
            height: 34px;
            border-radius: 999px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.08);
            color: var(--primary);
            flex: 0 0 34px;
            transition: transform 0.2s ease;
        }

        .accordion-panel[open] .accordion-indicator {
            transform: rotate(45deg);
        }

        .accordion-body {
            padding: 1.25rem 1.3rem 1.3rem;
            display: flex;
            flex-direction: column;
            gap: 1rem;
        }

        .form-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 0.9rem;
        }

        .field,
        .field-full { display: flex; flex-direction: column; gap: 0.45rem; }
        .field-full { grid-column: 1 / -1; }

        label {
            font-size: 0.78rem;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--text-soft);
        }

        input[type="text"],
        input[type="url"],
        textarea,
        select {
            width: 100%;
            border: 1px solid rgba(255,255,255,0.09);
            background: rgba(7, 10, 16, 0.72);
            color: var(--text-main);
            border-radius: 12px;
            padding: 0.82rem 0.9rem;
            font-family: inherit;
            font-size: 0.95rem;
            outline: none;
            transition: border-color 0.2s ease, box-shadow 0.2s ease;
        }

        input:focus,
        textarea:focus,
        select:focus {
            border-color: var(--primary);
            box-shadow: 0 0 0 3px rgba(162, 155, 120, 0.13);
        }

        textarea { min-height: 110px; resize: vertical; }

        .checkbox-row {
            display: flex;
            align-items: center;
            gap: 0.7rem;
            padding: 0.85rem 0.95rem;
            border-radius: 12px;
            background: rgba(255,255,255,0.03);
            border: 1px solid rgba(255,255,255,0.06);
        }

        .checkbox-row input[type="checkbox"] {
            width: 18px;
            height: 18px;
            margin: 0;
        }

        .checkbox-row label {
            text-transform: none;
            letter-spacing: 0;
            font-size: 0.92rem;
            color: var(--text-main);
            cursor: pointer;
        }

        .btn-row {
            display: flex;
            gap: 0.75rem;
            flex-wrap: wrap;
            margin-top: 1rem;
        }

        .btn,
        .btn-link {
            appearance: none;
            border: 0;
            border-radius: 12px;
            padding: 0.85rem 1rem;
            font-family: inherit;
            font-size: 0.92rem;
            text-decoration: none;
            cursor: pointer;
            transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 0.45rem;
        }

        .btn:hover,
        .btn-link:hover {
            transform: translateY(-1px);
            box-shadow: 0 12px 24px rgba(0,0,0,0.22);
        }

        .btn-small,
        .btn-link.btn-small {
            padding: 0.68rem 0.85rem;
            font-size: 0.85rem;
        }

        .btn-primary { background: linear-gradient(135deg, #d2c6a0, #93875f); color: #0d1017; }
        .btn-secondary { background: rgba(255,255,255,0.07); color: var(--text-main); border: 1px solid rgba(255,255,255,0.08); }
        .btn-danger { background: rgba(255, 107, 107, 0.14); color: #ffe7e7; border: 1px solid rgba(255, 107, 107, 0.28); }

        .characters-stack {
            display: flex;
            flex-direction: column;
            gap: 0.8rem;
            max-height: calc(100vh - 360px);
            overflow: auto;
            padding-right: 0.15rem;
        }

        .character-card {
            display: grid;
            grid-template-columns: 56px minmax(0, 1fr);
            gap: 0.85rem;
            padding: 0.85rem;
            color: inherit;
            text-decoration: none;
            border-color: rgba(255,255,255,0.08);
            transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
        }

        .character-card:hover {
            transform: translateY(-1px);
            border-color: rgba(162, 155, 120, 0.45);
            background: rgba(24, 30, 42, 0.94);
        }

        .character-card.is-active {
            border-color: rgba(162, 155, 120, 0.6);
            background: rgba(27, 32, 45, 0.96);
            box-shadow: 0 0 0 1px rgba(162, 155, 120, 0.18), 0 18px 45px rgba(0, 0, 0, 0.28);
        }

        .character-avatar,
        .character-avatar-fallback {
            width: 56px;
            height: 56px;
            border-radius: 16px;
            object-fit: cover;
            background: linear-gradient(145deg, rgba(162, 155, 120, 0.3), rgba(255,255,255,0.08));
            border: 1px solid rgba(255,255,255,0.1);
        }

        .character-avatar-fallback,
        .character-hero-fallback,
        .equip-thumb-fallback {
            display: flex;
            align-items: center;
            justify-content: center;
            color: var(--primary);
        }

        .character-card-body,
        .equip-content { min-width: 0; }

        .character-card-body h3,
        .equip-title,
        .character-hero-name {
            margin: 0;
        }

        .character-card-title,
        .hero-name-row {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            min-width: 0;
        }

        .character-card-body h3 {
            font-size: 0.98rem;
            line-height: 1.25;
        }

        .pin-indicator {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 1.8rem;
            height: 1.8rem;
            border-radius: 999px;
            border: 1px solid rgba(162, 155, 120, 0.34);
            background: rgba(162, 155, 120, 0.14);
            color: #f8f3e1;
            font-size: 0.95rem;
            line-height: 1;
            flex: 0 0 auto;
        }

        .pin-indicator-input {
            width: 2rem;
            height: 2rem;
            border-radius: 999px;
            border: 1px solid rgba(162, 155, 120, 0.25);
            background: rgba(162, 155, 120, 0.1);
            color: #f8f3e1;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-size: 1rem;
            line-height: 1;
            flex: 0 0 auto;
        }

        .muted {
            color: var(--text-soft);
            font-size: 0.88rem;
            line-height: 1.45;
        }

        .badge-row,
        .hero-meta,
        .equip-meta {
            display: flex;
            gap: 0.45rem;
            flex-wrap: wrap;
        }

        .hero-meta-secondary {
            margin-top: 0.7rem;
        }

        .identity-grid {
            display: grid;
            grid-template-columns: repeat(3, minmax(0, 1fr));
            gap: 0.7rem;
        }

        .identity-item {
            display: flex;
            flex-direction: column;
            gap: 0.22rem;
            padding: 0.72rem 0.82rem;
            border-radius: 14px;
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.1);
        }

        .identity-label {
            font-size: 0.7rem;
            letter-spacing: 0.09em;
            text-transform: uppercase;
            color: var(--text-soft);
        }

        .identity-value {
            font-size: 0.95rem;
            font-weight: 600;
            color: #f6f7fb;
            line-height: 1.35;
            word-break: break-word;
        }

        .badge {
            display: inline-flex;
            align-items: center;
            gap: 0.3rem;
            padding: 0.32rem 0.56rem;
            border-radius: 999px;
            background: rgba(255,255,255,0.06);
            border: 1px solid rgba(255,255,255,0.08);
            font-size: 0.77rem;
            color: #f2f2f2;
        }

        .badge-primary {
            background: rgba(162, 155, 120, 0.18);
            border-color: rgba(162, 155, 120, 0.34);
            color: #f8f3e1;
        }

        .badge-muted { color: var(--text-soft); }

        .badge-success {
            background: rgba(73, 209, 125, 0.12);
            border-color: rgba(73, 209, 125, 0.3);
            color: #d6ffe4;
        }

        .character-hero {
            display: grid;
            grid-template-columns: 110px minmax(0, 1fr);
            gap: 1.2rem;
            align-items: start;
        }

        .character-hero-avatar,
        .character-hero-fallback {
            width: 110px;
            height: 110px;
            border-radius: 24px;
            object-fit: cover;
            background: linear-gradient(145deg, rgba(162, 155, 120, 0.3), rgba(255,255,255,0.08));
            border: 1px solid rgba(255,255,255,0.1);
        }

        .character-hero-fallback {
            font-size: 2rem;
        }

        .character-hero-name {
            font-size: 1.5rem;
            margin-bottom: 0.55rem;
        }

        .hero-header {
            display: flex;
            justify-content: space-between;
            gap: 1rem;
            align-items: flex-start;
            margin-bottom: 0.8rem;
        }

        .share-box {
            margin-top: 1rem;
            padding: 1rem;
            border-radius: 14px;
            background: rgba(255,255,255,0.03);
            border: 1px solid rgba(255,255,255,0.08);
        }

        .share-box input {
            margin-top: 0.65rem;
            font-size: 0.88rem;
        }

        .edit-form-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 0.9rem;
        }

        .equipment-sections {
            display: flex;
            flex-direction: column;
            gap: 1rem;
        }

        .equipment-section {
            display: flex;
            flex-direction: column;
            gap: 0.8rem;
        }

        .equipment-section-heading {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 0.8rem;
            padding-bottom: 0.35rem;
            border-bottom: 1px solid rgba(255,255,255,0.08);
            flex-wrap: wrap;
        }

        .equipment-section-heading-main {
            display: inline-flex;
            align-items: center;
            gap: 0.65rem;
            flex-wrap: wrap;
        }

        .equipment-category-order-form {
            display: inline-flex;
            align-items: center;
            gap: 0.35rem;
        }

        .equipment-section-title {
            margin: 0;
            font-size: 0.92rem;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--primary);
        }

        .equipment-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 1rem;
        }

        .equip-card {
            padding: 1rem;
            display: flex;
            gap: 0.9rem;
            align-items: flex-start;
            cursor: grab;
            transition: opacity 0.18s ease, transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
        }

        .equip-card.dragging {
            opacity: 0.45;
            cursor: grabbing;
        }

        .equip-card.drag-over {
            border-color: rgba(162, 155, 120, 0.55);
            background: rgba(162, 155, 120, 0.09);
        }

        .equip-thumb,
        .equip-thumb-fallback {
            width: 64px;
            height: 64px;
            border-radius: 16px;
            flex: 0 0 64px;
            object-fit: cover;
            background: rgba(255,255,255,0.06);
            border: 1px solid rgba(255,255,255,0.08);
        }

        .equip-thumb-fallback {
            font-size: 1.2rem;
        }

        .equip-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            gap: 0.6rem;
            min-width: 0;
        }

        .equip-title-row {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 0.75rem;
        }

        .drag-handle {
            color: var(--text-soft);
            font-size: 1rem;
            line-height: 1;
            letter-spacing: -0.1em;
            user-select: none;
            flex: 0 0 auto;
        }

        .drag-hint {
            font-size: 0.8rem;
        }

        .equipment-actions {
            margin-top: auto;
            display: flex;
            flex-wrap: wrap;
            gap: 0.75rem;
            align-items: flex-start;
            justify-content: space-between;
        }

        .equipment-action-buttons {
            display: grid;
            grid-template-columns: repeat(2, auto);
            align-items: start;
            gap: 0.55rem;
            justify-content: end;
        }

        .equipment-edit {
            width: auto;
            margin-top: 0;
        }

        .equipment-edit[open] {
            grid-column: 1 / -1;
            width: min(100%, 34rem);
            justify-self: end;
        }

        .equipment-edit-summary,
        .equipment-icon-button {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 2.45rem;
            min-width: 2.45rem;
            height: 2.45rem;
            min-height: 2.45rem;
            padding: 0;
            cursor: pointer;
            list-style: none;
            line-height: 1;
        }

        .equipment-edit-summary::-webkit-details-marker {
            display: none;
        }

        .equipment-edit-form {
            margin-top: 0.85rem;
            padding: 0.95rem;
            border-radius: 14px;
            border: 1px solid rgba(255,255,255,0.08);
            background: rgba(255,255,255,0.04);
            display: grid;
            gap: 0.85rem;
            width: min(100%, 34rem);
        }

        .equipment-edit-grid {
            display: grid;
            grid-template-columns: minmax(110px, 135px) minmax(0, 1fr);
            gap: 0.75rem;
            align-items: start;
        }

        .equipment-edit-grid textarea {
            grid-column: 1 / -1;
            min-height: 96px;
            resize: vertical;
        }

        .item-attach-meta textarea {
            grid-column: 1 / -1;
            min-height: 72px;
            resize: vertical;
        }

        .equipment-edit-form input,
        .equipment-edit-form select,
        .equipment-edit-form textarea,
        .item-attach-meta input,
        .item-attach-meta select,
        .item-attach-meta textarea {
            width: 100%;
        }

        .equipment-edit-form-actions {
            display: flex;
            justify-content: flex-end;
        }

        .equipment-reorder-form {
            display: none;
        }

        .order-btn {
            min-width: 2.2rem;
            padding-inline: 0.55rem;
        }

        .equip-title {
            font-size: 1rem;
            line-height: 1.3;
            margin: 0;
        }

        .equip-stats {
            display: flex;
            gap: 0.55rem;
            flex-wrap: wrap;
            align-items: stretch;
            margin-top: 0.15rem;
            padding: 0;
            border: 0;
            background: transparent;
            box-shadow: none;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
        }

        .equip-stat {
            display: inline-flex;
            align-items: center;
            min-height: 36px;
            padding: 0.48rem 0.78rem;
            border-radius: 12px;
            background: linear-gradient(135deg, rgba(26, 74, 42, 0.9), rgba(18, 46, 28, 0.82));
            border: 1px solid rgba(90, 255, 150, 0.85);
            box-shadow: inset 0 0 0 1px rgba(140, 255, 188, 0.18), 0 0 0 1px rgba(34, 110, 58, 0.28), 0 10px 22px rgba(0,0,0,0.18);
            font-size: 0.8rem;
            font-weight: 700;
            letter-spacing: 0.01em;
            color: #dcffe9;
        }

        .search-toolbar {
            display: flex;
            flex-direction: column;
            gap: 0.85rem;
        }

        .item-search-form {
            display: grid;
            gap: 0.9rem;
        }

        .search-top-row {
            display: flex;
            justify-content: space-between;
            gap: 1rem;
            align-items: center;
            flex-wrap: wrap;
        }

        .search-controls-row {
            display: grid;
            grid-template-columns: minmax(0, 1fr) 170px auto;
            gap: 0.75rem;
            align-items: center;
        }

        .source-switch {
            display: inline-grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            padding: 0.28rem;
            border-radius: 14px;
            background: rgba(255,255,255,0.04);
            border: 1px solid rgba(255,255,255,0.08);
            gap: 0.25rem;
            width: fit-content;
        }

        .source-switch input {
            position: absolute;
            opacity: 0;
            pointer-events: none;
        }

        .source-switch label {
            min-width: 155px;
            min-height: 46px;
            margin: 0;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            padding: 0.7rem 0.9rem;
            border-radius: 10px;
            cursor: pointer;
            font-family: inherit;
            font-size: 0.82rem;
            font-weight: 400;
            line-height: 1.2;
            letter-spacing: 0.05em;
            text-transform: uppercase;
            white-space: nowrap;
            color: var(--text-soft);
            transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
            border: 1px solid transparent;
        }

        .source-switch label:hover {
            color: var(--text-main);
        }

        .source-switch input:checked + label {
            background: rgba(162, 155, 120, 0.16);
            border-color: rgba(162, 155, 120, 0.32);
            color: var(--text-main);
        }

        .search-input-row {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            gap: 0.75rem;
            align-items: center;
        }

        .search-results {
            display: flex;
            flex-direction: column;
            gap: 0.75rem;
            margin-top: 1rem;
        }

        .search-results-summary,
        .pagination-bar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 1rem;
            padding: 0.9rem 1rem;
        }

        .search-result {
            padding: 0.95rem;
            display: grid;
            grid-template-columns: minmax(0, 1fr) 360px;
            gap: 1rem;
            align-items: start;
        }

        body.show-item-preview .search-result {
            grid-template-columns: 96px minmax(0, 1fr) 360px;
        }

        .search-result strong { display: block; margin-bottom: 0.25rem; }

        .search-result-stats {
            display: flex;
            flex-wrap: wrap;
            gap: 0.4rem;
            margin-top: 0.05rem;
        }

        .search-result-stats .equip-stat {
            min-height: 24px;
            padding: 0.2rem 0.55rem;
            border-radius: 999px;
            background: rgba(22, 78, 45, 0.14);
            border: 1px solid rgba(90, 255, 150, 0.42);
            box-shadow: none;
            font-size: 0.68rem;
            font-weight: 600;
            line-height: 1.15;
            color: #d7ffe6;
        }

        .search-result-main {
            min-width: 0;
            display: flex;
            flex-direction: column;
            gap: 0.55rem;
        }

        .search-result-preview {
            display: none;
            align-items: flex-start;
            justify-content: center;
        }

        body.show-item-preview .search-result-preview {
            display: flex;
        }

        .preview-container {
            position: relative;
            width: 80px;
            height: 80px;
            cursor: zoom-in;
        }

        .item-preview,
        .item-preview-fallback {
            width: 80px;
            height: 80px;
            object-fit: cover;
            border-radius: 16px;
            border: 1px solid rgba(255,255,255,0.08);
            background: rgba(0,0,0,0.35);
            display: block;
        }

        .item-preview-fallback {
            display: grid;
            place-items: center;
            font-size: 1.2rem;
            color: var(--text-soft);
        }

        .preview-floating {
            visibility: hidden;
            opacity: 0;
            position: absolute;
            top: -10px;
            left: 92px;
            z-index: 20;
            padding: 5px;
            background: var(--card-bg);
            border: 1px solid rgba(162, 155, 120, 0.4);
            border-radius: 12px;
            box-shadow: 0 14px 32px rgba(0,0,0,0.45);
            backdrop-filter: blur(12px);
            transition: opacity 0.2s ease, visibility 0.2s ease;
            pointer-events: none;
        }

        .preview-floating img {
            width: 260px;
            height: 260px;
            object-fit: contain;
            display: block;
            border-radius: 8px;
        }

        .preview-container:hover .preview-floating,
        .preview-container:focus-within .preview-floating {
            visibility: visible;
            opacity: 1;
        }

        .item-attach-form {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            gap: 0.75rem;
            align-self: stretch;
            align-items: stretch;
        }

        .item-attach-meta {
            display: grid;
            grid-template-columns: minmax(96px, 112px) minmax(0, 1fr);
            gap: 0.55rem;
            align-items: start;
        }

        .item-attach-actions {
            display: flex;
            align-self: stretch;
        }

        .item-add-button {
            min-width: 3rem;
            min-height: 100%;
            height: 100%;
            padding: 0.4rem;
            font-size: 1.55rem;
            line-height: 1;
            font-weight: 700;
            display: inline-flex;
            align-items: center;
            justify-content: center;
        }

        .search-results-summary {
            flex-wrap: wrap;
        }

        .preview-toggle {
            display: inline-flex;
            align-items: center;
            gap: 0.55rem;
            font-size: 0.9rem;
            color: var(--text-main);
            user-select: none;
            cursor: pointer;
        }

        .preview-toggle input {
            width: 1rem;
            height: 1rem;
            margin: 0;
        }

        .search-result-range {
            font-size: 0.88rem;
            color: var(--text-soft);
        }

        .pagination-links {
            display: flex;
            gap: 0.55rem;
            flex-wrap: wrap;
            align-items: center;
        }

        .pagination-label {
            font-size: 0.88rem;
            color: var(--text-soft);
        }

        .empty-state {
            padding: 1.2rem;
            color: var(--text-soft);
            text-align: center;
        }

        .empty-state strong { color: var(--text-main); display: block; margin-bottom: 0.35rem; }

        .nav-tabs {
            display: flex;
            gap: 1rem;
            margin-bottom: 2rem;
            border-bottom: 1px solid var(--primary-border);
            padding-bottom: 1rem;
            flex-wrap: wrap;
        }

        .nav-tabs a {
            text-decoration: none;
            color: #888;
            text-transform: uppercase;
            font-size: 0.9rem;
            transition: color 0.3s;
        }

        .nav-tabs a:hover,
        .nav-tabs a.active {
            color: var(--primary);
        }

        @media (max-width: 1280px) {
            .main-grid {
                grid-template-columns: 340px minmax(0, 1fr);
            }

            .search-results-summary,
            .pagination-bar {
                flex-direction: column;
                align-items: stretch;
            }

            .search-result,
            body.show-item-preview .search-result {
                grid-template-columns: 1fr;
            }

            .search-result-preview {
                justify-content: flex-start;
            }

            .item-attach-form,
            .item-attach-meta,
            .search-controls-row {
                grid-template-columns: 1fr;
            }

            .item-attach-actions {
                justify-content: stretch;
            }

            .item-add-button {
                width: 100%;
                min-height: 2.75rem;
                height: auto;
            }
        }

        @media (max-width: 1180px) {
            .main-grid,
            .equipment-grid,
            .edit-form-grid {
                grid-template-columns: 1fr;
            }

            .characters-stack {
                max-height: none;
            }
        }

        @media (max-width: 720px) {
            .admin-layout { padding: 1rem; }
            .form-grid,
            .character-hero,
            .search-input-row,
            .source-switch {
                grid-template-columns: 1fr;
            }
            .topbar-actions { width: 100%; justify-content: flex-start; }
            .list-panel-header,
            .hero-header {
                flex-direction: column;
                align-items: stretch;
            }
            .source-switch {
                width: 100%;
            }
            .source-switch label {
                min-width: 0;
            }
        }
    </style>
</head>
<body class="sccharacters-page">
    <?php echo auth_render_page_access_widget('sccharacters.php', 'Personnages'); ?>
    <div class="admin-layout">
        <header class="admin-topbar">
            <div class="topbar-info">
                <h1>R.E.A.C.T. Characters Control</h1>
                <p>Niveau d'accès : <strong><?php echo htmlspecialchars($role_label, ENT_QUOTES, 'UTF-8'); ?></strong></p>
            </div>
            <div class="topbar-actions">
                <span class="session-user">Connecté : <strong><?php echo htmlspecialchars($current_session_user, ENT_QUOTES, 'UTF-8'); ?></strong></span>
                <a href="index.php" class="btn-modern">Retour au site</a>
                <a href="logout.php" class="btn-modern danger">Déconnexion</a>
            </div>
        </header>

        <?php echo auth_render_app_nav('sccharacters.php'); ?>

        <?php if ($flash_message !== ''): ?>
            <div class="flash <?php echo $flash_type === 'success' ? 'success' : 'error'; ?>">
                <?php echo htmlspecialchars($flash_message, ENT_QUOTES, 'UTF-8'); ?>
            </div>
        <?php endif; ?>

        <div class="main-grid">
            <aside class="sidebar-column">
                <details class="panel accordion-panel" <?php echo $create_panel_open ? 'open' : ''; ?>>
                    <summary class="accordion-summary">
                        <div>
                            <h2 class="panel-title">Créer un personnage</h2>
                            <p class="panel-subtitle">Le formulaire est replié par défaut pour laisser un maximum de place à ta liste de personnages.</p>
                        </div>
                        <span class="accordion-indicator">+</span>
                    </summary>
                    <div class="accordion-body">
                        <form method="post" id="characterCreateForm">
                            <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                            <input type="hidden" name="action" value="create_character">

                            <div class="form-grid">
                                <div class="field-full">
                                    <label for="newCharacterName">Nom</label>
                                    <input type="text" id="newCharacterName" name="character_name" maxlength="190" required value="<?php echo htmlspecialchars((string) $create_character['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="newCharacterRole">Rôle / Classe</label>
                                    <input type="text" id="newCharacterRole" name="character_role" maxlength="190" value="<?php echo htmlspecialchars((string) $create_character['cl_sccharacter_role'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="newCharacterOrgRsiUrl">Page RSI (URL)</label>
                                    <input type="url" id="newCharacterOrgRsiUrl" name="character_org_rsi_url" placeholder="https://robertsspaceindustries.com/en/orgs/REACT" value="<?php echo htmlspecialchars((string) $create_character['cl_sccharacter_org_rsi_url'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="newCharacterPlayerHandle">Handle</label>
                                    <input type="text" id="newCharacterPlayerHandle" name="character_player_handle" maxlength="190" value="<?php echo htmlspecialchars((string) $create_character['cl_sccharacter_player_handle'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field-full">
                                    <label for="newCharacterAvatar">Avatar (URL d’image)</label>
                                    <input type="url" id="newCharacterAvatar" name="character_avatar_url" placeholder="https://..." value="<?php echo htmlspecialchars((string) $create_character['cl_sccharacter_avatar_url'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field-full">
                                    <label for="newCharacterDescription">Description</label>
                                    <textarea id="newCharacterDescription" name="character_description"><?php echo htmlspecialchars((string) $create_character['cl_sccharacter_description'], ENT_QUOTES, 'UTF-8'); ?></textarea>
                                </div>
                                <div class="field-full">
                                    <label for="newCharacterNotes">Notes privées</label>
                                    <textarea id="newCharacterNotes" name="character_notes"><?php echo htmlspecialchars((string) $create_character['cl_sccharacter_notes'], ENT_QUOTES, 'UTF-8'); ?></textarea>
                                </div>
                                <div class="field-full">
                                    <div class="checkbox-row">
                                        <input type="checkbox" id="newCharacterShareEnabled" name="character_share_enabled" value="1" <?php echo !empty($create_character['cl_sccharacter_share_enabled']) ? 'checked' : ''; ?>>
                                        <label for="newCharacterShareEnabled">Activer l’accès public via le lien partagé</label>
                                    </div>
                                </div>
                                <div class="field-full">
                                    <div class="checkbox-row">
                                        <span class="pin-indicator-input" aria-hidden="true">📌</span>
                                        <input type="checkbox" id="newCharacterPinned" name="character_is_pinned" value="1" <?php echo !empty($create_character['cl_sccharacter_is_pinned']) ? 'checked' : ''; ?>>
                                        <label for="newCharacterPinned">Toujours afficher ce personnage en haut de la liste</label>
                                    </div>
                                </div>
                            </div>

                            <div class="btn-row">
                                <button type="submit" class="btn btn-primary">Créer le personnage</button>
                            </div>
                        </form>
                    </div>
                </details>

                <div class="panel list-panel">
                    <div class="list-panel-header">
                        <div>
                            <h2 class="panel-title">Liste des personnages</h2>
                            <p class="panel-subtitle"><?php echo count($characters); ?> personnage(s). Sélectionne une fiche pour voir son détail, la modifier et lui attribuer son équipement.</p>
                        </div>
                    </div>

                    <div class="characters-stack">
                        <?php if ($characters === []): ?>
                            <div class="empty-state">
                                <strong>Aucun personnage pour le moment</strong>
                                Ouvre le bloc « Créer un personnage » ci-dessus pour commencer.
                            </div>
                        <?php else: ?>
                            <?php foreach ($characters as $character_row): ?>
                                <?php
                                    $character_id = (int) $character_row['cl_sccharacter_id'];
                                    $is_active = $selected_character && $character_id === (int) $selected_character['cl_sccharacter_id'];
                                    $avatar_url = trim((string) ($character_row['cl_sccharacter_avatar_url'] ?? ''));
                                    $initial = function_exists('mb_substr')
                                        ? mb_strtoupper(mb_substr((string) $character_row['cl_sccharacter_name'], 0, 1, 'UTF-8'), 'UTF-8')
                                        : strtoupper(substr((string) $character_row['cl_sccharacter_name'], 0, 1));
                                    $character_row_org_tag = sccharacters_resolve_org_tag($character_row);
                                    $character_row_has_player_handle = sccharacters_has_player_handle($character_row);
                                    $character_link = 'sccharacters.php?character=' . $character_id . '&item_source=' . rawurlencode($item_source);
                                    if ($item_search !== '') {
                                        $character_link .= '&item_search=' . rawurlencode($item_search);
                                    }
                                ?>
                                <a class="character-card<?php echo $is_active ? ' is-active' : ''; ?>" href="<?php echo htmlspecialchars($character_link, ENT_QUOTES, 'UTF-8'); ?>">
                                    <?php if ($avatar_url !== ''): ?>
                                        <img class="character-avatar" src="<?php echo htmlspecialchars($avatar_url, ENT_QUOTES, 'UTF-8'); ?>" alt="Avatar de <?php echo htmlspecialchars((string) $character_row['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?>" loading="lazy" onerror="this.replaceWith(Object.assign(document.createElement('div'), {className: 'character-avatar-fallback', textContent: '<?php echo htmlspecialchars($initial, ENT_QUOTES, 'UTF-8'); ?>'}));">
                                    <?php else: ?>
                                        <div class="character-avatar-fallback"><?php echo htmlspecialchars($initial, ENT_QUOTES, 'UTF-8'); ?></div>
                                    <?php endif; ?>
                                    <div class="character-card-body">
                                        <div class="character-card-title">
                                            <h3><?php echo htmlspecialchars((string) $character_row['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?></h3>
                                            <?php if (!empty($character_row['cl_sccharacter_is_pinned'])): ?>
                                                <span class="pin-indicator" title="Personnage épinglé" aria-label="Personnage épinglé">📌</span>
                                            <?php endif; ?>
                                        </div>
                                        <div class="badge-row" style="margin:0.42rem 0 0.52rem;">
                                            <?php if (trim((string) $character_row['cl_sccharacter_role']) !== ''): ?>
                                                <span class="badge badge-primary"><?php echo htmlspecialchars((string) $character_row['cl_sccharacter_role'], ENT_QUOTES, 'UTF-8'); ?></span>
                                            <?php endif; ?>
                                            <?php if ($character_row_org_tag !== ''): ?>
                                                <span class="badge">Org: <?php echo htmlspecialchars($character_row_org_tag, ENT_QUOTES, 'UTF-8'); ?></span>
                                            <?php endif; ?>
                                            <?php if ($character_row_has_player_handle): ?>
                                                <span class="badge">Handle: <?php echo htmlspecialchars((string) $character_row['cl_sccharacter_player_handle'], ENT_QUOTES, 'UTF-8'); ?></span>
                                            <?php endif; ?>
                                            <span class="badge badge-muted"><?php echo (int) $character_row['cl_sccharacter_item_count']; ?> objet(s)</span>
                                            <?php if (!empty($character_row['cl_sccharacter_share_enabled'])): ?>
                                                <span class="badge badge-success">Partage actif</span>
                                            <?php endif; ?>
                                        </div>
                                        <div class="muted">
                                            <?php echo htmlspecialchars(trim((string) $character_row['cl_sccharacter_description']) !== '' ? sccharacters_excerpt((string) $character_row['cl_sccharacter_description'], 110) : 'Aucune description pour le moment.', ENT_QUOTES, 'UTF-8'); ?>
                                        </div>
                                    </div>
                                </a>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </div>
                </div>
            </aside>

            <section class="right-column">
                <?php if ($selected_character): ?>
                    <?php
                        $hero_avatar = trim((string) ($selected_character['cl_sccharacter_avatar_url'] ?? ''));
                        $hero_initial = function_exists('mb_substr')
                            ? mb_strtoupper(mb_substr((string) $selected_character['cl_sccharacter_name'], 0, 1, 'UTF-8'), 'UTF-8')
                            : strtoupper(substr((string) $selected_character['cl_sccharacter_name'], 0, 1));
                    ?>
                    <div class="panel">
                        <div class="character-hero">
                            <?php if ($hero_avatar !== ''): ?>
                                <img class="character-hero-avatar" src="<?php echo htmlspecialchars($hero_avatar, ENT_QUOTES, 'UTF-8'); ?>" alt="Avatar de <?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?>" loading="lazy" onerror="this.replaceWith(Object.assign(document.createElement('div'), {className: 'character-hero-fallback', textContent: '<?php echo htmlspecialchars($hero_initial, ENT_QUOTES, 'UTF-8'); ?>'}));">
                            <?php else: ?>
                                <div class="character-hero-fallback"><?php echo htmlspecialchars($hero_initial, ENT_QUOTES, 'UTF-8'); ?></div>
                            <?php endif; ?>
                            <div>
                                <div class="hero-header">
                                    <div>
                                        <div class="hero-name-row">
                                            <h2 class="character-hero-name"><?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?></h2>
                                            <?php if (!empty($selected_character['cl_sccharacter_is_pinned'])): ?>
                                                <span class="pin-indicator" title="Personnage épinglé" aria-label="Personnage épinglé">📌</span>
                                            <?php endif; ?>
                                        </div>
                                        <div class="identity-grid">
                                            <div class="identity-item">
                                                <span class="identity-label">Rôle / Classe</span>
                                                <span class="identity-value"><?php echo htmlspecialchars(trim((string) $selected_character['cl_sccharacter_role']) !== '' ? (string) $selected_character['cl_sccharacter_role'] : '—', ENT_QUOTES, 'UTF-8'); ?></span>
                                            </div>
                                            <div class="identity-item">
                                                <span class="identity-label">Tag organisation</span>
                                                <span class="identity-value"><?php echo htmlspecialchars($selected_character_org_tag !== '' ? $selected_character_org_tag : '—', ENT_QUOTES, 'UTF-8'); ?></span>
                                            </div>
                                            <div class="identity-item">
                                                <span class="identity-label">Handle</span>
                                                <span class="identity-value"><?php echo htmlspecialchars(trim((string) ($selected_character['cl_sccharacter_player_handle'] ?? '')) !== '' ? (string) $selected_character['cl_sccharacter_player_handle'] : '—', ENT_QUOTES, 'UTF-8'); ?></span>
                                            </div>
                                        </div>
                                        <div class="hero-meta hero-meta-secondary">
                                            <span class="badge badge-muted"><?php echo count($selected_character_items); ?> équipement(s)</span>
                                        </div>
                                    </div>
                                    <span class="badge <?php echo !empty($selected_character['cl_sccharacter_share_enabled']) ? 'badge-success' : 'badge-muted'; ?>">
                                        <?php echo !empty($selected_character['cl_sccharacter_share_enabled']) ? 'Lien public actif' : 'Lien public désactivé'; ?>
                                    </span>
                                </div>

                                <p class="muted">
                                    <?php echo nl2br(htmlspecialchars(trim((string) $selected_character['cl_sccharacter_description']) !== '' ? (string) $selected_character['cl_sccharacter_description'] : 'Aucune description publique renseignée pour ce personnage.', ENT_QUOTES, 'UTF-8')); ?>
                                </p>

                                <div class="share-box">
                                    <div class="badge-row">
                                        <span class="badge badge-muted">Partage par lien uniquement</span>
                                        <span class="badge badge-muted">Page publique dédiée</span>
                                    </div>
                                    <input type="text" id="shareLinkField" readonly value="<?php echo htmlspecialchars(sccharacters_share_url((string) $selected_character['cl_sccharacter_share_token']), ENT_QUOTES, 'UTF-8'); ?>">
                                    <div class="btn-row" style="margin-top:0.75rem;">
                                        <button type="button" class="btn btn-secondary btn-small" onclick="copyShareLink()">Copier le lien</button>
                                        <form method="post" style="display:inline-flex;">
                                            <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                                            <input type="hidden" name="action" value="regenerate_share_token">
                                            <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                            <button type="submit" class="btn btn-secondary btn-small">Régénérer</button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <details class="panel accordion-panel">
                        <summary class="accordion-summary">
                            <div>
                                <h2 class="panel-title">Modifier la fiche</h2>
                                <p class="panel-subtitle">Bloc repliable pour garder la fiche visible sans laisser le formulaire ouvert en permanence.</p>
                            </div>
                            <span class="accordion-indicator">+</span>
                        </summary>
                        <div class="accordion-body">
                        <form method="post" id="characterEditForm">
                            <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                            <input type="hidden" name="action" value="update_character">
                            <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                            <input type="hidden" name="category_order_state" id="characterCategoryOrderState" value="<?php echo htmlspecialchars($selected_character_visible_category_order_state, ENT_QUOTES, 'UTF-8'); ?>">
                            <input type="hidden" name="item_order_state" id="characterItemOrderState" value="<?php echo htmlspecialchars($selected_character_item_order_state_json, ENT_QUOTES, 'UTF-8'); ?>">

                            <div class="edit-form-grid">
                                <div class="field-full">
                                    <label for="editCharacterName">Nom</label>
                                    <input type="text" id="editCharacterName" name="character_name" maxlength="190" required value="<?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_name'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="editCharacterRole">Rôle / Classe</label>
                                    <input type="text" id="editCharacterRole" name="character_role" maxlength="190" value="<?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_role'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="editCharacterOrgRsiUrl">Page RSI (URL)</label>
                                    <input type="url" id="editCharacterOrgRsiUrl" name="character_org_rsi_url" placeholder="https://robertsspaceindustries.com/en/orgs/REACT" value="<?php echo htmlspecialchars((string) ($selected_character['cl_sccharacter_org_rsi_url'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field">
                                    <label for="editCharacterPlayerHandle">Handle</label>
                                    <input type="text" id="editCharacterPlayerHandle" name="character_player_handle" maxlength="190" value="<?php echo htmlspecialchars((string) ($selected_character['cl_sccharacter_player_handle'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field-full">
                                    <label for="editCharacterAvatar">Avatar (URL d’image)</label>
                                    <input type="url" id="editCharacterAvatar" name="character_avatar_url" placeholder="https://..." value="<?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_avatar_url'], ENT_QUOTES, 'UTF-8'); ?>">
                                </div>
                                <div class="field-full">
                                    <label for="editCharacterDescription">Description</label>
                                    <textarea id="editCharacterDescription" name="character_description"><?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_description'], ENT_QUOTES, 'UTF-8'); ?></textarea>
                                </div>
                                <div class="field-full">
                                    <label for="editCharacterNotes">Notes privées</label>
                                    <textarea id="editCharacterNotes" name="character_notes"><?php echo htmlspecialchars((string) $selected_character['cl_sccharacter_notes'], ENT_QUOTES, 'UTF-8'); ?></textarea>
                                </div>
                                <div class="field-full">
                                    <div class="checkbox-row">
                                        <input type="checkbox" id="editCharacterShareEnabled" name="character_share_enabled" value="1" <?php echo !empty($selected_character['cl_sccharacter_share_enabled']) ? 'checked' : ''; ?>>
                                        <label for="editCharacterShareEnabled">Activer l’accès public via le lien partagé</label>
                                    </div>
                                </div>
                                <div class="field-full">
                                    <div class="checkbox-row">
                                        <span class="pin-indicator-input" aria-hidden="true">📌</span>
                                        <input type="checkbox" id="editCharacterPinned" name="character_is_pinned" value="1" <?php echo !empty($selected_character['cl_sccharacter_is_pinned']) ? 'checked' : ''; ?>>
                                        <label for="editCharacterPinned">Toujours afficher ce personnage en haut de la liste</label>
                                    </div>
                                </div>
                            </div>

                            <div class="btn-row">
                                <button type="submit" class="btn btn-primary">Enregistrer</button>
                                <span class="muted order-state-indicator" id="characterOrderStateIndicator" hidden>Des changements d’ordre sont en attente d’enregistrement.</span>
                            </div>
                        </form>

                        <div class="btn-row">
                            <form method="post" style="display:inline-flex;">
                                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                                <input type="hidden" name="action" value="delete_character">
                                <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                <button type="submit" class="btn btn-danger" onclick="return confirm('Supprimer ce personnage et son équipement ?');">Supprimer le personnage</button>
                            </form>
                        </div>
                        </div>
                    </details>

                    <details class="panel accordion-panel" open>
                        <summary class="accordion-summary">
                            <div>
                                <h2 class="panel-title">Équipement attribué</h2>
                                <p class="panel-subtitle">Bloc repliable pour consulter rapidement l’équipement et le refermer quand tu veux dégager la vue.</p>
                            </div>
                            <span class="accordion-indicator">+</span>
                        </summary>
                        <div class="accordion-body">

                        <?php if ($selected_character_items === []): ?>
                            <div class="empty-state">
                                <strong>Aucun équipement attribué</strong>
                                Utilise le module de recherche plus bas pour ajouter un objet de la base ou un objet personnalisé.
                            </div>
                        <?php else: ?>
                            <div class="equipment-order-toolbar">
                                <span class="muted">Tu peux réorganiser librement les catégories et les objets ci-dessous, puis enregistrer quand tu veux.</span>
                                <button type="submit" form="characterEditForm" class="btn btn-primary btn-small">Enregistrer l’ordre</button>
                            </div>
                            <div class="equipment-sections" id="characterEquipmentSections">
                                <?php foreach ($selected_character_items_by_category as $category_key => $category_items): ?>
                                    <?php $category_order_meta = $selected_character_category_order_meta[$category_key] ?? ['is_first' => false, 'is_last' => false]; ?>
                                    <section class="equipment-section" data-category-key="<?php echo htmlspecialchars((string) $category_key, ENT_QUOTES, 'UTF-8'); ?>">
                                        <div class="equipment-section-heading">
                                            <div class="equipment-section-heading-main">
                                                <h3 class="equipment-section-title"><?php echo htmlspecialchars(sccharacters_item_category_label((string) $category_key), ENT_QUOTES, 'UTF-8'); ?></h3>
                                                <span class="badge badge-muted"><?php echo count($category_items); ?> objet(s)</span>
                                            </div>
                                            <div class="equipment-category-order-controls" data-category-key="<?php echo htmlspecialchars((string) $category_key, ENT_QUOTES, 'UTF-8'); ?>">
                                                <button type="button" class="btn btn-secondary btn-small order-btn category-order-btn" data-move-direction="up" data-category-key="<?php echo htmlspecialchars((string) $category_key, ENT_QUOTES, 'UTF-8'); ?>" title="Afficher cette catégorie plus haut" aria-label="Afficher cette catégorie plus haut" <?php echo $category_order_meta['is_first'] ? 'disabled' : ''; ?>>↑</button>
                                                <button type="button" class="btn btn-secondary btn-small order-btn category-order-btn" data-move-direction="down" data-category-key="<?php echo htmlspecialchars((string) $category_key, ENT_QUOTES, 'UTF-8'); ?>" title="Afficher cette catégorie plus bas" aria-label="Afficher cette catégorie plus bas" <?php echo $category_order_meta['is_last'] ? 'disabled' : ''; ?>>↓</button>
                                            </div>
                                        </div>
                                        <div class="equipment-grid equipment-grid-sortable" data-category-key="<?php echo htmlspecialchars((string) $category_key, ENT_QUOTES, 'UTF-8'); ?>">
                                            <?php foreach ($category_items as $character_item_row): ?>
                                                <?php
                                                    $is_custom = ($character_item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
                                                    $item_name = $is_custom
                                                        ? (string) ($character_item_row['cl_sccharacteritem_custom_name'] ?? 'Objet personnalisé indisponible')
                                                        : (string) ($character_item_row['cl_sccharacteritem_base_name'] ?? 'Objet indisponible');
                                                    $item_type = $is_custom
                                                        ? (string) ($character_item_row['cl_sccharacteritem_custom_type'] ?? '')
                                                        : (string) ($character_item_row['cl_sccharacteritem_base_type'] ?? '');
                                                    $item_subtype = $is_custom
                                                        ? (string) ($character_item_row['cl_sccharacteritem_custom_subtype'] ?? '')
                                                        : (string) ($character_item_row['cl_sccharacteritem_base_subtype'] ?? '');
                                                    $item_uuid = $is_custom
                                                        ? (string) ($character_item_row['cl_sccharacteritem_custom_uuid'] ?? '')
                                                        : (string) ($character_item_row['cl_sccharacteritem_base_uuid'] ?? '');
                                                    $item_category = sccharacters_resolve_item_category(
                                                        (string) ($character_item_row['cl_sccharacteritem_slot'] ?? ''),
                                                        $item_type,
                                                        $item_subtype
                                                    );
                                                    $item_quantity = sccharacters_normalize_item_quantity($character_item_row['cl_sccharacteritem_quantity'] ?? null);
                                                    $item_title = $item_quantity !== null ? $item_quantity . 'x ' . $item_name : $item_name;
                                                    $item_note = trim((string) ($character_item_row['cl_sccharacteritem_note'] ?? ''));
                                                    $item_stats = [];
                                                    if ($is_custom) {
                                                        $item_stats = $custom_stats_by_itemcustom[(int) ($character_item_row['cl_sccharacteritem_scitemcustom_id'] ?? 0)] ?? [];
                                                    }
                                                ?>
                                                <article class="equip-card" draggable="true" data-item-id="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>">
                                                    <?php if ($item_uuid !== ''): ?>
                                                        <img class="equip-thumb" src="https://cstone.space/uifimages/<?php echo htmlspecialchars($item_uuid, ENT_QUOTES, 'UTF-8'); ?>.png" alt="Aperçu de <?php echo htmlspecialchars($item_name, ENT_QUOTES, 'UTF-8'); ?>" loading="lazy" onerror="this.replaceWith(Object.assign(document.createElement('div'), {className: 'equip-thumb-fallback', textContent: '◈'}));">
                                                    <?php else: ?>
                                                        <div class="equip-thumb-fallback">◈</div>
                                                    <?php endif; ?>
                                                    <div class="equip-content">
                                                        <div>
                                                            <div class="equip-title-row">
                                                                <h3 class="equip-title"><?php echo htmlspecialchars($item_title, ENT_QUOTES, 'UTF-8'); ?></h3>
                                                                <span class="drag-handle" title="Glisser pour changer l’ordre" aria-hidden="true">⋮⋮</span>
                                                            </div>
                                                            <div class="equip-meta" style="margin-top:0.45rem;">
                                                                <span class="badge <?php echo $is_custom ? 'badge-primary' : 'badge-muted'; ?>"><?php echo $is_custom ? 'Objet perso.' : 'Base d’objets'; ?></span>
                                                                <span class="badge"><?php echo htmlspecialchars(sccharacters_item_category_label($item_category), ENT_QUOTES, 'UTF-8'); ?></span>
                                                                <?php if ($item_type !== ''): ?><span class="badge badge-muted"><?php echo htmlspecialchars($item_type, ENT_QUOTES, 'UTF-8'); ?></span><?php endif; ?>
                                                                <?php if ($item_subtype !== ''): ?><span class="badge badge-muted"><?php echo htmlspecialchars($item_subtype, ENT_QUOTES, 'UTF-8'); ?></span><?php endif; ?>
                                                            </div>
                                                        </div>

                                                        <?php if ($item_stats !== []): ?>
                                                            <div class="equip-stats">
                                                                <?php foreach ($item_stats as $stat_row): ?>
                                                                    <?php
                                                                        $sign = (string) ($stat_row['cl_scitemcustomstat_sign'] ?? '');
                                                                        $value = rtrim(rtrim(number_format((float) ($stat_row['cl_scitemcustomstat_value'] ?? 0), 2, '.', ''), '0'), '.');
                                                                        if ($value === '') {
                                                                            $value = '0';
                                                                        }
                                                                    ?>
                                                                    <span class="equip-stat"><?php echo htmlspecialchars((string) $stat_row['cl_scstatsitem_name'], ENT_QUOTES, 'UTF-8'); ?> : <?php echo htmlspecialchars($sign . $value . ' ' . (string) $stat_row['cl_scstatsitem_unit'], ENT_QUOTES, 'UTF-8'); ?></span>
                                                                <?php endforeach; ?>
                                                            </div>
                                                        <?php endif; ?>

                                                        <?php if ($item_note !== ''): ?>
                                                            <div class="muted"><?php echo nl2br(htmlspecialchars($item_note, ENT_QUOTES, 'UTF-8')); ?></div>
                                                        <?php endif; ?>

                                                        <div class="equipment-actions">
                                                            <span class="drag-hint muted">Glisser-déposer pour réordonner dans cette catégorie</span>
                                                            <div class="equipment-action-buttons">
                                                                <details class="equipment-edit">
                                                                    <summary class="btn btn-secondary btn-small equipment-edit-summary" title="Modifier l’objet" aria-label="Modifier l’objet"><span aria-hidden="true">✎</span></summary>
                                                                    <form method="post" class="equipment-edit-form">
                                                                        <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                                                                        <input type="hidden" name="action" value="update_character_item">
                                                                        <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                                                        <input type="hidden" name="character_item_id" value="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>">
                                                                        <input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>">
                                                                        <input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
                                                                        <input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>">
                                                                        <input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">
                                                                        <input type="hidden" name="item_panel_context" value="<?php echo ($item_search !== '' || $item_panel_open) ? '1' : '0'; ?>">
                                                                        <div class="equipment-edit-grid">
                                                                            <input type="number" name="item_quantity" min="1" step="1" inputmode="numeric" placeholder="Quantité" value="<?php echo $item_quantity !== null ? (int) $item_quantity : ''; ?>" aria-label="Quantité de l'objet">
                                                                            <select name="item_slot" aria-label="Catégorie de l'objet">
                                                                                <?php foreach ($item_category_options as $category_value => $category_label): ?>
                                                                                    <option value="<?php echo htmlspecialchars($category_value, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $item_category === $category_value ? 'selected' : ''; ?>>
                                                                                        <?php echo htmlspecialchars($category_label, ENT_QUOTES, 'UTF-8'); ?>
                                                                                    </option>
                                                                                <?php endforeach; ?>
                                                                            </select>
                                                                            <textarea name="item_note" class="item-note-field" rows="4" placeholder="Note optionnelle"><?php echo htmlspecialchars($item_note, ENT_QUOTES, 'UTF-8'); ?></textarea>
                                                                        </div>
                                                                        <div class="equipment-edit-form-actions">
                                                                            <button type="submit" class="btn btn-primary btn-small">Enregistrer</button>
                                                                        </div>
                                                                    </form>
                                                                </details>
                                                                <form method="post" style="display:inline-flex;">
                                                                    <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                                                                    <input type="hidden" name="action" value="delete_character_item">
                                                                    <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                                                    <input type="hidden" name="character_item_id" value="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>">
                                                                    <input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>">
                                                                    <input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
                                                                    <input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>">
                                                                    <input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">
                                                                    <input type="hidden" name="item_panel_context" value="<?php echo ($item_search !== '' || $item_panel_open) ? '1' : '0'; ?>">
                                                                    <button type="submit" class="btn btn-danger btn-small equipment-icon-button" title="Retirer l’objet" aria-label="Retirer l’objet" onclick="return confirm('Retirer cet objet du personnage ?');"><span aria-hidden="true">🗑</span></button>
                                                                </form>
                                                            </div>
                                                        </div>
                                                    </div>
                                                </article>
                                            <?php endforeach; ?>
                                        </div>
                                    </section>
                                <?php endforeach; ?>
                            </div>
                            </div>
                        <?php endif; ?>
                        </div>
                    </details>

                    <details class="panel accordion-panel" <?php echo ($item_search !== '' || $item_panel_open) ? 'open' : ''; ?>>
                        <summary class="accordion-summary">
                            <div>
                                <h2 class="panel-title">Ajouter des objets</h2>
                                <p class="panel-subtitle">Recherche repliable : tu l’ouvres quand tu équipes le personnage, tu la refermes dès que c’est fait.</p>
                            </div>
                            <span class="accordion-indicator">+</span>
                        </summary>
                        <div class="accordion-body">
                        <div class="search-toolbar">
                            <form method="get" class="item-search-form" id="itemSearchForm" data-character-id="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                <input type="hidden" name="character" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                <input type="hidden" name="item_panel" value="1">
                                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">

                                <div class="search-top-row">
                                    <div class="source-switch" role="radiogroup" aria-label="Source de recherche d’objet">
                                        <input type="radio" name="item_source" id="itemSourceBase" value="base" <?php echo $item_source === 'base' ? 'checked' : ''; ?>>
                                        <label for="itemSourceBase">Base d’objets</label>

                                        <input type="radio" name="item_source" id="itemSourceCustom" value="custom" <?php echo $item_source === 'custom' ? 'checked' : ''; ?>>
                                        <label for="itemSourceCustom">Objets perso.</label>
                                    </div>

                                    <label class="preview-toggle" for="itemPreviewToggle">
                                        <input type="checkbox" id="itemPreviewToggle">
                                        <span>Afficher l’aperçu</span>
                                    </label>
                                </div>

                                <div class="search-controls-row">
                                    <input type="text" name="item_search" placeholder="Nom, type, subtype, UUID..." value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
                                    <select name="item_per_page" aria-label="Nombre de résultats affichés">
                                        <?php foreach (sccharacters_allowed_item_per_page() as $per_page_option): ?>
                                            <option value="<?php echo (int) $per_page_option; ?>" <?php echo $item_per_page === $per_page_option ? 'selected' : ''; ?>>
                                                <?php echo (int) $per_page_option; ?> résultats / page
                                            </option>
                                        <?php endforeach; ?>
                                    </select>
                                    <button type="submit" class="btn btn-primary btn-small">Rechercher</button>
                                </div>
                            </form>
                        </div>

                        <div class="search-results">
                            <?php if ($item_results === []): ?>
                                <div class="empty-state">
                                    <strong><?php echo $item_source === 'custom' ? 'Aucun objet personnalisé trouvé' : 'Aucun objet trouvé'; ?></strong>
                                    <?php if ($item_source === 'custom'): ?>
                                        <?php if ($item_search !== ''): ?>
                                            Aucun objet personnalisé ne correspond à « <?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?> ».
                                        <?php else: ?>
                                            Commence par créer des objets dans l’onglet « Objets perso. » pour pouvoir les attribuer à tes personnages.
                                        <?php endif; ?>
                                    <?php else: ?>
                                        <?php if ($item_search !== ''): ?>
                                            Aucun objet de la base ne correspond à « <?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?> ».
                                        <?php else: ?>
                                            Lance une recherche ou parcours le catalogue page par page avec le sélecteur de résultats.
                                        <?php endif; ?>
                                    <?php endif; ?>
                                </div>
                            <?php else: ?>
                                <div class="search-results-summary panel panel-soft">
                                    <div>
                                        <strong>Résultats de recherche</strong>
                                        <div class="search-result-range">
                                            <?php echo (int) $item_result_offset_start; ?>–<?php echo (int) $item_result_offset_end; ?> sur <?php echo (int) $item_total_results; ?> résultat(s)
                                            · page <?php echo (int) $item_page; ?> / <?php echo (int) $item_total_pages; ?>
                                        </div>
                                    </div>
                                    <div class="muted">Le bouton <strong>+</strong> ajoute l’objet immédiatement au personnage sans casser ta recherche en cours.</div>
                                </div>

                                <?php foreach ($item_results as $item_result_row): ?>
                                    <?php
                                        $result_is_custom = $item_source === 'custom';
                                        $result_name = (string) $item_result_row['cl_scobjs_name'];
                                        $result_type = trim(((string) $item_result_row['cl_scobjs_type']) . ' · ' . ((string) $item_result_row['cl_scobjs_subtype']), ' ·');
                                        $recommended_category = sccharacters_resolve_item_category(
                                            '',
                                            (string) ($item_result_row['cl_scobjs_type'] ?? ''),
                                            (string) ($item_result_row['cl_scobjs_subtype'] ?? '')
                                        );
                                        $result_id = $result_is_custom
                                            ? (int) ($item_result_row['cl_scitemcustom_id'] ?? 0)
                                            : (int) ($item_result_row['cl_scobjs_id'] ?? 0);
                                        $item_action = $result_is_custom ? 'add_custom_item' : 'add_base_item';
                                        $item_id_field = $result_is_custom ? 'custom_item_id' : 'base_obj_id';
                                        $item_uuid = (string) ($item_result_row['cl_scobjs_uuid'] ?? '');
                                        $item_image_url = $item_uuid !== '' ? 'https://cstone.space/uifimages/' . rawurlencode($item_uuid) . '.png' : '';
                                        $result_stats = $result_is_custom ? ($item_result_custom_stats[$result_id] ?? []) : [];
                                    ?>
                                    <article class="search-result panel panel-soft">
                                        <div class="search-result-preview">
                                            <?php if ($item_image_url !== ''): ?>
                                                <div class="preview-container">
                                                    <img src="<?php echo htmlspecialchars($item_image_url, ENT_QUOTES, 'UTF-8'); ?>" class="item-preview" alt="Aperçu de <?php echo htmlspecialchars($result_name, ENT_QUOTES, 'UTF-8'); ?>" loading="lazy" onerror="this.replaceWith(Object.assign(document.createElement('div'), {className:'item-preview-fallback', textContent:'◈'}));">
                                                    <div class="preview-floating" aria-hidden="true">
                                                        <img src="<?php echo htmlspecialchars($item_image_url, ENT_QUOTES, 'UTF-8'); ?>" alt="" loading="lazy" onerror="this.closest('.preview-floating').remove();">
                                                    </div>
                                                </div>
                                            <?php else: ?>
                                                <div class="item-preview-fallback">◈</div>
                                            <?php endif; ?>
                                        </div>

                                        <div class="search-result-main">
                                            <div>
                                                <strong><?php echo htmlspecialchars($result_name, ENT_QUOTES, 'UTF-8'); ?></strong>
                                                <div class="muted"><?php echo htmlspecialchars($result_type !== '' ? $result_type : 'Type non renseigné', ENT_QUOTES, 'UTF-8'); ?></div>
                                            </div>
                                            <div class="badge-row">
                                                <span class="badge <?php echo $result_is_custom ? 'badge-primary' : 'badge-muted'; ?>"><?php echo $result_is_custom ? 'Objet perso.' : 'Base d’objets'; ?></span>
                                                <?php if ($item_uuid !== ''): ?>
                                                    <span class="badge badge-muted">UUID : <?php echo htmlspecialchars($item_uuid, ENT_QUOTES, 'UTF-8'); ?></span>
                                                <?php endif; ?>
                                                <?php if ($result_is_custom): ?>
                                                    <span class="badge badge-muted"><?php echo (int) $item_result_row['cl_scitemcustom_stat_count']; ?> stat(s)</span>
                                                <?php endif; ?>
                                            </div>

                                            <?php if ($result_is_custom && $result_stats !== []): ?>
                                                <div class="equip-stats search-result-stats">
                                                    <?php foreach ($result_stats as $stat_row): ?>
                                                        <span class="equip-stat"><?php echo htmlspecialchars(sccharacters_custom_stat_preview($stat_row), ENT_QUOTES, 'UTF-8'); ?></span>
                                                    <?php endforeach; ?>
                                                </div>
                                            <?php endif; ?>
                                        </div>

                                        <form method="post" class="item-attach-form">
                                            <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
                                            <input type="hidden" name="action" value="<?php echo htmlspecialchars($item_action, ENT_QUOTES, 'UTF-8'); ?>">
                                            <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
                                            <input type="hidden" name="<?php echo htmlspecialchars($item_id_field, ENT_QUOTES, 'UTF-8'); ?>" value="<?php echo (int) $result_id; ?>">
                                            <input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>">
                                            <input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
                                            <input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>">
                                            <input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">

                                            <div class="item-attach-meta">
                                                <input type="number" name="item_quantity" min="1" step="1" inputmode="numeric" placeholder="Quantité" aria-label="Quantité de l'objet">
                                                <select name="item_slot" aria-label="Catégorie de l'objet">
                                                    <?php foreach ($item_category_options as $category_value => $category_label): ?>
                                                        <option value="<?php echo htmlspecialchars($category_value, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $recommended_category === $category_value ? 'selected' : ''; ?>>
                                                            <?php echo htmlspecialchars($category_label, ENT_QUOTES, 'UTF-8'); ?>
                                                        </option>
                                                    <?php endforeach; ?>
                                                </select>
                                                <textarea name="item_note" class="item-note-field" rows="2" placeholder="Note optionnelle"></textarea>
                                            </div>

                                            <div class="item-attach-actions">
                                                <button type="submit" class="btn btn-primary item-add-button" title="Ajouter immédiatement" aria-label="Ajouter <?php echo htmlspecialchars($result_name, ENT_QUOTES, 'UTF-8'); ?> au personnage">+</button>
                                            </div>
                                        </form>
                                    </article>
                                <?php endforeach; ?>

                                <div class="pagination-bar panel panel-soft">
                                    <div class="pagination-label">Navigation dans les résultats</div>
                                    <div class="pagination-links">
                                        <?php
                                            $prev_params = $item_query_base_params;
                                            $next_params = $item_query_base_params;
                                            if ($item_has_previous_page) {
                                                if (($item_page - 1) > 1) {
                                                    $prev_params['item_page'] = $item_page - 1;
                                                }
                                            }
                                            if ($item_has_next_page) {
                                                $next_params['item_page'] = $item_page + 1;
                                            }
                                        ?>
                                        <?php if ($item_has_previous_page): ?>
                                            <a class="btn-link btn-small btn-secondary" href="sccharacters.php?<?php echo htmlspecialchars(http_build_query($prev_params), ENT_QUOTES, 'UTF-8'); ?>">← Page précédente</a>
                                        <?php endif; ?>
                                        <?php if ($item_has_next_page): ?>
                                            <a class="btn-link btn-small btn-secondary" href="sccharacters.php?<?php echo htmlspecialchars(http_build_query($next_params), ENT_QUOTES, 'UTF-8'); ?>">Page suivante →</a>
                                        <?php endif; ?>
                                    </div>
                                </div>
                            <?php endif; ?>
                        </div>                    </details>

                <?php else: ?>
                    <div class="empty-state">
                        <strong>Aucun personnage sélectionné</strong>
                        Crée un personnage via le bloc repliable de gauche, puis sélectionne-le dans la liste pour gérer sa fiche et son équipement.
                    </div>
                <?php endif; ?>
            </section>
        </div>
    <script>
        function copyShareLink() {
            const input = document.getElementById('shareLinkField');
            if (!input) {
                return;
            }

            input.select();
            input.setSelectionRange(0, input.value.length);

            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(input.value).catch(() => document.execCommand('copy'));
            } else {
                document.execCommand('copy');
            }
        }

        const itemSearchForm = document.getElementById('itemSearchForm');
        const itemPreviewToggle = document.getElementById('itemPreviewToggle');
        const itemSourceInputs = Array.from(document.querySelectorAll('input[name="item_source"]'));
        const previewStorageKey = 'sccharacters-item-preview-v2';

        function setPreviewState(enabled) {
            document.body.classList.toggle('show-item-preview', enabled);

            if (itemPreviewToggle) {
                itemPreviewToggle.checked = enabled;
            }
        }

        let previewEnabled = true;

        try {
            const storedPreviewState = window.localStorage.getItem(previewStorageKey);
            previewEnabled = storedPreviewState === null ? true : storedPreviewState === '1';
        } catch (error) {
            previewEnabled = true;
        }

        setPreviewState(previewEnabled);

        if (itemPreviewToggle) {
            itemPreviewToggle.addEventListener('change', () => {
                const enabled = itemPreviewToggle.checked;
                setPreviewState(enabled);

                try {
                    window.localStorage.setItem(previewStorageKey, enabled ? '1' : '0');
                } catch (error) {
                    // Ignore storage issues silently.
                }
            });
        }

        itemSourceInputs.forEach((input) => {
            input.addEventListener('change', () => {
                if (itemSearchForm) {
                    itemSearchForm.submit();
                }
            });
        });

        function initEquipmentOrdering() {
            const editForm = document.getElementById('characterEditForm');
            const categoryOrderInput = document.getElementById('characterCategoryOrderState');
            const itemOrderInput = document.getElementById('characterItemOrderState');
            const orderStateIndicator = document.getElementById('characterOrderStateIndicator');
            const equipmentSections = document.getElementById('characterEquipmentSections');
            const categoryButtons = Array.from(document.querySelectorAll('.category-order-btn'));
            const grids = Array.from(document.querySelectorAll('.equipment-grid-sortable'));

            if (!editForm || !categoryOrderInput || !itemOrderInput || !equipmentSections) {
                return;
            }

            const readItemOrderState = () => {
                try {
                    const parsed = JSON.parse(itemOrderInput.value || '{}');
                    return parsed && typeof parsed === 'object' ? parsed : {};
                } catch (error) {
                    return {};
                }
            };

            let hasPendingOrderChanges = false;

            const markPendingOrderChanges = () => {
                hasPendingOrderChanges = true;
                if (orderStateIndicator) {
                    orderStateIndicator.hidden = false;
                }
            };

            const syncCategoryButtonState = () => {
                const sections = Array.from(equipmentSections.querySelectorAll('.equipment-section[data-category-key]'));
                const firstKey = sections[0]?.dataset.categoryKey || '';
                const lastKey = sections[sections.length - 1]?.dataset.categoryKey || '';

                categoryButtons.forEach((button) => {
                    const categoryKey = button.dataset.categoryKey || '';
                    const direction = button.dataset.moveDirection || '';
                    button.disabled = (direction === 'up' && categoryKey === firstKey)
                        || (direction === 'down' && categoryKey === lastKey);
                });
            };

            const syncCategoryOrderState = () => {
                const orderedKeys = Array.from(equipmentSections.querySelectorAll('.equipment-section[data-category-key]'))
                    .map((section) => section.dataset.categoryKey || '')
                    .filter(Boolean);
                categoryOrderInput.value = orderedKeys.join(',');
                syncCategoryButtonState();
            };

            const syncItemOrderStateForGrid = (grid) => {
                const categoryKey = grid.dataset.categoryKey || '';
                if (!categoryKey) {
                    return;
                }

                const state = readItemOrderState();
                state[categoryKey] = Array.from(grid.querySelectorAll('.equip-card[data-item-id]'))
                    .map((card) => Number(card.dataset.itemId || 0))
                    .filter((itemId) => Number.isInteger(itemId) && itemId > 0);
                itemOrderInput.value = JSON.stringify(state);
            };

            categoryButtons.forEach((button) => {
                button.addEventListener('click', () => {
                    const categoryKey = button.dataset.categoryKey || '';
                    const direction = button.dataset.moveDirection || '';
                    const section = equipmentSections.querySelector(`.equipment-section[data-category-key="${categoryKey}"]`);
                    if (!section) {
                        return;
                    }

                    if (direction === 'up') {
                        const previousSection = section.previousElementSibling;
                        if (previousSection) {
                            equipmentSections.insertBefore(section, previousSection);
                        }
                    } else if (direction === 'down') {
                        const nextSection = section.nextElementSibling;
                        if (nextSection) {
                            equipmentSections.insertBefore(nextSection, section);
                        }
                    }

                    syncCategoryOrderState();
                    markPendingOrderChanges();
                });
            });

            grids.forEach((grid) => {
                const cards = Array.from(grid.querySelectorAll('.equip-card[data-item-id]'));
                if (cards.length < 2) {
                    syncItemOrderStateForGrid(grid);
                    return;
                }

                let draggedCard = null;
                let originalOrder = cards.map((card) => card.dataset.itemId).join(',');

                const currentOrder = () => Array.from(grid.querySelectorAll('.equip-card[data-item-id]'))
                    .map((card) => card.dataset.itemId)
                    .filter(Boolean)
                    .join(',');

                const clearDragMarkers = () => {
                    grid.querySelectorAll('.equip-card.drag-over').forEach((card) => card.classList.remove('drag-over'));
                };

                cards.forEach((card) => {
                    card.addEventListener('dragstart', (event) => {
                        draggedCard = card;
                        originalOrder = currentOrder();
                        card.classList.add('dragging');
                        if (event.dataTransfer) {
                            event.dataTransfer.effectAllowed = 'move';
                            event.dataTransfer.setData('text/plain', card.dataset.itemId || '');
                        }
                    });

                    card.addEventListener('dragover', (event) => {
                        if (!draggedCard || draggedCard === card || draggedCard.parentElement !== grid) {
                            return;
                        }

                        event.preventDefault();
                        clearDragMarkers();
                        card.classList.add('drag-over');

                        const rect = card.getBoundingClientRect();
                        const insertBefore = event.clientY < rect.top + (rect.height / 2);
                        grid.insertBefore(draggedCard, insertBefore ? card : card.nextSibling);
                    });

                    card.addEventListener('dragleave', () => {
                        card.classList.remove('drag-over');
                    });

                    card.addEventListener('drop', (event) => {
                        event.preventDefault();
                        card.classList.remove('drag-over');
                    });

                    card.addEventListener('dragend', () => {
                        card.classList.remove('dragging');
                        clearDragMarkers();

                        if (!draggedCard) {
                            return;
                        }

                        const updatedOrder = currentOrder();
                        draggedCard = null;

                        if (updatedOrder !== '' && updatedOrder !== originalOrder) {
                            syncItemOrderStateForGrid(grid);
                            markPendingOrderChanges();
                        }
                    });
                });

                grid.addEventListener('dragover', (event) => {
                    if (!draggedCard || draggedCard.parentElement !== grid) {
                        return;
                    }

                    event.preventDefault();
                    const targetCard = event.target.closest('.equip-card[data-item-id]');
                    if (!targetCard) {
                        grid.appendChild(draggedCard);
                    }
                });

                grid.addEventListener('drop', (event) => {
                    event.preventDefault();
                    clearDragMarkers();
                });

                syncItemOrderStateForGrid(grid);
            });

            editForm.addEventListener('submit', () => {
                syncCategoryOrderState();
                grids.forEach((grid) => syncItemOrderStateForGrid(grid));
                hasPendingOrderChanges = false;
                if (orderStateIndicator) {
                    orderStateIndicator.hidden = true;
                }
            });

            syncCategoryOrderState();
        }

        initEquipmentOrdering();
    </script>
</body>
</html>
