Output:
Exit code: 1
Wall time: 1.2 seconds
Output:
Select-String : Impossible de trouver un param�tre correspondant au nom ��Recurse��.
Au caract�re Ligne:1 : 47
+ Select-String -Path admin\* -Pattern '<style' -Recurse
+                                               ~~~~~~~~
    + CategoryInfo          : InvalidArgument : (:) [Select-String], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.SelectStringCommand


Summary: auto


Get-ChildItem -Recurse admin | Select-String -Pattern '<style'


Output:
Exit code: 0
Wall time: 1.1 seconds
Output:


Select-String -Path admin\hyperadmin_forms.php -Pattern '<style'


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:


Output:
Exit code: 0
Wall time: 1 seconds
Output:
admin\annonces_theme_admin.php:135:             style="width: 200px">
admin\annonces_theme_admin.php:177:                       style="width: 50px; height: 36px; padding: 2px;">
admin\annonces_theme_admin.php:188:                       style="width: 100px">
admin\annonces_theme_admin.php:197:                       style="width: 50px; height: 36px; padding: 2px;">
admin\annonces_theme_admin.php:208:                       style="width: 100px">
admin\annonces_theme_admin.php:217:                       style="width: 50px; height: 36px; padding: 2px;">
admin\annonces_theme_admin.php:228:                       style="width: 100px">
admin\annonces_widget.php:114:    '$2',
admin\annonces_widget.php:115:    '$2',
admin\annonces_widget.php:352:  echo '<div class="ann-grid '.h($layoutClass).'" style="--ann-gap: '.$gapPx.'px;" '.
admin\debug_patch.php:10:    echo '
';
admin\debug_traffic_alerts.php:45:    echo "
✅ Trouvé dans : $color
";
admin\debug_traffic_alerts.php:47:    echo "
❌ 'interrompu' n'existe PAS dans severity_levels
";
admin\hyperadmin.php:452:                <form method="post" style="display: inline;">
admin\hyperadmin.php:460:                <form method="post" style="display: inline;">
admin\hyperadmin_forms.php:161:

admin\hyperadmin_forms.php:220:                    <div class="form-group" id="reactivate_alerts_group" style="margin-left: 30px; <?= $showReactivateOption ? '' : 'display: none;' ?>">
admin\hyperadmin_forms.php:268:

admin\hyperadmin_forms.php:386:

admin\hyperadmin_forms.php:391:

admin\hyperadmin_forms.php:394:
admin\hyperadmin_forms.php:398:                                  style="font-family: monospace; border-left: 4px solid #ef4444; background: #fef2f2;">
admin\hyperadmin_forms.php:413:
admin\hyperadmin_forms.php:417:                                  style="font-family: monospace; border-left: 4px solid #f97316; background: #fff7ed;">
admin\hyperadmin_forms.php:431:
admin\hyperadmin_forms.php:435:                                  style="font-family: monospace; border-left: 4px solid #eab308; background: #fefce8;">
admin\hyperadmin_forms.php:449:
admin\hyperadmin_forms.php:453:                                  style="font-family: monospace; border-left: 4px solid #3b82f6; background: #eff6ff;">
admin\hyperadmin_forms.php:786:

admin\hyperadmin_forms.php:833:                                                Jamais
admin\hyperadmin_forms.php:883:                                                Jamais
admin\hyperadmin_forms.php:1067:

admin\hyperadmin_forms.php:1174:

admin\hyperadmin_forms.php:1190:                    content.innerHTML = '

Chargement...
';
admin\hyperadmin_forms.php:1199:                                content.innerHTML = '
❌ ' + data.message + '
';
admin\hyperadmin_forms.php:1203:                            content.innerHTML = '
❌ Erreur lors du chargement
';
admin\hyperadmin_forms.php:1261:

admin\hyperadmin_forms.php:1265:

admin\hyperadmin_forms.php:1285:

admin\index.php:440:        <form method="post" action="<?= $_SERVER['PHP_SELF'] ?>" id="template-form" style="margin-left: auto; display: flex; gap: 8px; align-items: center;">
admin\index.php:467:                    📌
admin\index.php:468:                    👁
admin\index.php:469:                    📅
admin\index.php:472:                    Couleur
admin\index.php:473:                    Actions
admin\index.php:483:                            <form class="inline-toggle" style="display:inline">
admin\index.php:498:                            <form class="inline-toggle" style="display:inline">
admin\index.php:513:                            <form class="inline-toggle" style="display:inline">
admin\index.php:538:                                  style="display: inline-block; width: 24px; height: 24px; border-radius: 4px;">
admin\index.php:544:

admin\index.php:547:                                    <form method="post" style="display:inline">
admin\index.php:555:                                <form method="post" style="display:inline">
admin\index.php:569:
admin\index.php:581:

admin\index.php:661:                  style="display: inline-block; width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--color-border);">
admin\index.php:669:                <form method="post" style="display:inline">
admin\index.php:677:            <form method="post" style="display:inline">
admin\index.php:718:

admin\index.php:726:
admin\index.php:736:                     style="background: <?= h($colors['bg']) ?>;
admin\index.php:746:
admin\index.php:748:    <label class="toggle <?= !empty($edit['show_date']) ? 'on' : '' ?>" style="margin-left: 8px;">
admin\index.php:755:
admin\index.php:757:            <label class="toggle <?= !empty($edit['pinned']) ? 'on' : '' ?>" style="margin-left: 8px;">
admin\index.php:764:
admin\index.php:766:            <label class="toggle <?= !empty($edit['active']) || !$edit ? 'on' : '' ?>" style="margin-left: 8px;">
admin\index.php:778:

admin\index.php:783:                <button data-color="#000000" style="background-color:#000000"></button>
admin\index.php:784:                <button data-color="#e60000" style="background-color:#e60000"></button>
admin\index.php:785:                <button data-color="#008a00" style="background-color:#008a00"></button>
admin\index.php:786:                <button data-color="#0066cc" style="background-color:#0066cc"></button>
admin\index.php:787:                <button data-color="#9933cc" style="background-color:#9933cc"></button>
admin\index.php:788:                <button data-color="#f39c12" style="background-color:#f39c12"></button>
admin\index.php:789:                <button data-color="#e74c3c" style="background-color:#e74c3c"></button>
admin\index.php:790:                <button data-color="#3498db" style="background-color:#3498db"></button>
admin\themes_admin.php:100:                        <div class="theme-preview" style="background: <?= $theme['colors']['--bg'] ?>">
admin\themes_admin.php:102:                                <div class="preview-panel" style="
admin\themes_admin.php:106:                                    <div class="preview-text long" style="background: <?= $theme['colors']['--text'] ?>">

admin\themes_admin.php:107:                                    <div class="preview-text medium" style="background: <?= $theme['colors']['--muted'] ?>; opacity: 0.5">

admin\themes_admin.php:108:                                    <div class="preview-text short" style="background: <?= $theme['colors']['--muted'] ?>; opacity: 0.3">

admin\themes_admin.php:109:                                    <div class="preview-button" style="background: <?= $theme['colors']['--accent'] ?>">

admin\themes_admin.php:111:                                <div class="preview-panel" style="
admin\themes_admin.php:115:                                    <div class="preview-text medium" style="background: <?= $theme['colors']['--text'] ?>">

admin\themes_admin.php:116:                                    <div class="preview-text long" style="background: <?= $theme['colors']['--muted'] ?>; opacity: 0.5">

admin\themes_admin.php:117:

admin\themes_admin.php:118:                                        <div style="flex: 1; height: 16px; background: <?= $theme['colors']['--warning'] ?>; border-radius: 3px;">

admin\themes_admin.php:119:                                        <div style="flex: 1; height: 16px; background: <?= $theme['colors']['--danger'] ?>; border-radius: 3px;">

admin\themes_admin.php:130:                                <div class="color-dot" style="background: <?= $theme['colors']['--bg'] ?>" data-color="Fond">

admin\themes_admin.php:131:                                <div class="color-dot" style="background: <?= $theme['colors']['--panel'] ?>" data-color="Panneau">

admin\themes_admin.php:132:                                <div class="color-dot" style="background: <?= $theme['colors']['--text'] ?>" data-color="Texte">

admin\themes_admin.php:133:                                <div class="color-dot" style="background: <?= $theme['colors']['--accent'] ?>" data-color="Accent">

admin\themes_admin.php:134:                                <div class="color-dot" style="background: <?= $theme['colors']['--warning'] ?>" data-color="Alerte">

admin\themes_admin.php:135:                                <div class="color-dot" style="background: <?= $theme['colors']['--danger'] ?>" data-color="Danger">

admin\themes_admin.php:140:                                    <button type="button" class="annadmin-btn annadmin-btn-primary" disabled style="flex: 1;">
admin\themes_admin.php:146:                                            style="flex: 1;">
admin\test_logique.php:50:    echo "
";
admin\test_logique.php:87:        echo "
✅ TEST RÉUSSI
";
admin\test_logique.php:89:        echo "
❌ TEST ÉCHOUÉ
";
admin\reset_password.php:138:

admin\reset_password.php:175:

admin\reset_password.php:215:

admin\reset_password.php:231:

admin\reset_password.php:236:                    <a href="<?= htmlspecialchars($loginUrl) ?>" class="annadmin-btn annadmin-btn-primary annadmin-btn-full" style="display: block; text-align: center; text-decoration: none;">
admin\themes_unified_admin.php:153:                            <div class="theme-preview" style="
admin\themes_unified_admin.php:160:

admin\themes_unified_admin.php:161:                                    <div style="
admin\themes_unified_admin.php:166:
admin\themes_unified_admin.php:221:                        <div class="color-preview" style="
admin\themes_unified_admin.php:242:                            <form method="POST" style="margin-top: 8px;">
admin\themes_unified_admin.php:258:
Ajouter une couleur personnalisée

admin\themes_unified_admin.php:338:

admin\ui_admin.php:213:

admin\ui_admin.php:215:

admin\ui_admin.php:228:

admin\ui_admin.php:252:

admin\ui_admin.php:266:                 class="annadmin-input" style="max-width: 150px;">
admin\ui_admin.php:267:

admin\ui_admin.php:276:

admin\ui_admin.php:283:                 class="annadmin-input" style="max-width: 150px;">
admin\ui_admin.php:284:

admin\ui_admin.php:293:                 class="annadmin-input" style="max-width: 150px;">
admin\ui_admin.php:294:

admin\ui_admin.php:303:                 class="annadmin-input" style="max-width: 150px;">
admin\ui_admin.php:304:

admin\ui_admin.php:314:

admin\ui_admin.php:332:

admin\ui_admin.php:353:

admin\ui_admin.php:363:

admin\ui_admin.php:372:

admin\ui_admin.php:374:

admin\ui_admin.php:379:

admin\ui_admin.php:385:

admin\ui_admin.php:386:

admin\ui_admin.php:387:            📋 Annonces actives disponibles (cliquez pour ajouter)
admin\ui_admin.php:389:

admin\ui_admin.php:396:                 style="display: flex; align-items: center; gap: 10px; background: white; padding: 8px 12px; border-radius: 6px; border-left: 3px solid #3b82f6; cursor: pointer; transition: all 0.2s;">
admin\ui_admin.php:397:
admin\ui_admin.php:400:
admin\ui_admin.php:403:
admin\ui_admin.php:406:              ➕
admin\ui_admin.php:413:

admin\ui_admin.php:418:

admin\ui_admin.php:430:

admin\ui_admin.php:442:

admin\ui_admin.php:443:
📁 Informations techniques

admin\ui_admin.php:444:

admin\ui_admin.php:446:
admin\ui_admin.php:504:
admin\ui_admin.php:507:
admin\ui_admin.php:510:          ×
admin\wiki\index.html:88:


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
<?php
/**
 * annonces_theme_admin.php - Administration des th��mes
 * Gestion des variantes de couleurs pour les annonces
 */

require_once __DIR__.'/config_annonces.php';
require_once __DIR__.'/auth.php';
require_once __DIR__.'/helpers.php';

// VǸrification de l'authentification
requireAuth('Admin �?" Th��me');

// Paths
$jsonPath = __DIR__.'/data/annonces_theme.json';
@is_dir(dirname($jsonPath)) || @mkdir(dirname($jsonPath), 0775, true);

// Load overrides
$overrides = read_json($jsonPath);

// POST processing
$flash = '';
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && verifyCsrf($_POST['csrf'] ?? '')) {
  $action = $_POST['action'] ?? 'save';

  if ($action === 'add') {
    $key = validate_key($_POST['key'] ?? '');
    if ($key !== false) {
      if (!isset($overrides[$key])) {
        $overrides[$key] = ['bg'=>'#F7F9FC','border'=>'#D9E1EC','text'=>'#0B1020'];
        write_json($jsonPath, $overrides);
        $flash = "Variante '{$key}' ajoutǸe.";
        redirect($_SERVER['PHP_SELF'].'?ok=1');
      } else {
        $flash = "Cette clǸ existe dǸj��.";
      }
    } else {
      $flash = "ClǸ invalide (3-24 caract��res alphanumǸriques).";
    }
  }
  elseif ($action === 'delete') {
    $key = $_POST['del_key'] ?? ($_POST['key'] ?? '');
    if ($key !== '' && isset($overrides[$key])) {
      unset($overrides[$key]);
      write_json($jsonPath, $overrides);
      $flash = "Variante '{$key}' supprimǸe.";
      redirect($_SERVER['PHP_SELF'].'?ok=1');
    }
  }
  else { // save
    $next = is_array($overrides) ? $overrides : [];
    $rows = $_POST['theme'] ?? [];

    if (is_array($rows)) {
      foreach ($rows as $kExact => $v) {
        $key = trim((string)$kExact);
        if ($key === '' || !preg_match('~^[a-z0-9_-]{3,24}$~i', $key)) continue;

// Lire d'abord le color picker (si prǸsent), sinon le champ texte
$bgHex = normalize_hex_color($_POST['theme_color_bg'][$kExact]     ?? ($v['bg']     ?? ''));
$bdHex = normalize_hex_color($_POST['theme_color_border'][$kExact] ?? ($v['border'] ?? ''));
$txHex = normalize_hex_color($_POST['theme_color_text'][$kExact]   ?? ($v['text']   ?? ''));

        // Fallback aux color pickers si champs texte vides
        if ($bgHex === '' && isset($_POST['theme_color_bg'][$kExact])) {
          $bgHex = normalize_hex_color($_POST['theme_color_bg'][$kExact]);
        }
        if ($bdHex === '' && isset($_POST['theme_color_border'][$kExact])) {
          $bdHex = normalize_hex_color($_POST['theme_color_border'][$kExact]);
        }
        if ($txHex === '' && isset($_POST['theme_color_text'][$kExact])) {
          $txHex = normalize_hex_color($_POST['theme_color_text'][$kExact]);
        }

        $old = $next[$key] ?? ['bg'=>'','border'=>'','text'=>''];
        if ($bgHex !== '') $old['bg'] = $bgHex;
        if ($bdHex !== '') $old['border'] = $bdHex;
        if ($txHex !== '') $old['text'] = $txHex;

        $next[$key] = $old;
      }
    }

    $overrides = $next;
    $ok = write_json($jsonPath, $overrides);
    $flash = $ok !== false ? 'Modifications enregistrǸes.' : "�%chec d'Ǹcriture.";
    redirect($_SERVER['PHP_SELF'].'?ok=1');
  }
}

?><!doctype html>

  <meta charset="utf-8">
  <title>Admin �?" Th��me</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <?php require __DIR__ . '/partials/admin_styles.php'; ?>

Admin �?" Th��me

      �Y?� Front
      �Y"< Annonces
      �Y�� UI

  <?php if (!empty($_GET['ok'])): ?>
    <?= display_flash('Sauvegarde effectuǸe.', 'success') ?>
  <?php endif; ?>

  <?php if ($flash): ?>
    <?= display_flash($flash, strpos($flash, '�%chec') !== false ? 'error' : 'success') ?>
  <?php endif; ?>

Variantes de th��me

    <form method="post" class="annadmin-row">
      <input type="hidden" name="csrf" value="<?= h($CSRF) ?>">
      <input type="hidden" name="action" value="add">
      Nouvelle clǸ
      <input class="annadmin-input annadmin-input-inline"
             name="key"
             placeholder="ma_couleur"
             pattern="^[a-zA-Z0-9_-]{3,24}$"
             required
             style="width: 200px">
      <button class="annadmin-btn annadmin-btn-primary" type="submit">Ajouter</button>
    </form>

�%dition

    <form method="post">
      <input type="hidden" name="csrf" value="<?= h($CSRF) ?>">
      <input type="hidden" name="action" value="save">

              ClǸ
              Fond
              Hex
              Bordure
              Hex
              Texte
              Hex
              Actions

          <?php foreach ($overrides as $k => $vals):
            $bg = $vals['bg'] ?? '#F7F9FC';
            $bd = $vals['border'] ?? '#D9E1EC';
            $tx = $vals['text'] ?? '#0B1020';
          ?>

                <?= h($k) ?>

                <input type="color"
                       name="theme_color_bg[<?= h($k) ?>]"
                       value="<?= h($bg) ?>"
                       class="annadmin-input annadmin-input-inline"
                       style="width: 50px; height: 36px; padding: 2px;">

                <input class="annadmin-input annadmin-input-inline"
                       type="text"
                       name="theme[<?= h($k) ?>][bg]"
                       value="<?= h($bg) ?>"
                       placeholder="#RRGGBB"
                       pattern="^(#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}))?$"
                       autocomplete="off"
                       spellcheck="false"
                       style="width: 100px">

                <input type="color"
                       name="theme_color_border[<?= h($k) ?>]"
                       value="<?= h($bd) ?>"
                       class="annadmin-input annadmin-input-inline"
                       style="width: 50px; height: 36px; padding: 2px;">

                <input class="annadmin-input annadmin-input-inline"
                       type="text"
                       name="theme[<?= h($k) ?>][border]"
                       value="<?= h($bd) ?>"
                       placeholder="#RRGGBB"
                       pattern="^(#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}))?$"
                       autocomplete="off"
                       spellcheck="false"
                       style="width: 100px">

                <input type="color"
                       name="theme_color_text[<?= h($k) ?>]"
                       value="<?= h($tx) ?>"
                       class="annadmin-input annadmin-input-inline"
                       style="width: 50px; height: 36px; padding: 2px;">

                <input class="annadmin-input annadmin-input-inline"
                       type="text"
                       name="theme[<?= h($k) ?>][text]"
                       value="<?= h($tx) ?>"
                       placeholder="#RRGGBB"
                       pattern="^(#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}))?$"
                       autocomplete="off"
                       spellcheck="false"
                       style="width: 100px">

                <input type="hidden" name="del_key" value="<?= h($k) ?>">
                <button class="annadmin-btn annadmin-btn-small annadmin-btn-danger"
                        type="submit"
                        name="action"
                        value="delete"
                        formaction="annonces_theme_admin.php"
                        formmethod="post"
                        formnovalidate
                        onclick="return confirm('Supprimer la variante <?= h($k) ?> ?')">
                  Supprimer
                </button>

          <?php endforeach; ?>

        <button class="annadmin-btn annadmin-btn-primary" type="submit" name="action" value="save">
          �Y'� Enregistrer
        </button>
        ��? Retour annonces

    </form>


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
/*!
 * Styles admin - bundle principal
 * Les styles sont dǸsormais dǸcoupǸs en modules :
 *  1. parts/foundation.css      ��' reset, typographie, formulaires, cartes
 *  2. parts/responsive-base.css ��' r��gles responsives + impression
 *  3. parts/preview.css         ��' bloc d�?Taper��u Ǹcran hall
 *  4. parts/header.css          ��' en-tǦte + navigation (desktop & mobile)
 *
 * L�?Tordre des imports respecte l�?Tancien fichier monolithique.
 * Chaque module peut Ǧtre ǸditǸ isolǸment sans impacter les autres zones.
 */
@import url('parts/foundation.css');
@import url('parts/responsive-base.css');
@import url('parts/preview.css');
@import url('parts/header.css');


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
/**
 * admin.css - Styles unifiǸs pour l'administration des annonces
 */

/* ========================================
   Reset & Variables CSS
======================================== */
:root {
    /* Couleurs principales */
    --color-primary: #0b3d91;
    --color-primary-dark: #0b1020;
    --color-secondary: #445b8a;
    --color-danger: #dc3545;
    --color-success: #28a745;
    --color-warning: #ffc107;
    --color-info: #17a2b8;

    /* Couleurs de base */
    --color-bg: #f0f4f9;
    --color-panel: #ffffff;
    --color-border: #d9e1ec;
    --color-border-light: #cdd6e1;
    --color-text: #0b1020;
    --color-muted: #6b7280;

    /* Espacement */
    --spacing-xs: 4px;
    --spacing-sm: 8px;
    --spacing-md: 16px;
    --spacing-lg: 24px;
    --spacing-xl: 32px;

    /* Bordures */
    --radius-sm: 8px;
    --radius-md: 10px;
    --radius-lg: 12px;
    --radius-pill: 999px;

    /* Transitions */
    --transition-fast: 0.2s ease;
    --transition-normal: 0.3s ease;
}

/* Reset de base */
.annadmin-reset * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
/* ========================================
   Smooth scroll pour les ancres
======================================== */
html {
    scroll-behavior: smooth;
}

/* Highlight de la section d'Ǹdition */
#editform {
    scroll-margin-top: 20px; /* Espace avec le haut de la page */
}

/* Animation douce quand on Ǹdite */
#editform.editing {
    animation: highlight-form 0.5s ease-in-out;
}

@keyframes highlight-form {
    0% {
        background-color: var(--color-panel);
        transform: scale(1);
    }
    50% {
        background-color: rgba(59, 130, 246, 0.1);
        transform: scale(1.01);
    }
    100% {
        background-color: var(--color-panel);
        transform: scale(1);
    }
}
/* ========================================
   Structure de base
======================================== */
.annadmin-body {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Arial, sans-serif;
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.6;
    margin: 0;
}

/* ========================================
   En-tǦte
======================================== */
.annadmin-header {
    background: var(--color-primary-dark);
    color: white;
    padding: var(--spacing-md) var(--spacing-lg);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.annadmin-header-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--spacing-md);
}

.annadmin-title {
    font-size: 20px;
    font-weight: 600;
    margin: 0;
}

.annadmin-nav {
    display: flex;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
    align-items: center;
}

/* ========================================
   Container principal
======================================== */
.annadmin-wrap {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--spacing-lg);
}

/* ========================================
   Cartes
======================================== */
.annadmin-card {
    background: var(--color-panel);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-lg);
    margin-bottom: var(--spacing-lg);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.annadmin-card h2 {
    font-size: 18px;
    margin-bottom: var(--spacing-md);
    color: var(--color-text);
}

.annadmin-card h3 {
    font-size: 16px;
    margin-bottom: var(--spacing-sm);
    color: var(--color-text);
}

/* ========================================
   Formulaires
======================================== */
.annadmin-form-group {
    margin-bottom: var(--spacing-md);
}

.annadmin-form-group label {
    display: block;
    margin-bottom: var(--spacing-xs);
    font-weight: 500;
    color: var(--color-text);
}

.annadmin-input,
.annadmin-select,
.annadmin-textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-sm);
    font-size: 14px;
    font-family: inherit;
    transition: border-color var(--transition-fast);
}

.annadmin-input:focus,
.annadmin-select:focus,
.annadmin-textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(11, 61, 145, 0.1);
}

.annadmin-select.loading {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path fill="none" stroke="%230b3d91" stroke-width="2" d="M10,3 a7,7 0 1,1 0,14"><animateTransform attributeName="transform" type="rotate" from="0 10 10" to="360 10 10" dur="1s" repeatCount="indefinite"/></path></svg>');
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 20px 20px;
    padding-right: 40px;
}

.annadmin-textarea {
    min-height: 100px;
    resize: vertical;
}

/* Inputs inline */
.annadmin-input-inline {
    width: auto;
    display: inline-block;
}

/* ========================================
   RangǸes flexibles
======================================== */
.annadmin-row {
    display: flex;
    gap: var(--spacing-md);
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: var(--spacing-md);
}

.annadmin-row label {
    min-width: 160px;
    margin-bottom: 0;
}

/* ========================================
   Boutons
======================================== */
.annadmin-btn {
    display: inline-block;
    padding: 10px 16px;
    border: none;
    border-radius: var(--radius-md);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: all var(--transition-fast);
    background: var(--color-secondary);
    color: white;
}

.annadmin-btn:hover {
    filter: brightness(1.1);
    transform: translateY(-1px);
}

.annadmin-btn:active {
    transform: translateY(0);
}

/* Variantes de boutons */
.annadmin-btn-primary,
.annadmin-btn.primary {
    background: var(--color-primary);
    color: white;
}

.annadmin-btn-secondary,
.annadmin-btn.secondary {
    background: var(--color-secondary);
    color: white;
}

.annadmin-btn-danger,
.annadmin-btn.danger {
    background: var(--color-danger);
    color: white;
}

.annadmin-btn-success,
.annadmin-btn.success {
    background: var(--color-success);
    color: white;
}

.annadmin-btn-small,
.annadmin-btn.small {
    padding: 6px 12px;
    font-size: 12px;
}

.annadmin-btn-full {
    width: 100%;
}

/* Pills (boutons arrondis) */
.annadmin-btn.pill,
.annadmin-pill {
    border-radius: var(--radius-pill);
    padding: 6px 12px;
    font-size: 12px;
    background: #fbfcfe;
    color: var(--color-text);
    border: 1px solid var(--color-border);
}

.annadmin-pill:hover {
    background: var(--color-bg);
}

/* ========================================
   Tables
======================================== */
.annadmin-table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--spacing-md) 0;
}

.annadmin-table thead {
    background: var(--color-bg);
}

.annadmin-table th {
    padding: var(--spacing-sm) var(--spacing-md);
    text-align: left;
    font-weight: 600;
    color: var(--color-text);
    border-bottom: 2px solid var(--color-border);
}

.annadmin-table td {
    padding: var(--spacing-sm) var(--spacing-md);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

.annadmin-table tbody tr:hover {
    background: rgba(0, 0, 0, 0.02);
}

.annadmin-table tbody tr.row--inactive {
    opacity: 0.6;
}

/* Table responsive */
.annadmin-table-wrap {
    overflow-x: auto;
    margin: 0 -var(--spacing-sm);
    padding: 0 var(--spacing-sm);
}

/* ========================================
   Toggles (Switches)
======================================== */
.toggle {
    display: inline-block;
    position: relative;
    width: 48px;
    height: 24px;
    cursor: pointer;
    vertical-align: middle;
}

.toggle input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
}

.toggle .knob {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #ccc;
    border-radius: 24px;
    transition: var(--transition-fast);
    width: 50px;
}

.toggle .knob:before {
    position: absolute;
    content: "";
    height: 18px;
    width: 18px;
    left: 3px;
    bottom: 3px;
    background: white;
    border-radius: 50%;
    transition: var(--transition-fast);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.toggle.on .knob {
    background: var(--color-success);
}

.toggle.on .knob:before {
    transform: translateX(24px);
}

.toggle:hover .knob {
    filter: brightness(0.95);
}

.toggle.loading {
    opacity: 0.5;
    pointer-events: none;
}

.toggle.loading .knob:before {
    animation: pulse 1s infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* Flash animation pour toggle */
.toggle.flash .knob {
    animation: flash-bg 0.45s;
}

@keyframes flash-bg {
    0%, 100% { filter: brightness(1); }
    50% { filter: brightness(1.3); }
}

/* ========================================
   Color chips (sǸlecteur de couleurs)
======================================== */
.color-chips {
    display: flex;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
}

.color-chip {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: 2px solid transparent;
    cursor: pointer;
    transition: all var(--transition-fast);
    position: relative;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.color-chip:hover {
    transform: scale(1.1);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.color-chip.active {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(11, 61, 145, 0.2);
}

.color-chip.active::after {
    content: '�o"';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-weight: bold;
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
}

.color-chip:not([data-color]) {
    background: var(--color-muted, #6b7280);
    border-color: var(--color-border, #9ca3af);
}

/* ========================================
   Grille d'annonces
======================================== */
.ann-grid {
    display: grid;
    gap: var(--ann-gap, 16px);
}

.ann-grid.layout-grid-2x2 {
    grid-template-columns: repeat(2, 1fr);
}

.ann-grid.layout-grid-3plus3 {
    grid-template-columns: repeat(3, 1fr);
}

.ann-grid.layout-grid-1plus2 {
    grid-template-columns: repeat(2, 1fr);
}

.ann-grid.layout-grid-1plus2 .ann:nth-child(1) {
    grid-column: 1 / span 2;
}

.ann-grid.layout-grid-2plus1 {
    grid-template-columns: repeat(2, 1fr);
}

.ann-grid.layout-grid-2plus1 .ann:nth-last-child(1) {
    grid-column: 1 / span 2;
}

.ann-grid.layout-grid-1plus3 {
    grid-template-columns: repeat(3, 1fr);
}

.ann-grid.layout-grid-1plus3 .ann:nth-child(1) {
    grid-column: 1 / -1;
}

.ann-grid.layout-grid-3plus1 {
    grid-template-columns: repeat(3, 1fr);
}

.ann-grid.layout-grid-3plus1 .ann:nth-last-child(1) {
    grid-column: 1 / -1;
}

.ann-grid.layout-grid-full {
    grid-template-columns: 1fr;
}

.ann-grid .ann.span-full {
    grid-column: span 2;
}

.ann-grid .ann.span-row,
.ann-grid .ann.takeover {
    grid-column: 1 / -1;
}

/* ========================================
   Alertes & Messages
======================================== */
.annadmin-alert {
    padding: var(--spacing-md);
    border-radius: var(--radius-sm);
    margin-bottom: var(--spacing-md);
    border: 1px solid;
}

.annadmin-alert.ok,
.annadmin-alert.success {
    background: #eaf6ff;
    border-color: #cfe6ff;
    color: #004085;
}

.annadmin-alert.error {
    background: #fff5f5;
    border-color: #feb2b2;
    color: #9b2c2c;
}

.annadmin-alert.warning {
    background: #fffdf7;
    border-color: #fed7aa;
    color: #92400e;
}

/* ========================================
   Toast notifications
======================================== */
#toast {
    position: fixed;
    top: 20px;
    right: 20px;
    background: var(--color-primary-dark);
    color: white;
    padding: 12px 20px;
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    opacity: 0;
    transform: translateY(-20px);
    transition: all var(--transition-normal);
    z-index: 9999;
    pointer-events: none;
}

#toast.show {
    opacity: 1;
    transform: translateY(0);
}

/* ========================================
   Login page
======================================== */
.annadmin-login-container {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-lg);
}

.annadmin-login-card {
    background: var(--color-panel);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-xl);
    width: 100%;
    max-width: 400px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.annadmin-login-title {
    font-size: 24px;
    margin-bottom: var(--spacing-lg);
    text-align: center;
}

.annadmin-login-form .annadmin-form-group:last-child {
    margin-bottom: 0;
    margin-top: var(--spacing-lg);
}

.login-error {
    background: #fed7d7;
    color: #742a2a;
    padding: 12px;
    border-radius: 6px;
    margin-bottom: 16px;
    text-align: center;
    font-size: 14px;
}

.forgot-password-link {
    text-align: center;
    margin-top: 16px;
}

.forgot-password-link a {
    color: #4299e1;
    text-decoration: none;
    font-size: 14px;
}

.forgot-password-link a:hover {
    text-decoration: underline;
}

/* ========================================
   Utilities
======================================== */
.annadmin-muted,
.muted {
    color: var(--color-muted);
    font-size: 0.875em;
}

.annadmin-hint,
.hint {
    font-size: 12px;
    color: var(--color-muted);
    line-height: 1.4;
}

.annadmin-text-center {
    text-align: center;
}

.annadmin-text-right {
    text-align: right;
}

.annadmin-mt-sm { margin-top: var(--spacing-sm); }
.annadmin-mt-md { margin-top: var(--spacing-md); }
.annadmin-mt-lg { margin-top: var(--spacing-lg); }

.annadmin-mb-sm { margin-bottom: var(--spacing-sm); }
.annadmin-mb-md { margin-bottom: var(--spacing-md); }
.annadmin-mb-lg { margin-bottom: var(--spacing-lg); }

/* Champ invalide visuel (optionnel) */
.is-invalid {
  outline: 2px solid #e53935;
}

/* Code inline */
code {
    background: var(--color-bg);
    padding: 2px 6px;
    border-radius: 4px;
    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
    font-size: 0.9em;
}


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
<?php
/**
 * Widget d�?Taffichage des annonces (front)
 * - Lit /data/ui.json pour le layout + vitesses par dǸfaut + overrides
 * - Respecte $ANN_PATH (donnǸes) et $ANN_THEME (couleurs)
 * - Pas de renommage des variables existantes
 */

require_once __DIR__.'/config_annonces.php';
require_once __DIR__.'/annonces_theme.php'; // expose $ANN_THEME

// Helper Ǹchappement HTML
if (!function_exists('h')) {
  function h(?string $s): string {
    return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
  }
}

/* ============================================================
 * UI (layout + vitesses) �?" lecture de /data/ui.json
 * ============================================================ */
$UI_CONF_PATH = __DIR__ . '/data/ui.json';
$UI = [
  'annonces_layout' => [
    'template'     => 'grid-2x2',   // grid-2x2 | grid-3plus3 | grid-1plus2 | grid-2plus1 | grid-1plus3 | grid-3plus1 | grid-full
    'gap'          => 16,
    'order'        => [],
    'takeover_id'  => null,
    'rowfull_id'   => null,
  ],
  'annonces_defaults' => [
    'maxlines' => 5,
    'speed'    => 30,
    'pause'    => 1500,
  ],
  'annonces_overrides' => []
];
if (is_file($UI_CONF_PATH)) {
  $raw = @file_get_contents($UI_CONF_PATH);
  $tmp = json_decode($raw, true);
  if (is_array($tmp)) {
    foreach ($UI as $k => $v) {
      if (isset($tmp[$k]) && is_array($tmp[$k])) {
        $UI[$k] = array_replace($UI[$k], $tmp[$k]);
      }
    }
  }
}
$UI_LAYOUT   = $UI['annonces_layout'];
$UI_DEFAULTS = $UI['annonces_defaults'];
$UI_OVR      = $UI['annonces_overrides'];
$LAYOUT_TPL  = $UI_LAYOUT['template'] ?? 'grid-2x2';
$LAYOUT_GAP  = (int)($UI_LAYOUT['gap'] ?? 16);
$ORDER_IDS   = is_array($UI_LAYOUT['order'] ?? null) ? $UI_LAYOUT['order'] : [];
$TAKEOVER_ID = $UI_LAYOUT['takeover_id'] ?? null;
$ROWFULL_ID  = $UI_LAYOUT['rowfull_id'] ?? null;

/* ============================================================
 * Helpers markdown "safe" + IO + normalisation
 * ============================================================ */
function ann__md_safe(string $text): string {
  // 1) Ǹchappe tout HTML
  $x = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');

  // 2) Traiter les titres Markdown en gardant trace des lignes traitǸes
  $lines = explode("\n", $x);
  $processed_lines = array();
  $skip_br = array(); // lignes pour lesquelles il ne faut pas ajouter de

  foreach($lines as $i => $line) {
    // DǸtecter et traiter les titres
    if (preg_match('/^# (.+?)$/', $line, $matches)) {
      $processed_lines[$i] = '
' . $matches[1] . '
';
      $skip_br[$i] = true; // Pas besoin de
 apr��s un titre
    }
    else if (preg_match('/^## (.+?)$/', $line, $matches)) {
      $processed_lines[$i] = '
' . $matches[1] . '
';
      $skip_br[$i] = true;
    }
    else if (preg_match('/^### (.+?)$/', $line, $matches)) {
      $processed_lines[$i] = '
' . $matches[1] . '
';
      $skip_br[$i] = true;
    }
    else {
      $processed_lines[$i] = $line;
    }
  }

  // Reconstituer le texte
  $x = implode("\n", $processed_lines);

  // 3) Traitement du markdown standard
  $patterns = [
    '/\*\*(.+?)\*\*/s',   // **bold**
    '/\*(.+?)\*/s',       // *italic*
    '/__(.+?)__/s',       // __underline__
    '/~~(.+?)~~/s',       // ~~strike~~

    // Balises personnalisǸes
    '/\[color=([#a-zA-Z0-9]+)\](.+?)\[\/color\]/s',  // [color=#ff0000]texte[/color]
    '/\[size=([a-zA-Z0-9\-]+)\](.+?)\[\/size\]/s',   // [size=large]texte[/size]
  ];

  $repl = [
    '$1',
    '$1',
    '$1',
    '<s>$1</s>',

    // Remplacements
    '$2',
    '$2',
  ];

  $x = preg_replace($patterns, $repl, $x);

  // 4) Gestion intelligente des retours �� la ligne
  $lines = explode("\n", $x);
  $result = '';

  foreach($lines as $i => $line) {
    $result .= $line;
    // Ajouter
 seulement si nǸcessaire (pas apr��s les titres)
    if ($i < count($lines) - 1 && !isset($skip_br[$i])) {
      $result .= '
';
    }
  }

  return $result;
}
function ann__read_all($path){
  if (!file_exists($path)) return [];
  $raw = file_get_contents($path);
  $data = json_decode($raw, true);
  return is_array($data) ? $data : [];
}

function ann__date_to_ts(?string $s): int {
  $s = trim((string)$s);
  if ($s === '') return 0;
  if (preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $s, $m)) {
    return mktime(0, 0, 0, (int)$m[2], (int)$m[1], (int)$m[3]);
  }
  $t = strtotime($s);
  return $t !== false ? $t : 0;
}

function ann__validate_all($arr, array $theme){
  if (!is_array($arr)) return [];
  $out = [];
  foreach ($arr as $a){
    if (!is_array($a)) continue;
    $item = [];
    $item['id']           = (string)($a['id'] ?? bin2hex(random_bytes(6)));
    $item['title']        = trim((string)($a['title'] ?? ''));
    $item['text']         = (string)($a['text'] ?? '');
    $item['date_visible'] = trim((string)($a['date_visible'] ?? ''));
    if ($item['date_visible'] && !preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $item['date_visible'])) {
      $item['date_visible'] = '';
    }
    // couleur autorisǸe
    $color = $a['color'] ?? 'neutral';
    $allowed = array_keys($theme);
    $item['color'] = in_array($color, $allowed, true) ? $color : 'neutral';

    // boolǸens tolǸrants
    $toBool = static function($v){ return filter_var($v, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? (bool)$v; };
    $item['pinned']    = $toBool($a['pinned'] ?? false);
    $item['active']    = $toBool($a['active'] ?? true);
    $item['show_date'] = $toBool($a['show_date'] ?? true);

    $created = $a['created_at'] ?? null;
    $updated = $a['updated_at'] ?? null;
    $item['created_at'] = $created ?: date('c');
    $item['updated_at'] = $updated ?: $item['created_at'];

    $out[] = $item;
  }
  return $out;
}

/* ============================================================
 * Styles de grille �?" injectǸs une seule fois
 * ============================================================ */
function ann__styles_once(){
  static $done = false;
  if ($done) return;
  $done = true;
  // Les styles d'affichage des annonces sont dǸsormais inclus via les feuilles CSS.
}

/* ============================================================
 * Rendu
 * ============================================================ */
/**
 * Rend les annonces (grille + cartes)
 * $path   : chemin JSON des annonces
 * $limit  : nb max de cartes
 * $colors : $ANN_THEME
 */
function ann__render_front($path, $limit, $colors){
  global $ANN_THEME, $UI_DEFAULTS, $UI_OVR, $LAYOUT_TPL, $LAYOUT_GAP, $ORDER_IDS, $TAKEOVER_ID, $ROWFULL_ID;

  // 1) Lecture + normalisation
  $all = ann__read_all($path);
  $all = ann__validate_all($all, $colors);

  // 2) Filtrer actives
  $active = array_values(array_filter($all, fn($a)=>!empty($a['active'])));

  // 3) Tri (ǸpinglǸes, actives, date_visible desc, updated_at desc, titre A��'Z)
  usort($active, function($a, $b) {
    $toBool = static function($v){ return filter_var($v, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? (bool)$v; };
    $toTs = static function($s){
      $s = trim((string)$s);
      if (preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $s, $m)) return mktime(0,0,0,(int)$m[2],(int)$m[1],(int)$m[3]);
      return strtotime($s) ?: 0;
    };
    if (($pa=$toBool($a['pinned']??false)) !== ($pb=$toBool($b['pinned']??false))) return $pb <=> $pa;
    if (($aa=$toBool($a['active']??true)) !== ($bb=$toBool($b['active']??true))) return $bb <=> $aa;
    if (($ta=$toTs($a['date_visible']??'')) !== ($tb=$toTs($b['date_visible']??''))) return $tb <=> $ta;
    $ua = strtotime($a['updated_at'] ?? $a['created_at'] ?? '1970-01-01');
    $ub = strtotime($b['updated_at'] ?? $b['created_at'] ?? '1970-01-01');
    if ($ua !== $ub) return $ub <=> $ua;
    return strcasecmp($a['title'] ?? '', $b['title'] ?? '');
  });

  // 4) RǸindexation par id
  $byId = [];
  foreach ($active as $it) {
    if (!empty($it['id'])) $byId[(string)$it['id']] = $it;
  }

  // 5.a) APPLICATION DE L'ORDRE PERSONNALIS�% (si dǸfini)
  if (!empty($ORDER_IDS) && is_array($ORDER_IDS)) {
    $ordered = [];
    $used_ids = [];

    // D'abord, ajouter les annonces dans l'ordre spǸcifiǸ
    foreach ($ORDER_IDS as $custom_id) {
      $custom_id = trim((string)$custom_id);
      if ($custom_id !== '' && isset($byId[$custom_id])) {
        $ordered[] = $byId[$custom_id];
        $used_ids[$custom_id] = true;
      }
    }

    // Ensuite, ajouter les annonces non spǸcifiǸes dans leur ordre naturel
    foreach ($active as $it) {
      $id = (string)($it['id'] ?? '');
      if (!isset($used_ids[$id])) {
        $ordered[] = $it;
      }
    }

    // Remplacer le tableau $active par le tableau ordonnǸ
    $active = $ordered;
  }

  // 5.b) Ajustement simple selon template + rowfull_id
  $tpl = strtolower((string)$LAYOUT_TPL);
  if (!empty($ROWFULL_ID)) {
    // RǸindex
    $idmap = [];
    foreach ($active as $it) {
      $idmap[(string)($it['id'] ?? '')] = $it;
    }
    if (isset($idmap[(string)$ROWFULL_ID])) {
      $rowfull = $idmap[(string)$ROWFULL_ID];
      // Retire l'ǸlǸment o�� il est actuellement
      $active = array_values(array_filter($active, fn($x) => (string)($x['id'] ?? '') !== (string)$ROWFULL_ID));

      // Place selon le template
      if ($tpl === 'grid-1plus2' || $tpl === 'grid-1plus3') {
        array_unshift($active, $rowfull); // plein en tǦte
      } elseif ($tpl === 'grid-2plus1' || $tpl === 'grid-3plus1') {
        $active[] = $rowfull; // plein en fin
      } else {
        // autres templates : ne change pas l'ordre
        array_unshift($active, $rowfull);
      }
    }
  }
// 5.c) Gestion du takeover (prioritaire sur tout)
if (!empty($TAKEOVER_ID)) {
    // RǸindexation par ID pour accǸder facilement �� l'annonce takeover
    $idmap = [];
    foreach ($active as $it) {
        $idmap[(string)($it['id'] ?? '')] = $it;
    }

    // Si l'annonce takeover existe, ne conserver que celle-l��
    if (isset($idmap[(string)$TAKEOVER_ID])) {
        $active = [$idmap[(string)$TAKEOVER_ID]];
        // En mode takeover, on force le template en grid-full
        $tpl = 'grid-full';
        $LAYOUT_TPL = 'grid-full';
        $layoutClass = 'layout-grid-full';
    }
}
// 5.d) DǸtermination du nombre optimal d'annonces selon le template
function ann__get_optimal_limit($template) {
    switch ($template) {
        case 'grid-full':
            return 1; // Une seule annonce en plein Ǹcran
        case 'grid-2x2':
            return 4; // 2�-2 = 4 annonces
         case 'grid-3plus3':
            return 6; // 3 plus3 = 6 annonces
        case 'grid-1plus2':
            return 3; // 1 grande + 2 petites
        case 'grid-2plus1':
            return 3; // 2 petites + 1 grande
        case 'grid-1plus3':
            return 4; // 1 grande + 3 petites
        case 'grid-3plus1':
            return 4; // 3 petites + 1 grande
        default:
            return 4; // Valeur par dǸfaut
    }
}

// Calculer la limite optimale selon le template
$optimalLimit = ann__get_optimal_limit($tpl);
// Si $limit est fourni explicitement et est infǸrieur �� l'optimal, on le respecte
// sinon on utilise la limite optimale
$effectiveLimit = ($limit > 0 && $limit < $optimalLimit) ? $limit : $optimalLimit;

// 6) Limite (adaptǸe au template)
$slice = array_slice($active, 0, $effectiveLimit);

  // 6) Limite
  $optimalLimit = ann__get_optimal_limit($LAYOUT_TPL);
// Si $limit est fourni explicitement et est infǸrieur �� l'optimal, on le respecte
$actualLimit = ($limit > 0 && $limit < $optimalLimit) ? $limit : $optimalLimit;
$slice = array_slice($active, 0, $actualLimit);

  // 7) Styles (une seule fois)
  ann__styles_once();

  // 8) Conteneur grille
  $layoutClass = 'layout-' . preg_replace('~[^a-z0-9\-]~', '-', strtolower($LAYOUT_TPL));
  $gapPx       = max(0, (int)$LAYOUT_GAP);

  echo '
';

  // 9) Boucle cartes
  foreach ($slice as $a){
    $id  = (string)($a['id'] ?? '');
    $key = array_key_exists($a['color'] ?? 'neutral', $ANN_THEME) ? ($a['color'] ?? 'neutral') : 'neutral';

    // classes carte
    $cls = ['ann','ann-card','ann-'.$key];
    if (!empty($ROWFULL_ID) && $id === (string)$ROWFULL_ID) $cls[] = 'span-row';
    $ovr = isset($GLOBALS['UI_OVR'][$id]) && is_array($GLOBALS['UI_OVR'][$id]) ? $GLOBALS['UI_OVR'][$id] : [];
    if (!empty($ovr['span'])) {
      if ($ovr['span'] === 'full') $cls[] = 'span-full';
      if ($ovr['span'] === 'mega') $cls[] = 'takeover';
    }

    // vitesses/param��tres
    $mx = isset($ovr['maxlines']) ? (int)$ovr['maxlines'] : (int)$GLOBALS['UI_DEFAULTS']['maxlines'];
    $sp = isset($ovr['speed'])    ? (int)$ovr['speed']    : (int)$GLOBALS['UI_DEFAULTS']['speed'];
    $pa = isset($ovr['pause'])    ? (int)$ovr['pause']    : (int)$GLOBALS['UI_DEFAULTS']['pause'];

    $title = h($a['title'] ?? 'Annonce');
    $text  = ann__md_safe($a['text'] ?? '');

    // Date visible (optionnelle)
    $showDate = filter_var($a['show_date'] ?? true, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
    if ($showDate === null) $showDate = (bool)($a['show_date'] ?? true);
    $dv = trim((string)($a['date_visible'] ?? ''));
    if ($dv !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $dv)) { $dv = date('d/m/Y', strtotime($dv)); }
    $dateHtml = ($showDate && $dv!=='') ? ''.h($dv).'' : '';

    echo '
';

      echo '
';
        if (!empty($a['pinned'])) echo '�Y"O';
        echo '
'.$title.'
';
      echo '
'.$dateHtml.'';

      echo '
';
        echo '
'.$text.'
';
      echo '
';

    echo '
';
  }

  echo '
'; // .ann-grid
}

/* ============================================================
 * Appel du widget
 * ============================================================ */
// $ANN_PATH est dǸfini dans config_annonces.php
// $ANN_THEME est dǸfini dans annonces_theme.php
//ann__render_front($ANN_PATH, 4, $ANN_THEME);

/* ============================================================
 * Mode "fragment" pour AJAX (appel direct uniquement)
 * ============================================================ */
if (basename(__FILE__) === basename($_SERVER['SCRIPT_FILENAME'] ?? '')) {
    // Appel direct : on renvoie juste la grille d'annonces
    header('Content-Type: text/html; charset=utf-8');

    // Limite optionnelle en GET (fallback = 6 comme sur le front)
    $limit = isset($_GET['limit']) ? max(1, (int)$_GET['limit']) : 6;

    // $ANN_PATH et $ANN_THEME viennent de config_annonces.php / annonces_theme.php
    ann__render_front($ANN_PATH, $limit, $ANN_THEME);
    exit;
}


@'
from pathlib import Path
import re, json
styles = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            styles.setdefault(match.group(1), set()).add(str(path))
print(len(styles), 'unique style strings')
for style, files in list(styles.items())[:20]:
    print('STYLE:', style)
    for f in list(files)[:3]:
        print('  ', f)
'@ | python -


Output:
Exit code: 0
Wall time: 1.2 seconds
Output:
105 unique style strings
STYLE: width: 200px
   admin\annonces_theme_admin.php
STYLE: width: 50px; height: 36px; padding: 2px;
   admin\annonces_theme_admin.php
STYLE: width: 100px
   admin\annonces_theme_admin.php
STYLE: color:$1
   admin\annonces_widget.php
STYLE: font-size:$1
   admin\annonces_widget.php
STYLE: --ann-gap: '.$gapPx.'px;
   admin\annonces_widget.php
STYLE: background: yellow; padding: 10px; margin: 10px;
   admin\debug_patch.php
STYLE: display: inline;
   admin\hyperadmin.php
STYLE: background: white; padding: 15px; border-radius: 8px; margin-bottom: 15px;
   admin\hyperadmin_forms.php
STYLE: margin-left: 30px; <?= $showReactivateOption ? '' : 'display: none;' ?>
   admin\hyperadmin_forms.php
STYLE: margin-bottom: 1rem; color: #64748b;
   admin\hyperadmin_forms.php
STYLE: grid-template-columns: 1fr 1fr;
   admin\hyperadmin_forms.php
STYLE: color: #ef4444; font-weight: bold;
   admin\hyperadmin_forms.php
STYLE: font-family: monospace; border-left: 4px solid #ef4444; background: #fef2f2;
   admin\hyperadmin_forms.php
STYLE: color: #f97316; font-weight: bold;
   admin\hyperadmin_forms.php
STYLE: font-family: monospace; border-left: 4px solid #f97316; background: #fff7ed;
   admin\hyperadmin_forms.php
STYLE: color: #ca8a04; font-weight: bold;
   admin\hyperadmin_forms.php
STYLE: font-family: monospace; border-left: 4px solid #eab308; background: #fefce8;
   admin\hyperadmin_forms.php
STYLE: color: #3b82f6; font-weight: bold;
   admin\hyperadmin_forms.php
STYLE: font-family: monospace; border-left: 4px solid #3b82f6; background: #eff6ff;
   admin\hyperadmin_forms.php


@'
from pathlib import Path
import re
styles = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            styles.setdefault(match.group(1), []).append(str(path))
for style, files in sorted(styles.items()):
    print(style)
    for f in files:
        print('  ', f)
    print()
'@ | python -


Output:
Exit code: 0
Wall time: 1 seconds
Output:

                                        flex: 1; height: 16px;
                                        background: <?= $color['bg'] ?>;
                                        border: 1px solid <?= $color['border'] ?>;
                                        border-radius: 3px;

   admin\themes_unified_admin.php

                                        width: 40px; height: 20px;
                                        background: <?= $theme['panel_colors']['--accent'] ?>;
                                        border-radius: 4px;

   admin\themes_unified_admin.php

                                        width: 60px; height: 20px;
                                        background: <?= $theme['panel_colors']['--panel'] ?>;
                                        border: 1px solid <?= $theme['panel_colors']['--border'] ?>;
                                        border-radius: 4px;

   admin\themes_unified_admin.php

                                    background: <?= $theme['colors']['--panel'] ?>;
                                    border: 1px solid <?= $theme['colors']['--border'] ?>

   admin\themes_admin.php

                                    background: <?= $theme['colors']['--panel-2'] ?>;
                                    border: 1px solid <?= $theme['colors']['--border'] ?>

   admin\themes_admin.php

                                background: linear-gradient(135deg,
                                    <?= $theme['panel_colors']['--bg'] ?>,
                                    <?= $theme['panel_colors']['--panel'] ?>);
                                border: 1px solid <?= $theme['panel_colors']['--border'] ?>;

   admin\themes_unified_admin.php

                            background: <?= $color['bg'] ?>;
                            border: 2px solid <?= $color['border'] ?>;
                            color: <?= $color['text'] ?>;

   admin\themes_unified_admin.php

--ann-gap: '.$gapPx.'px;
   admin\annonces_widget.php

background-color:#000000
   admin\index.php

background-color:#0066cc
   admin\index.php

background-color:#008a00
   admin\index.php

background-color:#3498db
   admin\index.php

background-color:#9933cc
   admin\index.php

background-color:#e60000
   admin\index.php

background-color:#e74c3c
   admin\index.php

background-color:#f39c12
   admin\index.php

background: #e0f2fe; color: #0369a1; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: 600; min-width: 80px; text-align: center;
   admin\ui_admin.php

background: #f0f9ff; border-color: #bae6fd; color: #0c4a6e;
   admin\ui_admin.php

background: #f0f9ff; border: 1px solid #bae6fd; border-radius: 8px; padding: 16px; margin-top: 20px;
   admin\ui_admin.php

background: #f9fafb;
   admin\ui_admin.php

background: <?= $theme['colors']['--accent'] ?>
   admin\themes_admin.php
   admin\themes_admin.php

background: <?= $theme['colors']['--bg'] ?>
   admin\themes_admin.php
   admin\themes_admin.php

background: <?= $theme['colors']['--danger'] ?>
   admin\themes_admin.php

background: <?= $theme['colors']['--muted'] ?>; opacity: 0.3
   admin\themes_admin.php

background: <?= $theme['colors']['--muted'] ?>; opacity: 0.5
   admin\themes_admin.php
   admin\themes_admin.php

background: <?= $theme['colors']['--panel'] ?>
   admin\themes_admin.php

background: <?= $theme['colors']['--text'] ?>
   admin\themes_admin.php
   admin\themes_admin.php
   admin\themes_admin.php

background: <?= $theme['colors']['--warning'] ?>
   admin\themes_admin.php

background: <?= h($colors['bg']) ?>;
                            border-color: <?= h($colors['border']) ?>;
   admin\index.php

background: rgba(255,255,255,0.2); color: white; padding: 2px 6px; border-radius: 4px; font-size: 11px;
   admin\ui_admin.php

background: white; padding: 15px; border-radius: 8px; margin-bottom: 15px;
   admin\hyperadmin_forms.php
   admin\hyperadmin_forms.php

background: white; padding: 4px 8px; border-radius: 4px; display: inline-block; margin-top: 4px;
   admin\ui_admin.php

background: yellow; padding: 10px; margin: 10px;
   admin\debug_patch.php

color: #3b82f6; font-weight: bold;
   admin\hyperadmin_forms.php

color: #6b7280; font-size: 14px; margin-bottom: 8px;
   admin\ui_admin.php

color: #718096; line-height: 1.6;
   admin\hyperadmin_forms.php

color: #718096; margin-bottom: 20px; text-align: center;
   admin\reset_password.php
   admin\reset_password.php

color: #718096; margin: 20px 0; text-align: center;
   admin\reset_password.php
   admin\reset_password.php

color: #718096; margin: 8px 0 0 0;
   admin\hyperadmin_forms.php

color: #a0aec0;
   admin\hyperadmin_forms.php
   admin\hyperadmin_forms.php

color: #ca8a04; font-weight: bold;
   admin\hyperadmin_forms.php

color: #dc2626; text-align: center; padding: 40px;
   admin\hyperadmin_forms.php
   admin\hyperadmin_forms.php

color: #ef4444; font-weight: bold;
   admin\hyperadmin_forms.php

color: #f97316; font-weight: bold;
   admin\hyperadmin_forms.php

color: var(--color-danger);
   admin\index.php

color:$1
   admin\annonces_widget.php

display: block; text-align: center; text-decoration: none;
   admin\reset_password.php

display: flex; align-items: center; gap: 10px; background: white; padding: 8px 12px; border-radius: 6px; border-left: 3px solid #3b82f6; cursor: pointer; transition: all 0.2s;
   admin\ui_admin.php

display: flex; align-items: center; gap: 8px;
   admin\index.php
   admin\index.php
   admin\index.php

display: flex; gap: 12px; flex-wrap: wrap;
   admin\ui_admin.php

display: flex; gap: 4px;
   admin\index.php
   admin\themes_unified_admin.php

display: flex; gap: 5px; margin-top: auto;
   admin\themes_admin.php

display: flex; gap: 8px; margin-bottom: 8px;
   admin\themes_unified_admin.php

display: grid; gap: 8px;
   admin\ui_admin.php

display: inline-block; width: 24px; height: 24px; border-radius: 4px;
   admin\index.php

display: inline-block; width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--color-border);
   admin\index.php

display: inline;
   admin\hyperadmin.php
   admin\hyperadmin.php

display: none;
   admin\themes_unified_admin.php

display:inline
   admin\index.php
   admin\index.php
   admin\index.php
   admin\index.php
   admin\index.php
   admin\index.php
   admin\index.php

display:none;
   admin\index.php

flex: 1;
   admin\index.php
   admin\themes_admin.php
   admin\themes_admin.php

flex: 1; color: #374151; font-size: 14px;
   admin\ui_admin.php

flex: 1; height: 16px; background: <?= $theme['colors']['--danger'] ?>; border-radius: 3px;
   admin\themes_admin.php

flex: 1; height: 16px; background: <?= $theme['colors']['--warning'] ?>; border-radius: 3px;
   admin\themes_admin.php

font-family: 'Courier New', monospace; font-size: 12px; color: #374151;
   admin\ui_admin.php

font-family: monospace; border-left: 4px solid #3b82f6; background: #eff6ff;
   admin\hyperadmin_forms.php

font-family: monospace; border-left: 4px solid #eab308; background: #fefce8;
   admin\hyperadmin_forms.php

font-family: monospace; border-left: 4px solid #ef4444; background: #fef2f2;
   admin\hyperadmin_forms.php

font-family: monospace; border-left: 4px solid #f97316; background: #fff7ed;
   admin\hyperadmin_forms.php

font-size: 11px; padding: 2px 8px; border-radius: 12px; background: #f3f4f6; color: #6b7280;
   admin\ui_admin.php

font-size: 16px; line-height: 1;
   admin\ui_admin.php

font-size: 18px; color: #10b981;
   admin\ui_admin.php

font-size:$1
   admin\annonces_widget.php

font-weight: normal; font-size: 12px; color: #64748b;
   admin\ui_admin.php

grid-template-columns: 1fr 1fr;
   admin\hyperadmin_forms.php

margin-bottom: 1rem; color: #64748b;
   admin\hyperadmin_forms.php

margin-bottom: 20px;
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php

margin-left: 30px; <?= $showReactivateOption ? '' : 'display: none;' ?>
   admin\hyperadmin_forms.php

margin-left: 8px;
   admin\index.php
   admin\index.php
   admin\index.php

margin-left: auto; display: flex; gap: 8px; align-items: center;
   admin\index.php

margin-top: 16px; padding: 12px; background: #fffbeb; border-radius: 6px; border-left: 3px solid #f59e0b;
   admin\ui_admin.php

margin-top: 20px;
   admin\hyperadmin_forms.php

margin-top: 30px; text-align: center;
   admin\hyperadmin_forms.php

margin-top: 6px;
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php

margin-top: 6px; padding: 10px; background: #fff7ed; border-radius: 6px; border-left: 3px solid #f97316;
   admin\ui_admin.php

margin-top: 8px;
   admin\themes_unified_admin.php
   admin\ui_admin.php

margin-top: 8px; padding: 12px; background: #f9fafb; border-radius: 6px; border-left: 3px solid #3b82f6;
   admin\ui_admin.php

margin-top:10px;
   admin\wiki\index.html

margin: 0 0 12px 0; color: #0c4a6e; font-size: 14px;
   admin\ui_admin.php

margin: 0 0 var(--spacing-md);
   admin\themes_unified_admin.php

margin: 8px 0 0 0;
   admin\ui_admin.php

max-width: 150px;
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php
   admin\ui_admin.php

max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
   admin\ui_admin.php

min-height: 80px; background: #f9fafb; border: 2px dashed #d1d5db; border-radius: 8px; padding: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;
   admin\ui_admin.php

text-align: center; color: #718096; padding: 40px 0;
   admin\hyperadmin_forms.php

text-align: center; padding: 40px;
   admin\hyperadmin_forms.php
   admin\index.php
   admin\index.php

text-align: center; padding: 40px; color: #718096;
   admin\hyperadmin_forms.php

width: 100%; margin-top: 10px;
   admin\themes_unified_admin.php
   admin\themes_unified_admin.php

width: 100%; text-align: center; color: #9ca3af; padding: 20px; font-size: 14px;
   admin\ui_admin.php

width: 100px
   admin\annonces_theme_admin.php
   admin\annonces_theme_admin.php
   admin\annonces_theme_admin.php

width: 120px
   admin\index.php

width: 200px
   admin\annonces_theme_admin.php

width: 40px
   admin\index.php
   admin\index.php
   admin\index.php

width: 50px
   admin\index.php

width: 50px; height: 36px; padding: 2px;
   admin\annonces_theme_admin.php
   admin\annonces_theme_admin.php
   admin\annonces_theme_admin.php


@'
from pathlib import Path
import re
statics = {}
dynamics = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            style = match.group(1)
            bucket = dynamics if '<?' in style or '<?= ' in style or '<?=' in style else statics
            bucket.setdefault(style, set()).add(str(path))
print('static styles:', len(statics))
print('dynamic styles:', len(dynamics))
'@ | python -


Output:
Exit code: 0
Wall time: 1 seconds
Output:
static styles: 86
dynamic styles: 19


@'
from pathlib import Path
import re, json
styles = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            style = match.group(1)
            if '<?' in style or '<?= ' in style or '<?=' in style:
                continue
            styles.setdefault(style, set()).add(str(path.relative_to(Path.cwd())))
style_items = sorted(styles.items())
map_data = {}
for idx, (style, files) in enumerate(style_items, 1):
    classname = f'u-style-{idx:03d}'
    map_data[style] = {'class': classname, 'files': sorted(files)}
Path('style_map.json').write_text(json.dumps(map_data, indent=2, ensure_ascii=False), encoding='utf-8')
print('created style_map.json with', len(map_data), 'entries')
'@ | python -


Output:
Exit code: 1
Wall time: 1 seconds
Output:
Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
  File "C:\Users\jcoget\AppData\Local\Programs\Python\Python313\Lib\pathlib\_local.py", line 385, in relative_to
    raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
ValueError: 'admin\\annonces_theme_admin.php' is not in the subpath of 'C:\\wamp64\\www\\cssp2AI'


@'
from pathlib import Path
import re, json
root = Path.cwd()
styles = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            style = match.group(1)
            if '<?' in style or '<?= ' in style or '<?=' in style:
                continue
            styles.setdefault(style, set()).add(str(path).replace(str(root)+'\\',''))
style_items = sorted(styles.items())
map_data = {}
for idx, (style, files) in enumerate(style_items, 1):
    classname = f'u-style-{idx:03d}'
    map_data[style] = {'class': classname, 'files': sorted(files)}
Path('style_map.json').write_text(json.dumps(map_data, indent=2, ensure_ascii=False), encoding='utf-8')
print('created style_map.json with', len(map_data), 'entries')
'@ | python -


Output:
Exit code: 0
Wall time: 1.7 seconds
Output:
created style_map.json with 86 entries


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
{
  "--ann-gap: '.$gapPx.'px;": {
    "class": "u-style-001",
    "files": [
      "admin\\annonces_widget.php"
    ]
  },
  "background-color:#000000": {
    "class": "u-style-002",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#0066cc": {
    "class": "u-style-003",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#008a00": {
    "class": "u-style-004",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#3498db": {
    "class": "u-style-005",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#9933cc": {
    "class": "u-style-006",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#e60000": {
    "class": "u-style-007",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#e74c3c": {
    "class": "u-style-008",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#f39c12": {
    "class": "u-style-009",
    "files": [
      "admin\\index.php"
    ]
  },
  "background: #e0f2fe; color: #0369a1; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: 600; min-width: 80px; text-align: center;": {
    "class": "u-style-010",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f0f9ff; border-color: #bae6fd; color: #0c4a6e;": {
    "class": "u-style-011",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f0f9ff; border: 1px solid #bae6fd; border-radius: 8px; padding: 16px; margin-top: 20px;": {
    "class": "u-style-012",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f9fafb;": {
    "class": "u-style-013",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: rgba(255,255,255,0.2); color: white; padding: 2px 6px; border-radius: 4px; font-size: 11px;": {
    "class": "u-style-014",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: white; padding: 15px; border-radius: 8px; margin-bottom: 15px;": {
    "class": "u-style-015",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "background: white; padding: 4px 8px; border-radius: 4px; display: inline-block; margin-top: 4px;": {
    "class": "u-style-016",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: yellow; padding: 10px; margin: 10px;": {
    "class": "u-style-017",
    "files": [
      "admin\\debug_patch.php"
    ]
  },
  "color: #3b82f6; font-weight: bold;": {
    "class": "u-style-018",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #6b7280; font-size: 14px; margin-bottom: 8px;": {
    "class": "u-style-019",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "color: #718096; line-height: 1.6;": {
    "class": "u-style-020",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #718096; margin-bottom: 20px; text-align: center;": {
    "class": "u-style-021",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "color: #718096; margin: 20px 0; text-align: center;": {
    "class": "u-style-022",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "color: #718096; margin: 8px 0 0 0;": {
    "class": "u-style-023",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #a0aec0;": {
    "class": "u-style-024",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #ca8a04; font-weight: bold;": {
    "class": "u-style-025",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #dc2626; text-align: center; padding: 40px;": {
    "class": "u-style-026",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #ef4444; font-weight: bold;": {
    "class": "u-style-027",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #f97316; font-weight: bold;": {
    "class": "u-style-028",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: var(--color-danger);": {
    "class": "u-style-029",
    "files": [
      "admin\\index.php"
    ]
  },
  "color:$1": {
    "class": "u-style-030",
    "files": [
      "admin\\annonces_widget.php"
    ]
  },
  "display: block; text-align: center; text-decoration: none;": {
    "class": "u-style-031",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "display: flex; align-items: center; gap: 10px; background: white; padding: 8px 12px; border-radius: 6px; border-left: 3px solid #3b82f6; cursor: pointer; transition: all 0.2s;": {
    "class": "u-style-032",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: flex; align-items: center; gap: 8px;": {
    "class": "u-style-033",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: flex; gap: 12px; flex-wrap: wrap;": {
    "class": "u-style-034",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: flex; gap: 4px;": {
    "class": "u-style-035",
    "files": [
      "admin\\index.php",
      "admin\\themes_unified_admin.php"
    ]
  },
  "display: flex; gap: 5px; margin-top: auto;": {
    "class": "u-style-036",
    "files": [
      "admin\\themes_admin.php"
    ]
  },
  "display: flex; gap: 8px; margin-bottom: 8px;": {
    "class": "u-style-037",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "display: grid; gap: 8px;": {
    "class": "u-style-038",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: inline-block; width: 24px; height: 24px; border-radius: 4px;": {
    "class": "u-style-039",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: inline-block; width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--color-border);": {
    "class": "u-style-040",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: inline;": {
    "class": "u-style-041",
    "files": [
      "admin\\hyperadmin.php"
    ]
  },
  "display: none;": {
    "class": "u-style-042",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "display:inline": {
    "class": "u-style-043",
    "files": [
      "admin\\index.php"
    ]
  },
  "display:none;": {
    "class": "u-style-044",
    "files": [
      "admin\\index.php"
    ]
  },
  "flex: 1;": {
    "class": "u-style-045",
    "files": [
      "admin\\index.php",
      "admin\\themes_admin.php"
    ]
  },
  "flex: 1; color: #374151; font-size: 14px;": {
    "class": "u-style-046",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-family: 'Courier New', monospace; font-size: 12px; color: #374151;": {
    "class": "u-style-047",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #3b82f6; background: #eff6ff;": {
    "class": "u-style-048",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #eab308; background: #fefce8;": {
    "class": "u-style-049",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #ef4444; background: #fef2f2;": {
    "class": "u-style-050",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #f97316; background: #fff7ed;": {
    "class": "u-style-051",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-size: 11px; padding: 2px 8px; border-radius: 12px; background: #f3f4f6; color: #6b7280;": {
    "class": "u-style-052",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-size: 16px; line-height: 1;": {
    "class": "u-style-053",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-size: 18px; color: #10b981;": {
    "class": "u-style-054",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-size:$1": {
    "class": "u-style-055",
    "files": [
      "admin\\annonces_widget.php"
    ]
  },
  "font-weight: normal; font-size: 12px; color: #64748b;": {
    "class": "u-style-056",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "grid-template-columns: 1fr 1fr;": {
    "class": "u-style-057",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-bottom: 1rem; color: #64748b;": {
    "class": "u-style-058",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-bottom: 20px;": {
    "class": "u-style-059",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-left: 8px;": {
    "class": "u-style-060",
    "files": [
      "admin\\index.php"
    ]
  },
  "margin-left: auto; display: flex; gap: 8px; align-items: center;": {
    "class": "u-style-061",
    "files": [
      "admin\\index.php"
    ]
  },
  "margin-top: 16px; padding: 12px; background: #fffbeb; border-radius: 6px; border-left: 3px solid #f59e0b;": {
    "class": "u-style-062",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 20px;": {
    "class": "u-style-063",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-top: 30px; text-align: center;": {
    "class": "u-style-064",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-top: 6px;": {
    "class": "u-style-065",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 6px; padding: 10px; background: #fff7ed; border-radius: 6px; border-left: 3px solid #f97316;": {
    "class": "u-style-066",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 8px;": {
    "class": "u-style-067",
    "files": [
      "admin\\themes_unified_admin.php",
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 8px; padding: 12px; background: #f9fafb; border-radius: 6px; border-left: 3px solid #3b82f6;": {
    "class": "u-style-068",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top:10px;": {
    "class": "u-style-069",
    "files": [
      "admin\\wiki\\index.html"
    ]
  },
  "margin: 0 0 12px 0; color: #0c4a6e; font-size: 14px;": {
    "class": "u-style-070",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin: 0 0 var(--spacing-md);": {
    "class": "u-style-071",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "margin: 8px 0 0 0;": {
    "class": "u-style-072",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "max-width: 150px;": {
    "class": "u-style-073",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;": {
    "class": "u-style-074",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "min-height: 80px; background: #f9fafb; border: 2px dashed #d1d5db; border-radius: 8px; padding: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;": {
    "class": "u-style-075",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "text-align: center; color: #718096; padding: 40px 0;": {
    "class": "u-style-076",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "text-align: center; padding: 40px;": {
    "class": "u-style-077",
    "files": [
      "admin\\hyperadmin_forms.php",
      "admin\\index.php"
    ]
  },
  "text-align: center; padding: 40px; color: #718096;": {
    "class": "u-style-078",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "width: 100%; margin-top: 10px;": {
    "class": "u-style-079",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "width: 100%; text-align: center; color: #9ca3af; padding: 20px; font-size: 14px;": {
    "class": "u-style-080",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "width: 100px": {
    "class": "u-style-081",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  },
  "width: 120px": {
    "class": "u-style-082",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 200px": {
    "class": "u-style-083",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  },
  "width: 40px": {
    "class": "u-style-084",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 50px": {
    "class": "u-style-085",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 50px; height: 36px; padding: 2px;": {
    "class": "u-style-086",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  }
}


@'
from pathlib import Path
import re, json
root = Path.cwd()
styles = {}
for path in Path('admin').rglob('*'):
    if path.is_file() and path.suffix.lower() in {'.php','.html','.htm'}:
        text = path.read_text(encoding='utf-8', errors='replace')
        for match in re.finditer(r'style="([^"]*)"', text):
            style = match.group(1)
            if any(token in style for token in ('<?', '<?=', '$', '<?= ')):
                continue
            styles.setdefault(style, set()).add(str(path).replace(str(root)+'\\',''))
style_items = sorted(styles.items())
map_data = {}
for idx, (style, files) in enumerate(style_items, 1):
    classname = f'u-style-{idx:03d}'
    map_data[style] = {'class': classname, 'files': sorted(files)}
Path('style_map.json').write_text(json.dumps(map_data, indent=2, ensure_ascii=False), encoding='utf-8')
print('created style_map.json with', len(map_data), 'entries')
'@ | python -


Output:
Exit code: 0
Wall time: 1 seconds
Output:
created style_map.json with 83 entries


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
{
  "background-color:#000000": {
    "class": "u-style-001",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#0066cc": {
    "class": "u-style-002",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#008a00": {
    "class": "u-style-003",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#3498db": {
    "class": "u-style-004",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#9933cc": {
    "class": "u-style-005",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#e60000": {
    "class": "u-style-006",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#e74c3c": {
    "class": "u-style-007",
    "files": [
      "admin\\index.php"
    ]
  },
  "background-color:#f39c12": {
    "class": "u-style-008",
    "files": [
      "admin\\index.php"
    ]
  },
  "background: #e0f2fe; color: #0369a1; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: 600; min-width: 80px; text-align: center;": {
    "class": "u-style-009",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f0f9ff; border-color: #bae6fd; color: #0c4a6e;": {
    "class": "u-style-010",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f0f9ff; border: 1px solid #bae6fd; border-radius: 8px; padding: 16px; margin-top: 20px;": {
    "class": "u-style-011",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: #f9fafb;": {
    "class": "u-style-012",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: rgba(255,255,255,0.2); color: white; padding: 2px 6px; border-radius: 4px; font-size: 11px;": {
    "class": "u-style-013",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: white; padding: 15px; border-radius: 8px; margin-bottom: 15px;": {
    "class": "u-style-014",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "background: white; padding: 4px 8px; border-radius: 4px; display: inline-block; margin-top: 4px;": {
    "class": "u-style-015",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "background: yellow; padding: 10px; margin: 10px;": {
    "class": "u-style-016",
    "files": [
      "admin\\debug_patch.php"
    ]
  },
  "color: #3b82f6; font-weight: bold;": {
    "class": "u-style-017",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #6b7280; font-size: 14px; margin-bottom: 8px;": {
    "class": "u-style-018",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "color: #718096; line-height: 1.6;": {
    "class": "u-style-019",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #718096; margin-bottom: 20px; text-align: center;": {
    "class": "u-style-020",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "color: #718096; margin: 20px 0; text-align: center;": {
    "class": "u-style-021",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "color: #718096; margin: 8px 0 0 0;": {
    "class": "u-style-022",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #a0aec0;": {
    "class": "u-style-023",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #ca8a04; font-weight: bold;": {
    "class": "u-style-024",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #dc2626; text-align: center; padding: 40px;": {
    "class": "u-style-025",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #ef4444; font-weight: bold;": {
    "class": "u-style-026",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: #f97316; font-weight: bold;": {
    "class": "u-style-027",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "color: var(--color-danger);": {
    "class": "u-style-028",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: block; text-align: center; text-decoration: none;": {
    "class": "u-style-029",
    "files": [
      "admin\\reset_password.php"
    ]
  },
  "display: flex; align-items: center; gap: 10px; background: white; padding: 8px 12px; border-radius: 6px; border-left: 3px solid #3b82f6; cursor: pointer; transition: all 0.2s;": {
    "class": "u-style-030",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: flex; align-items: center; gap: 8px;": {
    "class": "u-style-031",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: flex; gap: 12px; flex-wrap: wrap;": {
    "class": "u-style-032",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: flex; gap: 4px;": {
    "class": "u-style-033",
    "files": [
      "admin\\index.php",
      "admin\\themes_unified_admin.php"
    ]
  },
  "display: flex; gap: 5px; margin-top: auto;": {
    "class": "u-style-034",
    "files": [
      "admin\\themes_admin.php"
    ]
  },
  "display: flex; gap: 8px; margin-bottom: 8px;": {
    "class": "u-style-035",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "display: grid; gap: 8px;": {
    "class": "u-style-036",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "display: inline-block; width: 24px; height: 24px; border-radius: 4px;": {
    "class": "u-style-037",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: inline-block; width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--color-border);": {
    "class": "u-style-038",
    "files": [
      "admin\\index.php"
    ]
  },
  "display: inline;": {
    "class": "u-style-039",
    "files": [
      "admin\\hyperadmin.php"
    ]
  },
  "display: none;": {
    "class": "u-style-040",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "display:inline": {
    "class": "u-style-041",
    "files": [
      "admin\\index.php"
    ]
  },
  "display:none;": {
    "class": "u-style-042",
    "files": [
      "admin\\index.php"
    ]
  },
  "flex: 1;": {
    "class": "u-style-043",
    "files": [
      "admin\\index.php",
      "admin\\themes_admin.php"
    ]
  },
  "flex: 1; color: #374151; font-size: 14px;": {
    "class": "u-style-044",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-family: 'Courier New', monospace; font-size: 12px; color: #374151;": {
    "class": "u-style-045",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #3b82f6; background: #eff6ff;": {
    "class": "u-style-046",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #eab308; background: #fefce8;": {
    "class": "u-style-047",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #ef4444; background: #fef2f2;": {
    "class": "u-style-048",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-family: monospace; border-left: 4px solid #f97316; background: #fff7ed;": {
    "class": "u-style-049",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "font-size: 11px; padding: 2px 8px; border-radius: 12px; background: #f3f4f6; color: #6b7280;": {
    "class": "u-style-050",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-size: 16px; line-height: 1;": {
    "class": "u-style-051",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-size: 18px; color: #10b981;": {
    "class": "u-style-052",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "font-weight: normal; font-size: 12px; color: #64748b;": {
    "class": "u-style-053",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "grid-template-columns: 1fr 1fr;": {
    "class": "u-style-054",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-bottom: 1rem; color: #64748b;": {
    "class": "u-style-055",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-bottom: 20px;": {
    "class": "u-style-056",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-left: 8px;": {
    "class": "u-style-057",
    "files": [
      "admin\\index.php"
    ]
  },
  "margin-left: auto; display: flex; gap: 8px; align-items: center;": {
    "class": "u-style-058",
    "files": [
      "admin\\index.php"
    ]
  },
  "margin-top: 16px; padding: 12px; background: #fffbeb; border-radius: 6px; border-left: 3px solid #f59e0b;": {
    "class": "u-style-059",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 20px;": {
    "class": "u-style-060",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-top: 30px; text-align: center;": {
    "class": "u-style-061",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "margin-top: 6px;": {
    "class": "u-style-062",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 6px; padding: 10px; background: #fff7ed; border-radius: 6px; border-left: 3px solid #f97316;": {
    "class": "u-style-063",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 8px;": {
    "class": "u-style-064",
    "files": [
      "admin\\themes_unified_admin.php",
      "admin\\ui_admin.php"
    ]
  },
  "margin-top: 8px; padding: 12px; background: #f9fafb; border-radius: 6px; border-left: 3px solid #3b82f6;": {
    "class": "u-style-065",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin-top:10px;": {
    "class": "u-style-066",
    "files": [
      "admin\\wiki\\index.html"
    ]
  },
  "margin: 0 0 12px 0; color: #0c4a6e; font-size: 14px;": {
    "class": "u-style-067",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "margin: 0 0 var(--spacing-md);": {
    "class": "u-style-068",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "margin: 8px 0 0 0;": {
    "class": "u-style-069",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "max-width: 150px;": {
    "class": "u-style-070",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;": {
    "class": "u-style-071",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "min-height: 80px; background: #f9fafb; border: 2px dashed #d1d5db; border-radius: 8px; padding: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;": {
    "class": "u-style-072",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "text-align: center; color: #718096; padding: 40px 0;": {
    "class": "u-style-073",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "text-align: center; padding: 40px;": {
    "class": "u-style-074",
    "files": [
      "admin\\hyperadmin_forms.php",
      "admin\\index.php"
    ]
  },
  "text-align: center; padding: 40px; color: #718096;": {
    "class": "u-style-075",
    "files": [
      "admin\\hyperadmin_forms.php"
    ]
  },
  "width: 100%; margin-top: 10px;": {
    "class": "u-style-076",
    "files": [
      "admin\\themes_unified_admin.php"
    ]
  },
  "width: 100%; text-align: center; color: #9ca3af; padding: 20px; font-size: 14px;": {
    "class": "u-style-077",
    "files": [
      "admin\\ui_admin.php"
    ]
  },
  "width: 100px": {
    "class": "u-style-078",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  },
  "width: 120px": {
    "class": "u-style-079",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 200px": {
    "class": "u-style-080",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  },
  "width: 40px": {
    "class": "u-style-081",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 50px": {
    "class": "u-style-082",
    "files": [
      "admin\\index.php"
    ]
  },
  "width: 50px; height: 36px; padding: 2px;": {
    "class": "u-style-083",
    "files": [
      "admin\\annonces_theme_admin.php"
    ]
  }
}


@'
from pathlib import Path
import json,re
mapping = json.loads(Path('style_map.json').read_text(encoding='utf-8'))
files_map = {}
for style, meta in mapping.items():
    classname = meta['class']
    for rel in meta['files']:
        files_map.setdefault(rel, []).append((style, classname))

def add_class_to_tag(tag, classname):
    if 'class="' in tag:
        def repl(match):
            classes = match.group(1).split()
            if classname not in classes:
                classes.append(classname)
            return 'class="' + ' '.join(classes) + '"'
        return re.sub(r'class="([^"]*)"', repl, tag, count=1)
    m = re.match(r'(<\s*[^\/>\s]+)', tag)
    if m:
        insert_pos = m.end(1)
        return tag[:insert_pos] + f' class="{classname}"' + tag[insert_pos:]
    return tag[:-1] + f' class="{classname}">'

def replace_style(text, style, classname):
    style_seq = f'style="{style}"'
    idx = text.find(style_seq)
    while idx != -1:
        start_attr = idx
        while start_attr > 0 and text[start_attr-1] in ' \t':
            start_attr -= 1
        end_attr = idx + len(style_seq)
        text = text[:start_attr] + text[end_attr:]
        # adjust idx to start_attr for search
        tag_start = text.rfind('<', 0, start_attr)
        tag_end = text.find('>', start_attr)
        if tag_start == -1 or tag_end == -1:
            idx = text.find(style_seq, start_attr)
            continue
        tag_end += 1
        tag = text[tag_start:tag_end]
        new_tag = add_class_to_tag(tag, classname)
        text = text[:tag_start] + new_tag + text[tag_end:]
        idx = text.find(style_seq, tag_start + len(new_tag))
    return text

for rel_path, styles in files_map.items():
    path = Path(rel_path)
    text = path.read_text(encoding='utf-8')
    for style, classname in styles:
        text = replace_style(text, style, classname)
    path.write_text(text, encoding='utf-8')
print('Inline styles replaced in', len(files_map), 'files')
'@ | python -


Output:
Exit code: 0
Wall time: 1.2 seconds
Output:
Inline styles replaced in 10 files


rg -n "style=\"" admin\annonces_theme_admin.php


Output:
Exit code: 1
Wall time: 0.7 seconds
Output:
Le terminateur " est manquant dans la cha�ne.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString


rg -n 'style="' admin\annonces_theme_admin.php


Output:
Exit code: 1
Wall time: 0.9 seconds
Output:


rg -n "u-style" admin\annonces_theme_admin.php


Output:
Exit code: 0
Wall time: 0.8 seconds
Output:
130:      <input class="annadmin-input annadmin-input-inline u-style-080"
176:                       class="annadmin-input annadmin-input-inline u-style-083"
183:                       value="<?= class="u-style-078" h($bg) ?>"
196:                       class="annadmin-input annadmin-input-inline u-style-083"
203:                       value="<?= class="u-style-078" h($bd) ?>"
216:                       class="annadmin-input annadmin-input-inline u-style-083"
223:                       value="<?= class="u-style-078" h($tx) ?>"


Get-Content admin\annonces_theme_admin.php -TotalCount 220