/* =========================================================================
   JackTheFrog — feuille de style unique
   Direction : « Internet 2005, construit en 2026 ».
   Verdana pour le corps (typo du web des années 2000, très lisible),
   display gras condensé en capitales, aplats noir/blanc, vert grenouille
   réservé aux actions. Aucune dépendance externe.
   ========================================================================= */

:root {
    color-scheme: light;
    --ink:        #10140f;
    --ink-soft:   #3d453b;
    --paper:      #ffffff;
    --mist:       #f2f4f0;
    --mist-2:     #e7ebe3;
    --line:       #d6dcd1;
    --frog:       #2fa63a;
    --frog-dark:  #237c2c;
    --frog-bright:#7cff5b;
    --danger:     #c0392b;
    --warning:    #b8860b;
    --info:       #2b6cb0;

    --bg:         var(--paper);
    --surface:    var(--paper);
    --surface-2:  var(--mist);
    --text:       var(--ink);
    --text-soft:  var(--ink-soft);
    --border:     var(--line);
    --accent:     var(--frog);
    --accent-ink: #ffffff;

    --radius:     10px;
    --radius-sm:  6px;
    --shadow:     0 1px 0 rgba(16,20,15,.06), 0 6px 18px rgba(16,20,15,.07);
    --shadow-sm:  0 1px 2px rgba(16,20,15,.10);

    --font-display: "Arial Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
    --font-body: Verdana, Geneva, "Segoe UI", system-ui, sans-serif;
    --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", "Courier New", monospace;

    --wrap: 1180px;

    /* Palette d'états. Déclarée en variables et redéfinie dans CHACUN des deux contextes
       sombres (thème « dark » explicite ET thème « auto » sur un OS en sombre) : une règle
       [data-theme="dark"] seule laisserait les utilisateurs en « auto » — le réglage par
       défaut — avec des badges et bandeaux clairs sur fond sombre. */
    --dot:       var(--mist-2);
    --track:     var(--mist-2);
    --ok-fg:     #1d7a2b;  --ok-bg:     #eaf7ea;  --ok-bd:     #a9dcae;  --ok-strong: #1d5f28;
    --warn-fg:   #8a6100;  --warn-bg:   #fdf5e2;  --warn-bd:   #eacd88;  --warn-strong: #6d5100;
    --danger-fg: #9b2c20;  --danger-bg: #fdeceb;  --danger-bd: #eaa79f;  --danger-strong: #8f271c;
}

[data-theme="dark"] {
    color-scheme: dark;
    --bg:        #0d110c;
    --surface:   #151b14;
    --surface-2: #1d251c;
    --text:      #e9efe6;
    --text-soft: #a8b3a4;
    --border:    #2b352a;
    --accent:    var(--frog-bright);
    --accent-ink:#0d110c;
    --shadow:    0 1px 0 rgba(0,0,0,.4), 0 8px 22px rgba(0,0,0,.45);
    --dot:       #1e271d;
    --track:     #26301f;
    --ok-fg:     #9ff08d;  --ok-bg:     #16301a;  --ok-bd:     #2f5b32;  --ok-strong: #a5efa0;
    --warn-fg:   #f0d28d;  --warn-bg:   #322a12;  --warn-bd:   #5b4c22;  --warn-strong: #f2d99a;
    --danger-fg: #f5a79d;  --danger-bg: #331816;  --danger-bd: #6b2f28;  --danger-strong: #f7b0a6;
}

@media (prefers-color-scheme: dark) {
    [data-theme="auto"] {
        color-scheme: dark;
        --bg:        #0d110c;
        --surface:   #151b14;
        --surface-2: #1d251c;
        --text:      #e9efe6;
        --text-soft: #a8b3a4;
        --border:    #2b352a;
        --accent:    var(--frog-bright);
        --accent-ink:#0d110c;
        --shadow:    0 1px 0 rgba(0,0,0,.4), 0 8px 22px rgba(0,0,0,.45);
    --dot:       #1e271d;
    --track:     #26301f;
    --ok-fg:     #9ff08d;  --ok-bg:     #16301a;  --ok-bd:     #2f5b32;  --ok-strong: #a5efa0;
    --warn-fg:   #f0d28d;  --warn-bg:   #322a12;  --warn-bd:   #5b4c22;  --warn-strong: #f2d99a;
    --danger-fg: #f5a79d;  --danger-bg: #331816;  --danger-bd: #6b2f28;  --danger-strong: #f7b0a6;
    }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font: 400 15px/1.6 var(--font-body);
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--text); text-decoration-color: var(--accent); text-underline-offset: 3px; }
a:hover { color: var(--accent); }

:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

h1, h2, h3 {
    font-family: var(--font-display);
    letter-spacing: -.02em;
    line-height: 1.05;
    margin: 0 0 .5em;
    text-transform: uppercase;
}
h1 { font-size: clamp(28px, 5vw, 46px); }
/* Les titres reprenant une saisie utilisateur (nom de fichier, titre d'image,
   nom d'album) gardent leur casse d'origine : les capitales forcées les déformeraient. */
.title-literal { text-transform: none; letter-spacing: -.01em; font-size: clamp(22px, 3vw, 30px); }
h2 { font-size: clamp(20px, 3vw, 28px); }
h3 { font-size: 17px; letter-spacing: 0; }

.wrap { width: min(100% - 32px, var(--wrap)); margin-inline: auto; }
.stack > * + * { margin-top: 18px; }
.muted { color: var(--text-soft); }
.small { font-size: 13px; }
.mono { font-family: var(--font-mono); }
.center { text-align: center; }
.hidden { display: none !important; }
.visually-hidden {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ---------- En-tête ---------- */
.masthead {
    background: #0d110c;
    color: #f2f5f0;
    border-bottom: 3px solid var(--frog);
}
.masthead .wrap { display: flex; align-items: center; gap: 20px; min-height: 64px; }
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; }
.brand:hover { color: inherit; }
.brand .mascot,
.brand svg { width: 46px; height: 46px; object-fit: contain; flex: none; }
/* Jack assis est une silhouette entière, plus fine qu'un simple visage :
   il lui faut quelques pixels de plus qu'une icône pour rester lisible. */

/* Taille par défaut : la mascotte remplit son conteneur, sauf règle de contexte. */
.mascot { display: block; width: 100%; height: auto; }
.brand-name { font-family: var(--font-display); font-size: 21px; letter-spacing: -.02em; text-transform: uppercase; }
.brand-name em { font-style: normal; color: var(--frog-bright); }
.brand-slogan { display: block; font-size: 11px; letter-spacing: .06em; color: #9fb09a; text-transform: none; font-family: var(--font-body); }

.nav { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.nav a, .nav button {
    color: #dfe7dc; text-decoration: none; font-size: 13px; padding: 8px 12px;
    border-radius: var(--radius-sm); background: none; border: 0; cursor: pointer;
    font-family: var(--font-body);
}
.nav a:hover, .nav button:hover { background: rgba(255,255,255,.09); color: #fff; }
.nav a[aria-current="page"] { color: var(--frog-bright); font-weight: 700; }
/* .nav a est plus spécifique que .btn : sans cette règle, le bouton d'inscription
   perdrait son fond vert et passerait pour un lien en gras. */
.nav a.btn, .nav .btn {
    background: var(--frog); color: #fff; padding: 9px 16px; margin-left: 6px;
    border: 1px solid rgba(0,0,0,.2); box-shadow: var(--shadow-sm);
}
.nav a.btn:hover { background: var(--frog); filter: brightness(1.08); color: #fff; }

.masthead .menu-toggle { display: none; }  /* .btn est déclaré plus bas : il faut plus de spécificité */

/* ---------- Boutons ---------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 10px 18px; border-radius: var(--radius-sm); cursor: pointer;
    font: 700 14px/1 var(--font-body); text-decoration: none;
    background: var(--frog); color: #fff; border: 1px solid rgba(0,0,0,.12);
    box-shadow: var(--shadow-sm); transition: transform .06s ease, filter .15s ease;
}
.btn:hover { filter: brightness(1.06); color: #fff; }
.btn:active { transform: translateY(1px); }
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--border); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-danger { background: var(--danger); }
.btn-sm { padding: 7px 12px; font-size: 12px; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }

/* ---------- Blocs ---------- */
.panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 22px;
}
/* Le premier titre d'un panneau ne doit pas pousser le contenu vers le bas.
   Cette règle remplace 72 attributs style="margin-top:0" répétés dans les vues :
   un style en ligne bat toute feuille de style, et chacun était un réglage que
   le thème ne pouvait plus rattraper. */
.panel > h2:first-child,
.panel > h3:first-child,
.panel > h4:first-child { margin-top: 0; }
.panel-flush { padding: 0; overflow: hidden; }
.panel-head {
    padding: 14px 18px; border-bottom: 1px solid var(--border);
    background: var(--surface-2); font-weight: 700; font-size: 13px;
    letter-spacing: .06em; text-transform: uppercase;
}
.panel-body { padding: 18px; }

.grid { display: grid; gap: 18px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

/* ---------- Bande de points forts ---------- */
.features {
    display: grid; grid-template-columns: repeat(4, 1fr);
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow);
    margin-top: 18px; overflow: hidden;
}
.feature { display: flex; gap: 13px; align-items: flex-start; padding: 20px 22px; }
.feature + .feature { border-left: 1px solid var(--border); }
.feature svg { width: 26px; height: 26px; flex: none; color: var(--accent); margin-top: 2px; }
.feature h3 {
    margin: 0 0 3px; font-family: var(--font-display); font-size: 13px;
    letter-spacing: .06em; text-transform: uppercase;
}
.feature p { margin: 0; font-size: 12.5px; color: var(--text-soft); line-height: 1.5; }

/* ---------- Héros ---------- */
.hero {
    display: grid; grid-template-columns: 1.15fr .85fr; gap: 30px; align-items: center;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--shadow); padding: 34px; margin-top: 26px;
    background-image: radial-gradient(circle at 1px 1px, var(--dot) 1px, transparent 0);
    background-size: 22px 22px;
}
.hero h1 span { color: var(--accent); display: block; }
.hero-lede { font-size: 16.5px; color: var(--text-soft); max-width: 42ch; line-height: 1.6; }
.hero h1 { font-size: clamp(30px, 3.4vw, 44px); line-height: 1.04; margin: 0 0 14px; }
.hero-art { justify-self: center; max-width: 360px; }
.hero-art svg,
.hero-art .mascot { width: 100%; height: auto; }

/* ---------- Zone d'upload ---------- */
.dropzone {
    border: 2px dashed var(--border); border-radius: var(--radius);
    background: var(--surface); padding: 30px 24px; text-align: center;
    cursor: pointer; transition: border-color .15s ease, background .15s ease;
}
.dropzone:hover, .dropzone.is-active { border-color: var(--frog); background: var(--surface-2); }
.dropzone.is-active { border-style: solid; }
.dropzone strong { display: block; font-size: 17px; }
.dropzone .hint { font-size: 12px; color: var(--text-soft); margin-top: 8px; }
.dropzone svg { width: 46px; height: 46px; margin: 0 auto 10px; color: var(--accent); }

.upload-queue { margin-top: 16px; display: grid; gap: 10px; }
.queue-item {
    display: grid; grid-template-columns: 56px 1fr auto; gap: 12px; align-items: center;
    border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px; background: var(--surface);
}
.queue-item img { width: 56px; height: 56px; object-fit: cover; border-radius: 4px; }
.progress { height: 8px; background: var(--track); border-radius: 99px; overflow: hidden; }
.progress span { display: block; height: 100%; width: 0; background: var(--frog); transition: width .2s ease; }
.queue-item.is-error { border-color: var(--danger); }
.queue-item.is-done .progress span { background: var(--frog-bright); }

/* ---------- Champs de partage ---------- */
.copy-row { display: grid; gap: 6px; margin-bottom: 12px; }
.copy-row label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-soft); }
.copy-field { display: flex; gap: 8px; }
.copy-field input {
    flex: 1; min-width: 0; font-family: var(--font-mono); font-size: 12.5px;
    padding: 9px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-2); color: var(--text);
}
.copy-field .btn { flex: none; }
.copy-field .btn.is-copied { background: var(--frog-dark); }

/* ---------- Formulaires ---------- */
label { font-size: 13px; font-weight: 700; }
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=url], input[type=date], input[type=datetime-local], input[type=search],
select, textarea {
    width: 100%; padding: 10px 12px; font: 400 14px var(--font-body);
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface); color: var(--text);
}
textarea { min-height: 110px; resize: vertical; }
.field { margin-bottom: 14px; }
.field label { display: block; margin-bottom: 5px; }
.field .help { font-size: 12px; color: var(--text-soft); margin-top: 4px; }
/* Avertissement sous un champ : la couleur passe par un jeton, donc elle
   suit les trois thèmes sans règle supplémentaire. */
.field .help-warning { color: var(--warn-fg); font-weight: 600; }
/* Texte d'alerte hors champ de formulaire. Jeton -fg : les variantes
   --danger et --warning ne sont déclarées que pour le thème clair. */
.text-danger { color: var(--danger-fg); }
.check { display: flex; align-items: center; gap: 8px; font-weight: 400; font-size: 14px; }
.check input { width: 16px; height: 16px; }
fieldset { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 14px; margin: 0 0 18px; }
legend { font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; padding: 0 6px; }

/* ---------- Galerie ---------- */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.tile {
    position: relative; display: block; border: 1px solid var(--border); border-radius: var(--radius-sm);
    overflow: hidden; background: var(--surface-2); aspect-ratio: 1 / 1;
}
.tile img { width: 100%; height: 100%; object-fit: cover; transition: transform .25s ease; }
.tile:hover img { transform: scale(1.04); }
.tile figcaption {
    position: absolute; inset: auto 0 0 0; padding: 6px 8px; font-size: 11px;
    background: linear-gradient(transparent, rgba(0,0,0,.75)); color: #fff;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tile .badge-views {
    position: absolute; top: 6px; right: 6px; background: rgba(0,0,0,.62); color: #fff;
    font-size: 10px; padding: 3px 7px; border-radius: 99px;
    display: inline-flex; align-items: center; gap: 4px; backdrop-filter: blur(2px);
}
.tile .badge-views svg { width: 11px; height: 11px; }
.tile { transition: border-color .15s ease, box-shadow .15s ease; }
.tile:hover { border-color: var(--frog); box-shadow: 0 6px 18px rgba(0,0,0,.16); }

/* ---------- Divers ---------- */
.badge {
    display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700;
    padding: 3px 8px; border-radius: 99px; background: var(--surface-2);
    border: 1px solid var(--border); text-transform: uppercase; letter-spacing: .04em;
}
.badge-ok { color: var(--ok-fg); border-color: var(--ok-bd); background: var(--ok-bg); }
.badge-warn { color: var(--warn-fg); border-color: var(--warn-bd); background: var(--warn-bg); }
.badge-danger { color: var(--danger-fg); border-color: var(--danger-bd); background: var(--danger-bg); }

.flash { padding: 12px 16px; border-radius: var(--radius-sm); margin-bottom: 14px; border: 1px solid; font-size: 14px; }
.flash-success { background: var(--ok-bg); border-color: var(--ok-bd); color: var(--ok-strong); }
.flash-error { background: var(--danger-bg); border-color: var(--danger-bd); color: var(--danger-strong); }

.stat { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 14px 16px; background: var(--surface); }
.stat .value { font-family: var(--font-display); font-size: 26px; line-height: 1; }
.stat .label { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-soft); margin-top: 6px; }

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th, td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: middle; }
th { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-soft); }
tbody tr:hover { background: var(--surface-2); }
.table-wrap { overflow-x: auto; }

.pagination { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; justify-content: center; margin-top: 22px; }
.pagination a, .pagination span {
    padding: 7px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
    text-decoration: none; font-size: 13px; background: var(--surface);
}
.pagination .is-current { background: var(--frog); color: #fff; border-color: var(--frog); }

/* ---------- Bandeaux d'annonce ---------- */
.announce {
    display: flex; gap: 12px; align-items: flex-start; padding: 11px 16px;
    border-bottom: 1px solid var(--border); font-size: 14px; background: var(--surface-2);
}
.announce-low { background: var(--surface-2); }
.announce-medium { background: var(--warn-bg); color: var(--warn-strong); border-bottom-color: var(--warn-bd); }
.announce-high { background: var(--danger-bg); color: var(--danger-strong); border-bottom-color: var(--danger-bd); }
.announce .icon { flex: none; font-weight: 700; }
.announce .body { flex: 1; }
.announce .body strong { display: block; }
.announce .dismiss { background: none; border: 0; cursor: pointer; font-size: 18px; line-height: 1; color: inherit; padding: 0 4px; }

/* ---------- Pied de page ---------- */
.footer { position: relative; overflow: hidden; margin-top: 46px; background: #0d110c; color: #c9d3c5; padding: 34px 0 26px; }
.footer-peek { position: absolute; right: 26px; bottom: 0; width: 185px; pointer-events: none; z-index: 0; }
.footer .wrap { position: relative; z-index: 1; }  /* le contenu passe devant Jack */
.avatar-jack { width: 64px; height: 64px; border-radius: 50%; overflow: hidden; background: var(--surface-2); border: 2px solid var(--border); flex: none; }
.footer a { color: #c9d3c5; text-decoration: none; font-size: 13px; }
.footer a:hover { color: var(--frog-bright); }
.footer h4 { font-family: var(--font-display); font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: #8ba085; margin: 0 0 12px; }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 26px; }
.footer-bottom {
    margin-top: 26px; padding-top: 16px; border-top: 1px solid #232c21;
    display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap;
    font-size: 12px; color: #7f8f7b; align-items: center;
}
/* Jack dépasse du coin droit : on réserve sa place pour qu'il ne passe pas
   par-dessus le sélecteur de langue et les boutons de thème. */
@media (min-width: 1000px) { .footer-bottom { padding-right: 215px; flex-wrap: nowrap; } }
.footer-controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-left: auto; }
.footer .btn-ghost {
    background: #171d16; color: #c9d3c5; border-color: #2b352a;
}
.footer .btn-ghost:hover { background: #202920; color: #fff; }
.footer .btn-ghost[aria-pressed="true"] { border-color: var(--frog); color: var(--frog-bright); }
.lang-select { max-width: 190px; background: #171d16; color: #c9d3c5; border: 1px solid #2b352a; border-radius: var(--radius-sm); padding: 7px 9px; font-size: 13px; }

/* ---------- Administration ---------- */
/* margin: 24px 0 écrasait le margin-inline: auto hérité de .wrap : la console
   se retrouvait collée au bord gauche alors que l'en-tête restait centré. */
.admin-shell { display: grid; grid-template-columns: 232px 1fr; gap: 24px; align-items: start; margin: 24px auto; }
.admin-nav { position: sticky; top: 16px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.admin-nav a {
    display: flex; justify-content: space-between; align-items: center; gap: 8px;
    padding: 11px 15px; text-decoration: none; font-size: 13.5px; border-bottom: 1px solid var(--border);
}
.admin-nav a:last-child { border-bottom: 0; }
.admin-nav a[aria-current="page"] { background: var(--frog); color: #fff; font-weight: 700; }
.admin-nav .count { background: var(--danger); color: #fff; border-radius: 99px; font-size: 11px; padding: 1px 7px; }

.chart { width: 100%; height: auto; }
.chart .bar { fill: var(--frog); }
.chart .grid-line { stroke: var(--border); stroke-width: 1; }
.chart .label { fill: var(--text-soft); font-size: 9px; font-family: var(--font-body); }
.chart .line { fill: none; stroke: var(--frog); stroke-width: 2; }
.chart .area { fill: var(--frog); opacity: .12; }

/* ---------- Installateur ---------- */
.install-shell { max-width: 760px; margin: 40px auto; padding: 0 16px; }
.steps { display: flex; gap: 8px; margin-bottom: 22px; flex-wrap: wrap; }
.steps li {
    list-style: none; flex: 1; min-width: 120px; font-size: 11.5px; text-transform: uppercase;
    letter-spacing: .05em; padding: 9px 10px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--surface); color: var(--text-soft);
}
.steps li.is-current { background: var(--frog); border-color: var(--frog); color: #fff; font-weight: 700; }
.steps li.is-done { border-color: var(--frog); color: var(--frog); }
.check-list { list-style: none; margin: 0; padding: 0; }
.check-list li { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px dashed var(--border); font-size: 14px; }
.check-list .ok { color: #1d7a2b; font-weight: 700; }
.check-list .ko { color: var(--danger); font-weight: 700; }
.check-list .optional { color: var(--warn-fg); font-weight: 700; }

/* ---------- Maintenance ---------- */
.maintenance { min-height: 100vh; display: grid; place-items: center; text-align: center; padding: 30px; }
.maintenance .art { width: 200px; margin: 0 auto 20px; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
    .hero { grid-template-columns: 1fr; text-align: left; }
    .features { grid-template-columns: 1fr 1fr; }
    .feature:nth-child(odd) + .feature { border-left: 1px solid var(--border); }
    .feature:nth-child(n+3) { border-top: 1px solid var(--border); }
    .hero-art { max-width: 220px; }
    .admin-shell { grid-template-columns: 1fr; }
    .admin-nav { position: static; }
    .footer-grid { grid-template-columns: 1fr 1fr; }
    .footer-peek { display: none; }
}
@media (max-width: 640px) {
    .masthead .wrap { flex-wrap: wrap; padding-block: 10px; }  /* surchargé plus bas pour le mobile */
    .masthead .menu-toggle { display: inline-flex; margin-left: auto; }
    .nav { display: none; width: 100%; margin-left: 0; }
    /* flex-basis 100% force le retour à la ligne même avec un conteneur en nowrap. */
    .nav.is-open { display: flex; flex-direction: column; align-items: stretch; flex: 1 0 100%; margin-top: 4px; }
    .nav a, .nav button { text-align: left; }
    .footer-grid { grid-template-columns: 1fr; }
    .features { grid-template-columns: 1fr; }
    .feature + .feature { border-left: 0; border-top: 1px solid var(--border); }
    .copy-field { flex-direction: column; }
    .copy-field .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

@media print {
    .masthead, .footer, .announce, .btn { display: none; }
}

/* ==========================================================================
   Mise en page verticale : en-tête collant, pied de page en bas de fenêtre
   ==========================================================================
   Deux problèmes distincts, deux solutions différentes.

   1. Sur une page courte, le pied de page flottait au milieu de l'écran avec
      jusqu'à 667 px de blanc en dessous. La colonne en flex avec min-height le
      pousse en bas SANS le fixer : il reste dans le flux, on le dépasse en
      défilant sur les pages longues.

   2. L'en-tête devient collant : la navigation et le bouton d'upload restent
      accessibles quelle que soit la position dans la page. Il ne fait que 67 px,
      le coût en surface utile est négligeable.

   Le pied de page, lui, n'est délibérément PAS fixé : il mesure 308 px, soit
   38 % d'un écran de 800 px, qui seraient perdus en permanence. */
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;   /* tient compte des barres mobiles rétractables */
}
body > main { flex: 1 0 auto; }
body > .footer { flex: none; margin-top: auto; }

.masthead {
    position: sticky; top: 0; z-index: 50;
}
/* L'ancre d'un lien interne ne doit pas se retrouver cachée sous l'en-tête collant. */
:target { scroll-margin-top: 80px; }

@media (max-width: 640px) {
    /* Sur mobile, l'écran est déjà court : on rend l'en-tête au défilement. */
    .masthead { position: static; }
}
@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}

/* ==========================================================================
   Outils d'en-tête : langue et thème
   ========================================================================== */
.tools { display: flex; align-items: center; gap: 6px; margin-left: 14px; padding-left: 14px;
         border-left: 1px solid rgba(255,255,255,.12); }
.masthead .nav { margin-left: auto; }

.tool-btn {
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 10px;
    background: rgba(255,255,255,.06); color: #d7e0d3;
    border: 1px solid rgba(255,255,255,.12); border-radius: 999px;
    font: inherit; font-size: 12.5px; line-height: 1; cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.tool-btn:hover { background: rgba(255,255,255,.13); color: #fff; border-color: rgba(255,255,255,.22); }
.tool-btn:focus-visible { outline: 2px solid var(--frog-bright); outline-offset: 2px; }
.tool-btn .flag { font-size: 14px; }
.tool-btn .code { font-weight: 700; letter-spacing: .04em; }
.tool-btn .caret { width: 12px; height: 12px; opacity: .7; }
.theme-btn { width: 34px; padding: 0; justify-content: center; }
.theme-btn svg { width: 17px; height: 17px; }

/* L'icône affichée suit le thème actif : une seule est visible à la fois. */
.theme-btn .i-light, .theme-btn .i-dark, .theme-btn .i-auto { display: none; }
[data-theme="light"] .theme-btn .i-light,
[data-theme="dark"]  .theme-btn .i-dark,
[data-theme="auto"]  .theme-btn .i-auto { display: block; }

.lang-menu { position: relative; }
.lang-list {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
    min-width: 190px; margin: 0; padding: 6px; list-style: none;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: 0 12px 34px rgba(0,0,0,.28);
    display: none;
}
.lang-menu.is-open .lang-list { display: block; }
.lang-list a {
    display: flex; align-items: center; gap: 9px; padding: 8px 10px;
    border-radius: var(--radius-sm); color: var(--text); text-decoration: none; font-size: 13.5px;
}
.lang-list a:hover { background: var(--surface-2); }
.lang-list a[aria-current="true"] { color: var(--accent); font-weight: 700; }

@media (max-width: 640px) {
    /* Sur mobile, l'en-tête tient sur une seule ligne : marque à gauche, puis
       langue, thème et menu alignés à droite. Auparavant les outils basculaient
       sur une seconde ligne, laissant un séparateur vertical orphelin et un
       alignement bancal entre le logo et les boutons. */
    /* wrap, pas nowrap : la barre reste sur une ligne tant que le menu est fermé
       (marque + outils + bouton tiennent dans 360 px), et la navigation dépliée
       passe naturellement sur une deuxième ligne au lieu de recouvrir le logo. */
    .masthead .wrap { flex-wrap: wrap; gap: 8px; padding-block: 8px; min-height: 58px; }
    .brand { flex: 1 1 auto; min-width: 0; }
    .brand-name { font-size: 17px; }
    .brand-slogan { display: none; }          /* le slogan reprend sa place en 641 px et plus */
    .brand .mascot, .brand svg { width: 36px; height: 36px; }

    .tools {
        order: 0; margin-left: auto; padding-left: 0;
        border-left: 0;                        /* plus de séparateur suspendu */
        flex: none;
    }
    .tool-btn { height: 32px; padding: 0 8px; }
    .theme-btn { width: 32px; }
    .tool-btn .code { display: none; }
    .tool-btn .caret { display: none; }
    .lang-list { right: 0; }

    .masthead .menu-toggle {
        order: 1; margin-left: 0; flex: none;
        height: 32px; padding: 0 10px;
    }
    /* La navigation dépliée passe sous tout le reste, sur la largeur complète. */
    .nav { order: 3; }
}

@media (max-width: 380px) {
    /* Très petits écrans (iPhone SE et assimilés) : sous 360 px, marque + langue +
       thème + « Menu » ne tiennent plus côte à côte. On abrège le bouton en icône
       seule et on réduit la marque, plutôt que de laisser la barre se casser en deux. */
    .brand-name { font-size: 15px; }
    .brand .mascot, .brand svg { width: 30px; height: 30px; }
    .masthead .wrap { gap: 6px; }
    .tools { gap: 4px; }
    .masthead .menu-toggle { padding: 0 9px; font-size: 0; }   /* « Menu » masqué, ☰ conservé */
    .masthead .menu-toggle::before { content: '\2630'; font-size: 16px; }
}

/* ==========================================================================
   Modernisation — même identité (noir, blanc, vert grenouille), traits plus fins,
   arrondis plus généreux, ombres plus douces. On ne change ni la palette ni la
   typographie : seulement la façon dont les surfaces respirent.
   ========================================================================== */
:root {
    --radius:    14px;
    --radius-sm: 9px;
    --radius-lg: 22px;
    --shadow:    0 1px 2px rgba(16,20,15,.04), 0 10px 30px -12px rgba(16,20,15,.16);
    --shadow-sm: 0 1px 2px rgba(16,20,15,.07);
    --ring:      0 0 0 3px rgba(58,166,45,.22);
}
[data-theme="dark"] {
    --shadow: 0 1px 2px rgba(0,0,0,.5), 0 14px 34px -14px rgba(0,0,0,.7);
    --ring:   0 0 0 3px rgba(126,224,110,.22);
}
@media (prefers-color-scheme: dark) {
    [data-theme="auto"] {
        --shadow: 0 1px 2px rgba(0,0,0,.5), 0 14px 34px -14px rgba(0,0,0,.7);
        --ring:   0 0 0 3px rgba(126,224,110,.22);
    }
}

/* Champs : anneau de focus vert plutôt qu'un contour système, plus dans l'esprit du site */
input[type="text"], input[type="email"], input[type="password"], input[type="search"],
input[type="url"], input[type="number"], input[type="datetime-local"], select, textarea {
    border-radius: var(--radius-sm);
    transition: border-color .15s ease, box-shadow .15s ease;
}
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--frog); box-shadow: var(--ring);
}

/* Boutons : léger relief au survol, retour tactile à l'appui */
.btn {
    border-radius: 999px; font-weight: 700; letter-spacing: .01em;
    transition: transform .12s ease, box-shadow .15s ease, background .15s ease, filter .15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Panneaux : bord plus discret, ombre plus basse et plus large */
.panel { border-radius: var(--radius); }
.hero { border-radius: var(--radius-lg); }

/* Cartes de chiffres : le nombre porte la couleur d'accent, comme sur la maquette */
.stat { border-radius: var(--radius); transition: border-color .15s ease, box-shadow .15s ease; }
.stat:hover { border-color: var(--frog); box-shadow: var(--shadow); }
.stat .value { font-family: var(--font-display); }

/* Tuiles : coins plus doux et légère montée au survol */
.tile { border-radius: var(--radius); }
.tile:hover { transform: translateY(-2px); }
.tile img { border-radius: 0; }

/* Bande de points forts : pastille verte derrière l'icône */
.feature svg {
    box-sizing: content-box; padding: 8px; border-radius: 12px;
    background: rgba(58,166,45,.10); color: var(--frog);
}
[data-theme="dark"] .feature svg { background: rgba(126,224,110,.12); }
@media (prefers-color-scheme: dark) {
    [data-theme="auto"] .feature svg { background: rgba(126,224,110,.12); }
}

/* Zone de dépôt : le vert n'apparaît qu'au survol, pour rester sobre au repos */
.dropzone { border-radius: var(--radius-lg); transition: border-color .15s ease, background .15s ease; }
.dropzone:hover, .dropzone.is-active { border-color: var(--frog); background: rgba(58,166,45,.045); }

/* En-tête : liseré vert plus fin, ombre portée sur le contenu */
.masthead { box-shadow: 0 1px 0 rgba(255,255,255,.06); }

/* Champs de copie : monospace un peu plus lisible et bouton collé au champ */
.copy-field input { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.copy-field .btn { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

@media (prefers-reduced-motion: reduce) {
    .btn:hover, .tile:hover { transform: none; }
}

/* ---------- File de modération ---------- */
.mod-queue { display: grid; gap: 14px; margin-top: 16px; }
.mod-card {
    display: grid; grid-template-columns: 200px 1fr; gap: 18px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 16px; outline: none;
    transition: border-color .15s ease, box-shadow .15s ease, opacity .18s ease, transform .18s ease;
}
.mod-card.is-current { border-color: var(--frog); box-shadow: var(--ring); }
.mod-card.is-flagged { border-left: 4px solid var(--danger-bd); }
.mod-card.is-working { opacity: .55; }
.mod-card.is-gone { opacity: 0; transform: translateX(-14px); }
.mod-card.is-error { border-color: var(--danger-bd); }
.mod-media img {
    width: 100%; aspect-ratio: 1; object-fit: cover;
    border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--surface-2);
}
.mod-head { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.mod-message {
    margin: 0 0 12px; padding: 8px 12px; font-size: 13.5px;
    border-left: 3px solid var(--border); color: var(--text-soft);
}
.mod-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 0 0 14px; }
.mod-meta dt { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-soft); }
.mod-meta dd { margin: 2px 0 0; font-size: 13.5px; }
.mod-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.mod-actions form { display: inline; }
kbd {
    display: inline-block; padding: 1px 5px; margin-left: 4px;
    font: 700 10px/1.5 var(--font-mono, monospace);
    background: var(--surface-2); border: 1px solid var(--border);
    border-bottom-width: 2px; border-radius: 4px; color: var(--text-soft);
}
@media (max-width: 700px) {
    .mod-card { grid-template-columns: 1fr; }
    .mod-media img { max-width: 190px; }
}

/* ---------- Actions en fin de ligne de tableau ----------
   Chaque action est un <form> distinct (nécessaire pour le jeton CSRF), ce qui
   empêche un simple flex du parent d'aligner les boutons : les formulaires sont
   des blocs. On les rend inline-flex et on aligne tout sur la même ligne de base. */
.row-actions {
    /* nowrap : les actions d'une même ligne restent alignées horizontalement.
       La colonne est étroite, donc c'est le tableau qui défile (.table-wrap),
       plutôt que les boutons qui s'empilent sur trois niveaux. */
    display: flex; flex-wrap: nowrap; gap: 6px; align-items: center;
}
.table-wrap td:last-child { white-space: nowrap; }
.row-actions form { display: inline-flex; margin: 0; }
.row-actions .btn { white-space: nowrap; }
.row-actions .role-form { display: inline-flex; gap: 4px; align-items: center; }
.row-actions select {
    height: 30px; padding: 0 8px; font-size: 12.5px;
    border-radius: 999px; width: auto; min-width: 104px;
}
@media (max-width: 900px) {
    .row-actions { flex-wrap: wrap; }
}

/* ---------- Options d'upload (expiration) ---------- */
.upload-options {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-top: 12px; padding: 10px 14px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.upload-options label { font-size: 13px; font-weight: 700; margin: 0; }
.upload-options select { width: auto; min-width: 150px; }

/* ---------- Sélection multiple ---------- */
/* L'attribut hidden pose display:none, mais une règle de classe qui déclare
   display:flex l'emporte : sans cette ligne, la barre restait affichée en
   permanence, « 0 sélectionnée » compris. */
.bulk-bar[hidden] { display: none; }
.bulk-bar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-top: 14px; padding: 10px 14px;
    background: var(--surface-2); border: 1px solid var(--frog); border-radius: var(--radius-sm);
}
.bulk-bar select { width: auto; min-width: 140px; }
.col-check { width: 34px; }
.col-check input { width: 16px; height: 16px; }
tr.is-selected { background: rgba(58,166,45,.06); }

.mod-ban { display: flex; align-items: center; gap: 7px; margin-bottom: 10px; }
.mod-ban .muted { font-size: 12px; }

/* ---------- Navigation de l'espace membre ----------
   Elle manquait sur les sous-pages : on arrivait dans « Mes images » sans aucun
   moyen de rejoindre « Mes albums » ou les réglages, sinon le bouton Précédent. */
.account-nav {
    /* Huit entrées ne tiennent pas toujours sur une ligne, et un retour à la ligne
       isolé (« Réglages » seul en dessous) est disgracieux. On garde une seule ligne
       et on laisse défiler horizontalement si la place manque — comportement usuel
       des barres d'onglets, et naturel au doigt sur mobile. */
    display: flex; flex-wrap: nowrap; gap: 8px;
    margin: 14px 0 20px; padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
    overflow-x: auto; scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
}
.account-nav::-webkit-scrollbar { height: 6px; }
.account-nav::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }
.account-nav a { flex: none; }
.account-nav a {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 8px 13px; border-radius: 999px; white-space: nowrap;
    font-size: 13.5px; font-weight: 700; text-decoration: none;
    color: var(--text-soft); border: 1px solid var(--border); background: var(--surface);
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.account-nav a:hover { border-color: var(--frog); color: var(--text); }
.account-nav a[aria-current="page"] {
    background: var(--frog); border-color: var(--frog); color: #fff;
}

/* ---------- Actions groupées dans les cartes d'images (admin) ----------
   Trois boutons empilés sur trois lignes dans une tuile étroite : on les réduit
   et on les laisse s'aligner, la tuile étant trop étroite pour du texte long. */
.card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.card-actions form { display: inline-flex; margin: 0; }
.card-actions .btn { padding: 5px 10px; font-size: 11.5px; white-space: nowrap; }

/* ---------- Bandeau d'usurpation d'identité ---------- */
.impersonation-bar {
    display: flex; align-items: center; justify-content: center; gap: 14px; flex-wrap: wrap;
    padding: 9px 16px; background: #7a3d00; color: #ffe9c9;
    border-bottom: 2px solid #b45f00; font-size: 13.5px;
}
.impersonation-bar .small { opacity: .85; }
.impersonation-bar .btn { background: #ffe9c9; color: #4a2600; border-color: #ffd9a3; }
.impersonation-bar .btn:hover { background: #fff; color: #3a1d00; }

/* ---------- Choix de la méthode de second facteur ---------- */
.twofa-methods { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
/* Chaque code dans son propre encadré : ils étaient auparavant de simples <span>
   côte à côte, et se lisaient comme une seule longue suite de caractères dès que la
   feuille de style n'était pas appliquée — ce qui arrivait avec un CSS en cache. */
.recovery-codes {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px;
    margin: 14px 0; padding: 14px 14px 14px 34px;
    background: var(--surface-2);
    border: 1px dashed var(--border); border-radius: var(--radius-sm);
}
.recovery-codes li { color: var(--text-soft); }
.recovery-codes code {
    display: inline-block; padding: 6px 10px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
    font-family: var(--font-mono, monospace); font-size: 14px; letter-spacing: .12em;
    color: var(--text);
}
.secret-box {
    padding: 12px 14px; background: var(--surface-2); border: 1px solid var(--border);
    border-radius: var(--radius-sm); font-family: var(--font-mono, monospace);
    font-size: 15px; letter-spacing: .1em; word-break: break-all;
}

/* ---------- Configuration du second facteur ---------- */
.twofa-setup { display: flex; gap: 22px; flex-wrap: wrap; align-items: flex-start; margin: 14px 0; }
.qr-figure { margin: 0; text-align: center; }
.qr-figure svg {
    display: block; width: 200px; height: 200px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.qr-figure figcaption { margin-top: 8px; max-width: 200px; }
.twofa-secret { flex: 1; min-width: 240px; }

/* ---------- Boutons d'action en icône ----------
   Utilisés là où la place manque (cartes d'images de l'administration) : le libellé
   reste dans title et aria-label, donc rien n'est perdu au clavier ni au lecteur
   d'écran. Trois libellés traduits ne tenaient pas dans une carte de 192 px. */
.btn-icon {
    width: 32px; height: 32px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
}
.btn-icon svg { width: 16px; height: 16px; }
.card-actions { gap: 8px; }

/* ---------- Cloche de notifications (administration) ---------- */
.bell { position: relative; }
.bell-btn { width: 34px; padding: 0; justify-content: center; position: relative; }
.bell-btn svg { width: 17px; height: 17px; }
.bell-count {
    position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px;
    padding: 0 4px; border-radius: 99px;
    background: var(--danger-fg); color: #fff;
    font-size: 10px; font-weight: 700; line-height: 17px; text-align: center;
    border: 2px solid #0d110c;
}
.bell-panel {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
    min-width: 290px; padding: 6px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: 0 12px 34px rgba(0,0,0,.28);
    display: none;
}
.bell.is-open .bell-panel { display: block; }
.bell-panel ul { list-style: none; margin: 0; padding: 0; }
.bell-panel a {
    display: flex; align-items: center; gap: 10px; padding: 9px 10px;
    border-radius: var(--radius-sm); color: var(--text); text-decoration: none; font-size: 13.5px;
}
.bell-panel a:hover { background: var(--surface-2); }
.bell-empty { margin: 0; padding: 12px 10px; font-size: 13px; color: var(--text-soft); }

/* ---------- Option de réduction automatique ---------- */
.upload-resize {
    display: flex; gap: 9px; align-items: flex-start;
    margin-top: 12px; padding: 10px 14px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
    font-size: 13.5px; cursor: pointer;
}
.upload-resize input { margin-top: 2px; }
.upload-resize .muted { display: block; margin-top: 2px; }

/* ---------- Cases à cocher des réglages ----------
   Une case placée dans la même rangée qu'un champ classique doit s'aligner sur la
   ligne de saisie, pas sur le libellé : on réserve donc la hauteur du libellé
   au-dessus. Sur une rangée qui ne contient que des cases, l'espace est neutralisé. */
/* label.toggle-label et non .toggle-label : la règle générale « .field label »
   est plus spécifique qu'une simple classe et remettait display:block, ce qui
   annulait le flex — la case se retrouvait collée à son texte. */
label.toggle-label {
    display: flex; gap: 9px; align-items: center;
    margin: 0; font-weight: 700; cursor: pointer;
}
.toggle-label input[type="checkbox"] { width: 16px; height: 16px; flex: none; margin: 0; }
.field-toggle { display: flex; flex-direction: column; justify-content: flex-start; }
/* Le décalage ne s'applique QUE si la rangée mêle cases et champs libellés :
   une rangée composée uniquement de cases n'a rien à compenser. Les navigateurs
   sans :has() retrouvent simplement l'ancien rendu, sans rien casser. */
/* 26 px pour la hauteur du libellé, plus la moitié de la différence de hauteur
   entre un champ de saisie et une case : ce sont les CENTRES qui doivent coïncider,
   pas les bords supérieurs. */
.grid:has(> .field:not(.field-toggle)) > .field-toggle { padding-top: 38px; }
.field-toggle .help { margin-top: 6px; }

/* ---------- Compteur d'affichages ---------- */
.view-counts { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.view-counts svg { width: 13px; height: 13px; flex: none; opacity: .7; }
