/* ==========================================================================
   SHE'S TYPING — Chat immersif
   --------------------------------------------------------------------------
   Hérite du design system du site (vide violet-noir, aurores magenta, verre
   dépoli, filets lumineux) et le pousse vers l'imagerie « v2 » : des bulles
   de néon qui flottent dans l'obscurité, une conversation comme seule
   source de lumière.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Jetons
   -------------------------------------------------------------------------- */

:root {
    /* Fonds */
    --void:        #07040a;
    --void-2:      #0c0710;
    --void-3:      #120a17;

    /* Accents */
    --crimson:     #cb1258;
    --crimson-hi:  #e8447a;
    --blush:       #ff7aa8;
    --plum:        #b4368f;
    --grape:       #6d2f9c;

    /* Encre */
    --ink:         #ffffff;
    --ink-2:       rgba(255, 255, 255, 0.66);
    --ink-3:       rgba(255, 255, 255, 0.42);
    --ink-4:       rgba(255, 255, 255, 0.24);

    /* Surfaces */
    --glass:       rgba(255, 255, 255, 0.035);
    --glass-2:     rgba(255, 255, 255, 0.055);
    --glass-3:     rgba(255, 255, 255, 0.085);
    --line:        rgba(255, 255, 255, 0.09);
    --line-2:      rgba(255, 255, 255, 0.16);
    --line-hot:    rgba(232, 68, 122, 0.42);

    /* Lueurs */
    --glow:        rgba(203, 18, 88, 0.45);
    --glow-soft:   rgba(203, 18, 88, 0.16);

    /* Bulles */
    --bubble-her:  rgba(255, 216, 233, 0.06);
    --bubble-me-a: #ef5287;
    --bubble-me-b: #cb1258;
    --bubble-me-c: #971044;

    /* Rayons */
    --r-sm: 12px;
    --r-md: 18px;
    --r-lg: 26px;
    --r-pill: 999px;

    /* Mouvement */
    --ease:        cubic-bezier(0.22, 1, 0.36, 1);
    --ease-io:     cubic-bezier(0.65, 0, 0.35, 1);
    --ease-spring: cubic-bezier(0.34, 1.45, 0.64, 1);
    --t-fast: 0.22s var(--ease);
    --t: 0.42s var(--ease);

    /* Typo */
    --f-display: 'Sora', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --f-text: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --f-serif: 'Instrument Serif', Georgia, 'Times New Roman', serif;

    /* Clavier virtuel (iOS) : poussé par JS via visualViewport */
    --kb: 0px;
}

/* --------------------------------------------------------------------------
   2. Remise à zéro — application plein écran, la page ne défile jamais
   -------------------------------------------------------------------------- */

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

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

body {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    background: var(--void);
    color: var(--ink);
    font-family: var(--f-text);
    font-size: 16px;
    line-height: 1.55;
    letter-spacing: -0.011em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    -webkit-tap-highlight-color: transparent;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }

button, input, textarea {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
}
button { cursor: pointer; }

::selection { background: var(--crimson); color: #fff; }

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

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(203, 18, 88, 0.5) transparent;
}
*::-webkit-scrollbar { width: 6px; height: 6px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: rgba(203, 18, 88, 0.42); border-radius: 99px; }

/* --------------------------------------------------------------------------
   3. Scène — le vide, les aurores, les bulles de néon
   -------------------------------------------------------------------------- */

.scene {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    background:
        radial-gradient(1200px 800px at 80% -10%, rgba(203, 18, 88, 0.32), transparent 62%),
        radial-gradient(900px 700px at 4% 16%,  rgba(109, 47, 156, 0.26), transparent 60%),
        radial-gradient(1100px 900px at 50% 110%, rgba(180, 54, 143, 0.22), transparent 66%),
        linear-gradient(180deg, var(--void) 0%, var(--void-2) 45%, var(--void) 100%);
}

/* Grain pellicule */
.scene::after {
    content: '';
    position: absolute;
    inset: -200%;
    opacity: 0.055;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    animation: grain 8s steps(6) infinite;
}

@keyframes grain {
    0%   { transform: translate(0, 0); }
    20%  { transform: translate(-3%, 2%); }
    40%  { transform: translate(2%, -3%); }
    60%  { transform: translate(-2%, -2%); }
    80%  { transform: translate(3%, 1%); }
    100% { transform: translate(0, 0); }
}

/* Trame technique */
.scene__mesh {
    position: absolute;
    inset: 0;
    opacity: 0.3;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.028) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.028) 1px, transparent 1px);
    background-size: 68px 68px;
    mask-image: radial-gradient(ellipse 90% 65% at 50% 0%, #000 0%, transparent 78%);
    -webkit-mask-image: radial-gradient(ellipse 90% 65% at 50% 0%, #000 0%, transparent 78%);
}

/* Aurores : la parallaxe pointeur est appliquée par JS sur --px / --py */
.scene__orb {
    position: absolute;
    border-radius: 50%;
    filter: blur(90px);
    opacity: 0.55;
    will-change: transform;
    translate: calc(var(--px, 0) * 1px) calc(var(--py, 0) * 1px);
}
.scene__orb--a {
    top: -16%; right: -10%;
    width: 48vmax; height: 48vmax;
    background: radial-gradient(circle, rgba(232, 68, 122, 0.5), transparent 68%);
    animation: drift-a 26s var(--ease-io) infinite alternate;
}
.scene__orb--b {
    bottom: -20%; left: -14%;
    width: 54vmax; height: 54vmax;
    background: radial-gradient(circle, rgba(109, 47, 156, 0.44), transparent 68%);
    animation: drift-b 32s var(--ease-io) infinite alternate;
}
.scene__orb--c {
    top: 34%; left: 46%;
    width: 26vmax; height: 26vmax;
    opacity: 0.3;
    background: radial-gradient(circle, rgba(255, 122, 168, 0.42), transparent 66%);
    animation: drift-a 38s var(--ease-io) infinite alternate-reverse;
}

@keyframes drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(-7%, 9%, 0) scale(1.16); }
}
@keyframes drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.1); }
    to   { transform: translate3d(9%, -7%, 0) scale(0.94); }
}

/* Filaments de lumière qui traversent le vide */
.scene__streak {
    position: absolute;
    height: 2px;
    border-radius: 99px;
    filter: blur(1.5px);
    opacity: 0.5;
    background: linear-gradient(90deg, transparent, rgba(255, 87, 141, 0.85), rgba(180, 54, 143, 0.5), transparent);
}
.scene__streak--a {
    width: 58vmax;
    left: -12%; bottom: 22%;
    transform: rotate(-16deg);
    animation: streak 14s var(--ease-io) infinite alternate;
}
.scene__streak--b {
    width: 44vmax;
    right: -10%; top: 30%;
    transform: rotate(-16deg);
    opacity: 0.3;
    animation: streak 18s var(--ease-io) infinite alternate-reverse;
}

@keyframes streak {
    from { transform: rotate(-16deg) translateX(-4%); opacity: 0.2; }
    50%  { opacity: 0.55; }
    to   { transform: rotate(-16deg) translateX(5%);  opacity: 0.25; }
}

/* Bulles de néon — l'imagerie de la photo v2 : contours lumineux qui
   dérivent lentement, avec l'indicateur de saisie qui pulse à l'intérieur */
.scene__bubble {
    position: absolute;
    stroke: rgba(232, 68, 122, 0.75);
    stroke-width: 2.5;
    stroke-linejoin: round;
    stroke-linecap: round;
    filter:
        drop-shadow(0 0 6px rgba(232, 68, 122, 0.65))
        drop-shadow(0 0 22px rgba(203, 18, 88, 0.4));
    opacity: 0.5;
    will-change: transform;
    translate: calc(var(--px, 0) * -1.6px) calc(var(--py, 0) * -1.6px);
}
.scene__bubble--a {
    width: clamp(150px, 16vw, 250px);
    top: 7%; left: 3%;
    animation: bubble-float 13s var(--ease-io) infinite alternate;
}
.scene__bubble--b {
    width: clamp(90px, 10vw, 160px);
    top: 4%; right: 6%;
    stroke: rgba(180, 54, 143, 0.7);
    filter:
        drop-shadow(0 0 6px rgba(180, 54, 143, 0.6))
        drop-shadow(0 0 22px rgba(109, 47, 156, 0.45));
    opacity: 0.38;
    animation: bubble-float 17s var(--ease-io) infinite alternate-reverse;
}
.scene__bubble--c {
    width: clamp(70px, 8vw, 130px);
    bottom: 12%; left: 10%;
    opacity: 0.26;
    animation: bubble-float 21s var(--ease-io) infinite alternate;
}

@keyframes bubble-float {
    from { transform: translateY(0) rotate(-2deg); }
    to   { transform: translateY(-26px) rotate(2.5deg); }
}

.scene__dot {
    fill: #ff9dbf;
    stroke: none;
    animation: neon-typing 1.6s var(--ease-io) infinite;
}
.scene__dot--2 { animation-delay: 0.2s; }
.scene__dot--3 { animation-delay: 0.4s; }

@keyframes neon-typing {
    0%, 62%, 100% { opacity: 0.35; }
    28%           { opacity: 1; }
}

/* Sur mobile, on éclaircit la scène : la conversation est la seule star */
@media (max-width: 1023px) {
    .scene__bubble--a { top: 3%; left: -8%; opacity: 0.3; }
    .scene__bubble--b { top: auto; bottom: 18%; right: -6%; opacity: 0.22; }
    .scene__bubble--c { display: none; }
    .scene__streak--b { display: none; }
}

/* --------------------------------------------------------------------------
   4. Plateau — plein écran mobile, scène cinéma sur desktop
   -------------------------------------------------------------------------- */

.stage {
    position: relative;
    z-index: 1;
    height: 100vh;   /* filet de sécurité */
    height: 100dvh;  /* suit le clavier sur Android (resizes-content) */
    display: flex;
    flex-direction: column;
}

.hero { display: none; }
.brand { display: none; }
.portrait { display: none; }

/* Transparent sur mobile : le chat reste enfant direct du plateau */
.duo { display: contents; }

/* ------------------------------------------------------------------
   Le chat
   ------------------------------------------------------------------ */

.chat {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    /* Compensation clavier iOS : visualViewport pilote --kb */
    padding-bottom: var(--kb);
    transition: padding-bottom 0.12s ease-out;
}

/* --------------------------------------------------------------------------
   5. En-tête de conversation
   -------------------------------------------------------------------------- */

.chat__head {
    position: relative;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex: none;
    padding: calc(0.55rem + env(safe-area-inset-top)) 0.65rem 0.55rem;
    background: rgba(10, 5, 14, 0.78);
    border-bottom: 1px solid var(--line);
    backdrop-filter: blur(24px) saturate(160%);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
}

/* Filet lumineux sous l'en-tête — signature du site */
.chat__head::after {
    content: '';
    position: absolute;
    inset-inline: 18%;
    bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--line-hot), transparent);
}

.chat__back {
    display: grid;
    place-items: center;
    width: 40px; height: 40px;
    flex: none;
    border-radius: 50%;
    color: var(--ink-2);
    transition: background var(--t-fast), color var(--t-fast);
}
.chat__back:hover { background: var(--glass-2); color: var(--ink); }
.chat__back svg { width: 21px; height: 21px; }

.chat__identity {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-width: 0;
    flex: 1;
}

.chat__avatar {
    position: relative;
    flex: none;
    width: 44px; height: 44px;
    border-radius: 50%;
    padding: 2px;
    background: linear-gradient(134deg, var(--blush), var(--crimson) 55%, var(--grape));
    box-shadow: 0 0 18px -4px var(--glow);
}
.chat__avatar img {
    width: 100%; height: 100%;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--void);
}

/* Pastille de présence, respiration lente */
.chat__presence {
    position: absolute;
    right: 0; bottom: 0;
    width: 12px; height: 12px;
    border-radius: 50%;
    background: #35e08f;
    border: 2.5px solid var(--void);
    box-shadow: 0 0 0 0 rgba(53, 224, 143, 0.55);
    animation: presence 2.4s var(--ease-io) infinite;
}
@keyframes presence {
    0%   { box-shadow: 0 0 0 0 rgba(53, 224, 143, 0.5); }
    70%  { box-shadow: 0 0 0 7px rgba(53, 224, 143, 0); }
    100% { box-shadow: 0 0 0 0 rgba(53, 224, 143, 0); }
}

.chat__who { min-width: 0; }

.chat__name {
    display: flex;
    align-items: center;
    gap: 5px;
    font-family: var(--f-display);
    font-size: 1.02rem;
    font-weight: 700;
    letter-spacing: -0.025em;
    line-height: 1.2;
    white-space: nowrap;
}
.chat__verified { width: 16px; height: 16px; flex: none; }

.chat__status {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.766rem;
    line-height: 1.3;
    color: var(--ink-3);
    transition: color var(--t-fast);
}
.chat__status-text { transition: color var(--t-fast); }

/* Les trois points du statut « écrit… » */
.chat__status-dots {
    display: none;
    align-items: center;
    gap: 2.5px;
    padding-top: 1px;
}
.chat__status-dots i {
    width: 3.5px; height: 3.5px;
    border-radius: 50%;
    background: var(--crimson-hi);
    animation: status-dot 1.3s var(--ease-io) infinite;
}
.chat__status-dots i:nth-child(2) { animation-delay: 0.16s; }
.chat__status-dots i:nth-child(3) { animation-delay: 0.32s; }

@keyframes status-dot {
    0%, 60%, 100% { opacity: 0.35; transform: translateY(0); }
    26%           { opacity: 1;    transform: translateY(-2px); }
}

.chat__status.is-typing .chat__status-text {
    color: var(--crimson-hi);
    font-weight: 500;
}
.chat__status.is-typing .chat__status-dots { display: inline-flex; }

.chat__actions {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    flex: none;
}
.chat__action {
    display: grid;
    place-items: center;
    width: 40px; height: 40px;
    border-radius: 50%;
    color: var(--ink-3);
    transition: background var(--t-fast), color var(--t-fast);
}
.chat__action:hover { background: var(--glass-2); color: var(--ink); }
.chat__action svg { width: 20px; height: 20px; }

/* --------------------------------------------------------------------------
   6. Fil de conversation
   -------------------------------------------------------------------------- */

.chat__scroll {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

.chat__thread {
    display: flex;
    flex-direction: column;
    margin-top: auto; /* le fil colle en bas, comme toute messagerie */
    padding: 1.1rem 0.9rem 1rem;
    width: 100%;
    max-width: 720px;
    margin-inline: auto;
}

.thread__meta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: 1.4rem;
    animation: msg-in 0.6s var(--ease) both;
}

.thread__day {
    padding: 0.28rem 0.85rem;
    border-radius: var(--r-pill);
    background: var(--glass-2);
    border: 1px solid var(--line);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    font-family: var(--f-display);
    font-size: 0.688rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-3);
}

/* ------------------------------------------------------------------
   Messages
   ------------------------------------------------------------------ */

.msg {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    max-width: 84%;
    /* Assez d'air pour que deux bulles d'affilée se distinguent au premier
       coup d'œil, pas assez pour casser la « rafale ». */
    margin-top: 0.34rem;
}
.msg--gap { margin-top: 0.95rem; } /* nouvelle « rafale » de messages */

.msg--her { align-self: flex-start; }
.msg--me  { align-self: flex-end; flex-direction: row-reverse; }

/* Entrée : petit ressort depuis le bas, ancré côté expéditeur */
.msg--her { transform-origin: 0 100%; }
.msg--me  { transform-origin: 100% 100%; }
.msg { animation: msg-in 0.5s var(--ease-spring) both; }

@keyframes msg-in {
    from { opacity: 0; transform: translateY(16px) scale(0.9); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Avatar : réservé, affiché seulement sur le dernier message du groupe */
.msg__avatar {
    width: 30px; height: 30px;
    flex: none;
    border-radius: 50%;
    object-fit: cover;
    visibility: hidden;
    box-shadow: 0 0 0 1.5px rgba(232, 68, 122, 0.35), 0 4px 14px -4px var(--glow);
}
.msg--last .msg__avatar { visibility: visible; }

.msg__bubble {
    position: relative;
    padding: 0.62rem 0.85rem 0.42rem;
    border-radius: var(--r-md);
    font-size: 0.938rem;
    line-height: 1.5;
    letter-spacing: -0.008em;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.msg__bubble p { white-space: pre-line; }

/* Ses bulles : verre sombre, filet supérieur lumineux */
.msg--her .msg__bubble {
    background: var(--bubble-her);
    border: 1px solid var(--line);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow: 0 8px 26px -14px rgba(0, 0, 0, 0.8);
}
.msg--her .msg__bubble::before {
    content: '';
    position: absolute;
    inset-inline: 16%;
    top: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--line-hot), transparent);
}
.msg--her.msg--last .msg__bubble { border-bottom-left-radius: 6px; }

/* Mes bulles : dégradé crimson, halo chaud */
.msg--me .msg__bubble {
    background: linear-gradient(128deg, var(--bubble-me-a), var(--bubble-me-b) 58%, var(--bubble-me-c));
    box-shadow:
        0 10px 30px -12px var(--glow),
        inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.msg--me.msg--last .msg__bubble { border-bottom-right-radius: 6px; }

/* Méta : heure + accusés, flottés en fin de dernière ligne du texte
   (le span vit dans le <p>) ; ne passe sous le texte que si la ligne
   est pleine, aucune ligne n'est réservée pour l'heure. */
.msg__meta {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    float: right;
    margin: 0.5rem -0.15rem -0.05rem 0.6rem;
    font-size: 0.656rem;
    font-variant-numeric: tabular-nums;
    color: var(--ink-4);
    user-select: none;
}
.msg--me .msg__meta { color: rgba(255, 255, 255, 0.62); }

.msg__ticks { width: 15px; height: 11px; }
.msg__ticks path {
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}
.msg__ticks .tick--2 { opacity: 0; transition: opacity 0.3s ease; }

/* Lu : les deux coches passent au blush lumineux */
.msg--read .msg__ticks { color: #ffd3e2; filter: drop-shadow(0 0 4px rgba(255, 160, 195, 0.8)); }
.msg--read .msg__ticks .tick--2 { opacity: 1; }

/* ------------------------------------------------------------------
   Sticker animé — message sans bulle
   ------------------------------------------------------------------
   Le GIF est détouré : comme dans les messageries, il se pose nu sur le
   fil. Toute la quincaillerie de bulle (verre, filet, ombre) disparaît,
   l'heure passe dessous.
   ------------------------------------------------------------------ */

.msg--sticker .msg__bubble {
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}
.msg--sticker .msg__bubble::before { content: none; }

.msg__sticker {
    display: block;
    width: 148px;
    max-width: 42vw;
    height: auto;
    /* Le sujet est clair et le fond très sombre : une ombre portée douce
       le décolle du décor sans lui dessiner de cadre. */
    filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.55));
}

.msg--sticker .msg__meta {
    float: none;
    display: flex;
    justify-content: flex-end;
    margin: 0.18rem 0.15rem 0 0;
}

/* ------------------------------------------------------------------
   Carrousel de profils — message riche
   ------------------------------------------------------------------ */

.msg--cards { max-width: min(100%, 640px); width: 100%; }

/* Restauration de l'historique : rien ne doit rejouer d'animation */
.is-restoring .msg,
.is-restoring .gcard { animation: none !important; }

/* Mouvement réduit : plus d'onde, mais le point garde sa lueur — sans elle
   il redeviendrait une pastille terne, et le signal « en live » se perdrait. */
@media (prefers-reduced-motion: reduce) {
    .gcard__live i {
        animation: none;
        box-shadow: 0 0 7px rgba(53, 224, 143, 0.85);
    }
}

/* Attente du jeton de sortie après un clic anticipé sur une carte */
.is-gate-pending, .is-gate-pending * { cursor: progress !important; }

/* La bulle remplit l'espace restant à côté de l'avatar, sans déborder */
.msg--cards .msg__bubble {
    flex: 1;
    min-width: 0;
    padding: 0.75rem 0.75rem 0.5rem;
}
.msg__bubble--cards > p { padding: 0.05rem 0.3rem 0.7rem; }

/* La date passe sous le carrousel, alignée à droite */
.msg__bubble--cards .msg__meta {
    float: none;
    display: flex;
    justify-content: flex-end;
    margin: 0.3rem 0.2rem 0.05rem 0;
}

/* Enveloppe du rail : porte les voiles de bord, la barre de progression et
   l'incitation à glisser — tous fixes pendant que les cartes défilent. */
.gcarousel {
    position: relative;
    /* Réserve la place de la barre : sans elle, le dernier pixel de carte
       serait recouvert au moment où elle apparaît. */
    padding-bottom: 0.5rem;
}

.gcards {
    display: flex;
    gap: 0.6rem;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
    cursor: grab;
}
.gcards:active { cursor: grabbing; }

/* ---- La barre système est masquée partout, on dessine la nôtre ----------
   Sur mobile elle n'apparaît qu'au doigt posé ; sur macOS elle dépend d'un
   réglage système, et son style varie d'un navigateur à l'autre. Une barre
   maison est visible en permanence et tient le design du site partout. */
.gcards { scrollbar-width: none; }
.gcards::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* Estompe de bord : la carte suivante s'efface au lieu d'être coupée net,
   ce qui se lit immédiatement comme « ça continue par là ».
   C'est un masque, pas un cache posé par-dessus : la bulle est translucide
   et floute ce qu'il y a derrière — un aplat opaque s'y verrait. */
.gcarousel.has-overflow .gcards {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
}
.gcarousel.has-overflow.at-start .gcards {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent 100%);
}
.gcarousel.has-overflow.at-end .gcards {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 44px, #000 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 44px, #000 100%);
}

/* Barre de défilement maison — visible en permanence. Sa largeur dit combien
   de cartes tiennent à l'écran, sa position où l'on en est. */
.gcarousel__bar {
    position: absolute;
    left: 0; right: 0;
    bottom: 0;
    height: 3px;
    border-radius: 99px;
    background: rgba(255, 255, 255, 0.09);
    opacity: 0;
    transition: opacity var(--t-fast);
}
.gcarousel.has-overflow .gcarousel__bar { opacity: 1; }

.gcarousel__bar > i {
    position: absolute;
    top: 0; bottom: 0;
    left: 0;
    width: 40%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--blush), var(--crimson-hi) 55%, var(--crimson));
    box-shadow: 0 0 10px -2px var(--glow);
    transition: left 0.12s linear;
}

/* Pendant qu'on tire le pouce, il suit le curseur sans amortissement. */
.gcarousel.is-seeking .gcarousel__bar > i { transition: none; }

/* Incitation au geste : visible tant que le visiteur n'a pas fait glisser. */
.gcarousel__hint {
    position: absolute;
    right: 0.35rem;
    bottom: 1.15rem;
    z-index: 3;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 0.26rem 0.5rem 0.26rem 0.62rem;
    border-radius: 999px;
    font-family: var(--f-display);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    color: #fff;
    background: rgba(12, 7, 16, 0.82);
    border: 1px solid var(--line-2);
    backdrop-filter: blur(6px);
    box-shadow: 0 6px 18px -8px rgba(0, 0, 0, 0.9);
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--t);
}
.gcarousel__hint svg {
    width: 13px; height: 13px;
    animation: hint-nudge 1.5s var(--ease-io) infinite;
}
.gcarousel.has-overflow:not(.is-touched) .gcarousel__hint { opacity: 1; }

@keyframes hint-nudge {
    0%, 100% { transform: translateX(-2px); opacity: 0.55; }
    50%      { transform: translateX(2px);  opacity: 1; }
}

/* ---- Pointeur fin (PC) : une vraie barre de défilement, aux couleurs du site
   ------------------------------------------------------------------------
   À la souris on attend une barre qu'on peut saisir. Elle remplace alors la
   barre de progression, qui n'aurait fait que la doubler. */
/* ---- Pointeur fin (PC) : la barre devient une vraie poignée -------------
   À la souris on attend de pouvoir saisir et tirer la barre. Elle s'épaissit,
   se dote d'une piste lisible et réagit au survol. L'estompe des bords et
   l'incitation au geste n'ont plus lieu d'être : la barre dit tout. */
@media (pointer: fine) {
    .gcarousel { padding-bottom: 0.85rem; }

    .gcarousel__bar {
        height: 9px;
        background: rgba(255, 255, 255, 0.07);
        border: 1px solid rgba(255, 255, 255, 0.07);
        cursor: pointer;
    }
    .gcarousel__bar > i {
        top: 1px; bottom: 1px;
        box-shadow: 0 0 12px -3px var(--glow), inset 0 1px 0 rgba(255, 255, 255, 0.25);
    }
    .gcarousel__bar:hover > i,
    .gcarousel.is-seeking .gcarousel__bar > i {
        background: linear-gradient(90deg, #ffa8c6, var(--blush) 55%, var(--crimson-hi));
    }
    .gcarousel.is-seeking .gcarousel__bar { cursor: grabbing; }

    .gcarousel.has-overflow .gcards,
    .gcarousel.has-overflow.at-start .gcards,
    .gcarousel.has-overflow.at-end .gcards {
        -webkit-mask-image: none;
                mask-image: none;
    }

    .gcarousel__hint { display: none; }
}

.gcard {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: none;
    /* Calibré pour qu'une 3e carte dépasse sur mobile : on comprend
       d'un coup d'œil que le carrousel se fait défiler. */
    width: 172px;
    scroll-snap-align: start;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid var(--line);
    background: var(--void-3);
    isolation: isolate;
    transition: transform var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
    animation: msg-in 0.5s var(--ease-spring) both;
    animation-delay: calc(var(--i, 0) * 70ms);
}
.gcard:hover {
    transform: translateY(-3px);
    border-color: var(--line-hot);
    box-shadow: 0 14px 34px -14px rgba(0, 0, 0, 0.9), 0 0 24px -10px var(--glow);
}

.gcard__media {
    position: relative;
    display: block;
    aspect-ratio: 2 / 3;
    overflow: hidden;
    background: #0b0610;
}

/* La vignette est une vidéo muette en boucle : elle occupe la carte comme
   le ferait une image, et le poster tient l'espace tant qu'elle n'a pas
   démarré (preload="none" → aucun octet avant l'entrée à l'écran). */
.gcard__video {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center 12%;
    transition: transform 0.9s var(--ease);
    user-select: none;
    -webkit-user-drag: none;
    pointer-events: none;
}
.gcard:hover .gcard__video { transform: scale(1.055); }

.gcard__media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(7, 4, 10, 0.5) 0%, transparent 34%, transparent 46%, rgba(7, 4, 10, 0.9) 100%);
}

/* Pastille « En live » — le point vert reprend celui d'Ava en tête de
   conversation : c'est le même signal de présence, donc il se lit sans
   effort. Le fond reste neutre pour que le vert porte seul le message. */
.gcard__live {
    position: absolute;
    z-index: 1;
    top: 0.5rem;
    left: 0.5rem;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.26rem 0.56rem 0.26rem 0.5rem;
    border-radius: 999px;
    font-family: var(--f-display);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: #fff;
    background: rgba(9, 5, 13, 0.66);
    border: 1px solid rgba(53, 224, 143, 0.34);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(7px) saturate(130%);
    -webkit-backdrop-filter: blur(7px) saturate(130%);
}

/* Point vert + onde qui se propage : elle est là, maintenant.
   Keyframe dédiée plutôt que `presence` : celle-ci réécrit tout le
   box-shadow à chaque étape, ce qui effacerait la lueur du point. */
.gcard__live i {
    width: 7px; height: 7px;
    flex: none;
    border-radius: 50%;
    background: #35e08f;
    animation: live-presence 2.4s var(--ease-io) infinite;
}

@keyframes live-presence {
    0%   { box-shadow: 0 0 0 0 rgba(53, 224, 143, 0.55), 0 0 7px rgba(53, 224, 143, 0.85); }
    70%  { box-shadow: 0 0 0 7px rgba(53, 224, 143, 0),   0 0 7px rgba(53, 224, 143, 0.85); }
    100% { box-shadow: 0 0 0 0 rgba(53, 224, 143, 0),     0 0 7px rgba(53, 224, 143, 0.85); }
}

/* Cartouche de scène (« Dans sa chambre », « Sur son canapé »… ) */
.gcard__scene {
    position: absolute;
    z-index: 1;
    inset-inline: 0.55rem;
    bottom: 1.85rem;
    display: block;
    font-family: var(--f-text);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    color: rgba(255, 255, 255, 0.82);
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.85);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gcard__id {
    position: absolute;
    z-index: 1;
    inset-inline: 0.55rem;
    bottom: 0.42rem;
    display: flex;
    align-items: baseline;
    gap: 5px;
    font-family: var(--f-display);
    font-size: 0.875rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #fff;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.7);
}
.gcard__id em {
    font-style: normal;
    font-weight: 500;
    font-size: 0.703rem;
    color: rgba(255, 255, 255, 0.72);
    font-variant-numeric: tabular-nums;
}

.gcard__cta {
    display: block;
    padding: 0.52rem 0.4rem;
    text-align: center;
    font-family: var(--f-display);
    font-size: 0.734rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    color: #fff;
    background: linear-gradient(118deg, var(--crimson-hi), var(--crimson) 55%, #a30f47);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
    transition: filter var(--t-fast);
}
.gcard:hover .gcard__cta { filter: brightness(1.15); }

/* ------------------------------------------------------------------
   Indicateur de saisie — la marque incarnée
   ------------------------------------------------------------------ */

.msg--typing .msg__bubble {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 0.85rem 1rem;
    min-height: 40px;
}

.msg--typing { animation: msg-in 0.4s var(--ease-spring) both; }
.msg--typing.is-leaving { animation: typing-out 0.22s var(--ease) both; }

@keyframes typing-out {
    to { opacity: 0; transform: translateY(6px) scale(0.9); }
}

.typing-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--crimson-hi);
    box-shadow: 0 0 8px rgba(232, 68, 122, 0.9);
    animation: typing-bounce 1.25s var(--ease-io) infinite;
}
.typing-dot:nth-child(2) { animation-delay: 0.15s; }
.typing-dot:nth-child(3) { animation-delay: 0.3s; }

@keyframes typing-bounce {
    0%, 58%, 100% { opacity: 0.35; transform: translateY(0) scale(0.92); }
    26%           { opacity: 1;    transform: translateY(-3.5px) scale(1); }
}

/* --------------------------------------------------------------------------
   7. Bouton « revenir en bas »
   -------------------------------------------------------------------------- */

.chat__jump {
    position: absolute;
    right: 0.9rem;
    bottom: calc(84px + var(--kb) + env(safe-area-inset-bottom));
    z-index: 6;
    display: grid;
    place-items: center;
    width: 42px; height: 42px;
    border-radius: 50%;
    background: rgba(14, 7, 18, 0.85);
    border: 1px solid var(--line-2);
    color: var(--ink-2);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.9);
    opacity: 0;
    transform: translateY(10px) scale(0.85);
    pointer-events: none;
    transition: opacity var(--t-fast), transform var(--t-fast), border-color var(--t-fast);
}
.chat__jump.is-shown {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}
.chat__jump:hover { border-color: var(--line-hot); color: var(--ink); }
.chat__jump svg { width: 19px; height: 19px; }

/* --------------------------------------------------------------------------
   8. Composer
   -------------------------------------------------------------------------- */

.chat__composer {
    position: relative;
    z-index: 5;
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    flex: none;
    padding: 0.6rem 0.75rem calc(0.6rem + env(safe-area-inset-bottom));
    background: rgba(10, 5, 14, 0.82);
    border-top: 1px solid var(--line);
    backdrop-filter: blur(24px) saturate(160%);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
}
.chat__composer::before {
    content: '';
    position: absolute;
    inset-inline: 22%;
    top: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--line-hot), transparent);
}

.composer__extra,
.composer__emoji {
    display: grid;
    place-items: center;
    flex: none;
    color: var(--ink-3);
    transition: color var(--t-fast), background var(--t-fast), transform var(--t-fast);
}

.composer__extra {
    width: 42px; height: 42px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--glass);
}
.composer__extra:hover { color: var(--ink); border-color: var(--line-2); transform: rotate(90deg); }
.composer__extra svg { width: 19px; height: 19px; }

.composer__field {
    position: relative;
    display: flex;
    align-items: flex-end;
    flex: 1;
    min-width: 0;
    border-radius: 22px;
    background: var(--glass-2);
    border: 1px solid var(--line);
    transition: border-color var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
}
.composer__field:focus-within {
    border-color: var(--line-hot);
    background: var(--glass-3);
    box-shadow: 0 0 0 3px var(--glow-soft), 0 0 24px -6px var(--glow-soft);
}

.composer__input {
    flex: 1;
    min-width: 0;
    max-height: 118px;
    padding: 0.6rem 0.15rem 0.6rem 1rem;
    resize: none;
    font-size: 16px; /* < 16px = zoom automatique iOS au focus */
    line-height: 1.4;
    letter-spacing: -0.008em;
    caret-color: var(--crimson-hi);
    scrollbar-width: none;
}
.composer__input::-webkit-scrollbar { display: none; }
.composer__input::placeholder { color: var(--ink-4); }
.composer__input:focus { outline: none; }

.composer__emoji {
    width: 40px; height: 42px;
    padding-right: 4px;
}
.composer__emoji:hover,
.composer__emoji.is-active { color: var(--blush); }
.composer__emoji svg { width: 20px; height: 20px; }

/* Palette d'émojis : petit panneau de verre ancré au-dessus du composer */
.epicker {
    position: absolute;
    right: 3.4rem;
    bottom: calc(100% + 10px);
    z-index: 40;
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    width: min(318px, calc(100vw - 4.5rem));
    padding: 0.5rem;
    border-radius: 18px;
    background: rgba(24, 13, 32, 0.96);
    border: 1px solid var(--line-2);
    backdrop-filter: blur(24px) saturate(150%);
    -webkit-backdrop-filter: blur(24px) saturate(150%);
    box-shadow:
        0 26px 60px -18px rgba(0, 0, 0, 0.95),
        0 0 44px -16px var(--glow);
    transform-origin: 88% 100%;
    animation: epicker-in 0.32s var(--ease-spring) both;
}
.epicker[hidden] { display: none; }

/* Filet lumineux, signature maison */
.epicker::before {
    content: '';
    position: absolute;
    inset-inline: 20%;
    top: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--line-hot), transparent);
}

@keyframes epicker-in {
    from { opacity: 0; transform: translateY(10px) scale(0.88); }
    to   { opacity: 1; transform: none; }
}

.epicker__item {
    display: grid;
    place-items: center;
    height: 40px;
    font-size: 1.3rem;
    line-height: 1;
    border-radius: 10px;
    transition: background var(--t-fast), transform var(--t-fast);
}
.epicker__item:hover { background: var(--glass-3); transform: scale(1.16); }
.epicker__item:active { transform: scale(0.92); }

/* Envoi : éteint tant que le champ est vide, s'embrase dès le premier mot */
.composer__send {
    display: grid;
    place-items: center;
    flex: none;
    width: 42px; height: 42px;
    border-radius: 50%;
    color: var(--ink-4);
    background: var(--glass-2);
    border: 1px solid var(--line);
    transition: background var(--t-fast), color var(--t-fast), transform var(--t-fast),
                box-shadow var(--t-fast), border-color var(--t-fast);
}
.composer__send svg {
    width: 19px; height: 19px;
    transform: translateX(-1px) rotate(0deg);
    transition: transform var(--t-fast);
}
.composer__send:disabled { cursor: default; }

/* ------------------------------------------------------------------
   Attente de réponse — un seul message à la fois
   ------------------------------------------------------------------
   Tant qu'Ava n'a pas répondu, on ne peut pas empiler un second message.
   Le champ reste éditable à dessein : le passer en `readonly` ferait
   replier le clavier iOS à chaque tour de conversation. */
.chat__composer.is-waiting .composer__field {
    opacity: 0.62;
    border-color: var(--line);
}
.chat__composer.is-waiting .composer__send { opacity: 0.5; }

/* Tentative d'envoi pendant l'attente : le composer refuse d'un petit
   mouvement, plutôt que de ne rien faire en silence. */
.chat__composer.is-refusing .composer__field { animation: composer-refuse 0.32s var(--ease-io); }

@keyframes composer-refuse {
    0%, 100% { transform: translateX(0); }
    25%      { transform: translateX(-4px); }
    75%      { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
    .chat__composer.is-refusing .composer__field { animation: none; }
}

.composer__send.is-armed {
    color: #fff;
    border-color: transparent;
    background: linear-gradient(128deg, var(--crimson-hi), var(--crimson) 58%, #a30f47);
    box-shadow: 0 8px 26px -8px var(--glow), inset 0 1px 0 rgba(255, 255, 255, 0.22);
    animation: send-arm 0.35s var(--ease-spring);
}
.composer__send.is-armed:hover { transform: translateY(-2px); }
.composer__send.is-armed:active { transform: scale(0.9); }
.composer__send.is-armed:active svg { transform: translateX(2px) rotate(-18deg); }

@keyframes send-arm {
    from { transform: scale(0.82); }
    55%  { transform: scale(1.08); }
    to   { transform: scale(1); }
}

/* --------------------------------------------------------------------------
   9. Desktop — scène cinéma : volet éditorial + panneau de verre
   -------------------------------------------------------------------------- */

@media (min-width: 1024px) {

    .stage {
        align-items: center;
        gap: clamp(0.9rem, 2.2vh, 1.5rem);
        padding: clamp(1.1rem, 2.6vh, 1.9rem) clamp(1.5rem, 4vw, 3rem) clamp(1.2rem, 3vh, 2rem);
    }

    /* ------ Bandeau : logo + titre, au-dessus du voile ------ */

    .hero {
        position: relative;
        z-index: 2; /* jamais assombri par la pénombre */
        display: flex;
        flex-direction: column;
        align-items: center;
        flex: none;
        gap: 0.8rem;
        text-align: center;
        animation: hero-in 0.9s var(--ease) both;
    }

    @keyframes hero-in {
        from { opacity: 0; transform: translateY(-16px); }
        to   { opacity: 1; transform: none; }
    }

    /* Hors du .hero animé : un ancêtre avec transform capturerait le
       position:fixed et le logo quitterait le coin de l'écran. */
    .brand {
        position: fixed;
        top: 1.3rem;
        left: 1.7rem;
        z-index: 3; /* au-dessus du voile, pleine opacité */
        display: inline-flex;
        align-items: center;
        gap: 11px;
    }
    .brand__mark { width: 34px; height: 34px; flex: none; }
    .brand__text { display: flex; flex-direction: column; line-height: 1; }
    .brand__name {
        font-family: var(--f-display);
        font-size: 1.06rem;
        font-weight: 700;
        letter-spacing: -0.035em;
        white-space: nowrap;
    }
    .brand__name em {
        font-style: normal;
        margin-left: 0.22em;
        background: linear-gradient(102deg, var(--blush), var(--crimson-hi) 55%, var(--plum));
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }
    .brand__sub {
        font-size: 0.594rem;
        letter-spacing: 0.22em;
        text-transform: uppercase;
        color: var(--ink-3);
        margin-top: 3px;
    }

    .brand__dot { transform-origin: center; animation: brand-typing 1.5s var(--ease-io) infinite; }
    .brand__dot--2 { animation-delay: 0.18s; }
    .brand__dot--3 { animation-delay: 0.36s; }

    @keyframes brand-typing {
        0%, 62%, 100% { opacity: 0.45; transform: translateY(0); }
        28%           { opacity: 1;    transform: translateY(-2.2px); }
    }

    .hero__eyebrow {
        display: inline-flex;
        align-items: center;
        gap: 10px;
        font-family: var(--f-display);
        font-size: 0.688rem;
        font-weight: 600;
        letter-spacing: 0.22em;
        text-transform: uppercase;
        color: var(--ink-2);
    }
    .hero__eyebrow::before,
    .hero__eyebrow::after {
        content: '';
        width: 26px; height: 1px;
    }
    .hero__eyebrow::before { background: linear-gradient(90deg, transparent, var(--crimson-hi)); }
    .hero__eyebrow::after  { background: linear-gradient(90deg, var(--crimson-hi), transparent); }

    .hero__title {
        font-family: var(--f-display);
        font-size: clamp(1.9rem, 3vw, 2.8rem);
        font-weight: 800;
        line-height: 1;
        letter-spacing: -0.045em;
    }
    .serif {
        font-family: var(--f-serif);
        font-style: italic;
        font-weight: 400;
        letter-spacing: -0.02em;
        background: linear-gradient(104deg, var(--blush) 0%, var(--crimson-hi) 42%, var(--plum) 100%);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }

    /* Curseur d'écriture qui clignote au bout du titre */
    .hero__cursor {
        display: inline-block;
        width: 3px;
        height: 0.78em;
        margin-left: 0.12em;
        border-radius: 2px;
        background: var(--crimson-hi);
        box-shadow: 0 0 12px var(--crimson-hi);
        animation: caret 1.1s steps(2) infinite;
        vertical-align: baseline;
    }
    @keyframes caret { 50% { opacity: 0; } }

    .hero__facts {
        list-style: none;
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 0.5rem;
    }
    .hero__facts li {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 0.42rem 0.9rem;
        border-radius: var(--r-pill);
        background: var(--glass);
        border: 1px solid var(--line);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        font-size: 0.781rem;
        font-weight: 500;
        color: var(--ink-2);
        white-space: nowrap;
    }
    .hero__facts svg { width: 15px; height: 15px; color: var(--crimson-hi); flex: none; }

    .pulse-dot {
        width: 7px; height: 7px;
        border-radius: 50%;
        background: #35e08f;
        box-shadow: 0 0 0 0 rgba(53, 224, 143, 0.6);
        animation: presence 2.4s var(--ease-io) infinite;
        flex: none;
    }

    /* ------ Rangée centrale : portrait + chat ------ */

    .duo {
        display: flex;
        align-items: stretch;
        justify-content: center;
        gap: clamp(1rem, 1.8vw, 1.6rem);
        flex: 1;
        min-height: 0;
        width: 100%;
        position: relative;
        z-index: 2;
    }

    /* L'encart « à qui tu parles » : un portrait vertical sous néon */
    .portrait {
        position: relative;
        display: block;
        flex: none;
        width: clamp(240px, 22vw, 330px);
        border-radius: 30px;
        overflow: hidden;
        border: 1px solid rgba(255, 255, 255, 0.15);
        isolation: isolate;
        animation:
            portrait-in 0.9s var(--ease) 0.05s both,
            portrait-neon 4.5s var(--ease-io) 1.2s infinite alternate;
    }

    @keyframes portrait-in {
        from { opacity: 0; transform: translateX(-26px) scale(0.98); }
        to   { opacity: 1; transform: none; }
    }

    @keyframes portrait-neon {
        from {
            box-shadow:
                0 46px 120px -32px rgba(0, 0, 0, 1),
                0 0 0 1px rgba(232, 68, 122, 0.26),
                0 20px 80px -22px rgba(203, 18, 88, 0.5),
                0 44px 130px -30px rgba(109, 47, 156, 0.5);
        }
        to {
            box-shadow:
                0 46px 120px -32px rgba(0, 0, 0, 1),
                0 0 0 1px rgba(232, 68, 122, 0.42),
                0 24px 100px -18px rgba(203, 18, 88, 0.7),
                0 52px 160px -26px rgba(109, 47, 156, 0.7);
        }
    }

    .portrait img {
        width: 100%; height: 100%;
        object-fit: cover;
        object-position: center top;
    }

    .portrait__veil {
        position: absolute;
        inset: 0;
        background: linear-gradient(180deg,
            rgba(7, 4, 10, 0.2) 0%,
            transparent 26%,
            transparent 52%,
            rgba(7, 4, 10, 0.88) 100%);
    }

    /* « Ava » en enseigne néon, posée sur le portrait */
    .portrait__name {
        position: absolute;
        left: 1.35rem;
        bottom: 2.9rem;
        z-index: 1;
        font-family: var(--f-serif);
        font-style: italic;
        font-size: clamp(2.8rem, 3.6vw, 3.8rem);
        line-height: 1;
        color: #fff;
        animation: name-neon 4.5s var(--ease-io) infinite alternate;
    }

    @keyframes name-neon {
        from {
            text-shadow:
                0 0 5px rgba(255, 255, 255, 0.35),
                0 0 14px rgba(232, 68, 122, 0.85),
                0 0 34px rgba(232, 68, 122, 0.65),
                0 0 70px rgba(203, 18, 88, 0.55);
        }
        to {
            text-shadow:
                0 0 7px rgba(255, 255, 255, 0.5),
                0 0 20px rgba(232, 68, 122, 1),
                0 0 46px rgba(232, 68, 122, 0.85),
                0 0 96px rgba(203, 18, 88, 0.75);
        }
    }

    .portrait__status {
        position: absolute;
        left: 1.45rem;
        bottom: 1.25rem;
        z-index: 1;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        font-size: 0.781rem;
        font-weight: 500;
        color: rgba(255, 255, 255, 0.88);
    }

    /* ------ Panneau de chat ------ */

    /* Le voile : toute la page — volet éditorial compris — bascule dans la
       pénombre. Seule la zone du chat reste dégagée, cerclée d'une aura
       chaude. C'est lui la source de lumière, le reste est le décor. */
    .stage::before {
        content: '';
        position: fixed;
        inset: 0;
        z-index: 1;
        pointer-events: none;
        background:
            radial-gradient(64vw 88vh at 50% 55%, rgba(232, 68, 122, 0.12), transparent 60%),
            radial-gradient(150% 135% at 50% 55%, rgba(2, 1, 4, 0.28) 16%, rgba(2, 1, 4, 0.82) 74%);
    }

    /* Le chat domine l'écran : c'est une vraie messagerie, pas une vitrine.
       C'est la surface la plus claire de la page — un écran allumé dans le
       noir — posée sur un néon qui respire. */
    .chat {
        flex: 0 1 900px;
        min-width: 0;
        height: 100%;
        border-radius: 30px;
        border: 1px solid rgba(255, 255, 255, 0.17);
        background: linear-gradient(180deg, #281a39 0%, #1c1029 40%, #150b20 100%);
        overflow: hidden;
        animation:
            chat-in 0.9s var(--ease) 0.12s both,
            chat-neon 4.5s var(--ease-io) 1s infinite alternate;
        /* Le clavier virtuel ne concerne que le mobile */
        padding-bottom: 0;
    }

    /* Néon sous le panneau : l'ombre portée est remplacée par une lueur
       crimson/grape qui pulse lentement — l'écran semble sous tension. */
    @keyframes chat-neon {
        from {
            box-shadow:
                0 70px 160px -40px rgba(0, 0, 0, 1),
                0 0 0 1px rgba(232, 68, 122, 0.34),
                0 14px 60px -10px rgba(232, 68, 122, 0.62),
                0 44px 130px -22px rgba(203, 18, 88, 0.62),
                0 70px 190px -30px rgba(109, 47, 156, 0.65);
        }
        to {
            box-shadow:
                0 70px 160px -40px rgba(0, 0, 0, 1),
                0 0 0 1px rgba(232, 68, 122, 0.5),
                0 14px 84px -6px rgba(232, 68, 122, 0.9),
                0 50px 170px -18px rgba(203, 18, 88, 0.82),
                0 84px 230px -26px rgba(109, 47, 156, 0.85);
        }
    }

    /* Papier peint du fil : le panneau a sa propre matière intérieure,
       distincte du décor de la page — comme un fond de messagerie. */
    .chat__scroll {
        background:
            radial-gradient(90% 60% at 50% 0%, rgba(203, 18, 88, 0.10), transparent 60%),
            radial-gradient(80% 55% at 50% 110%, rgba(109, 47, 156, 0.12), transparent 62%),
            radial-gradient(1.2px 1.2px at 22% 34%, rgba(255, 255, 255, 0.05) 99%, transparent),
            radial-gradient(1.2px 1.2px at 64% 12%, rgba(255, 255, 255, 0.045) 99%, transparent),
            radial-gradient(1.2px 1.2px at 81% 58%, rgba(255, 255, 255, 0.05) 99%, transparent),
            radial-gradient(1.2px 1.2px at 38% 76%, rgba(255, 255, 255, 0.04) 99%, transparent),
            radial-gradient(1.2px 1.2px at 9% 87%, rgba(255, 255, 255, 0.045) 99%, transparent);
        background-size:
            100% 100%, 100% 100%,
            240px 240px, 240px 240px, 240px 240px, 240px 240px, 240px 240px;
    }

    /* En-tête et composer plus denses : des surfaces d'application,
       pas des voiles translucides. */
    .chat__head,
    .chat__composer {
        background: rgba(32, 19, 44, 0.9);
        border-color: rgba(255, 255, 255, 0.12);
    }

    /* L'intérieur suit : bulles et champ un cran plus lumineux que
       partout ailleurs sur la page. */
    .msg--her .msg__bubble {
        background: rgba(255, 216, 233, 0.085);
        border-color: rgba(255, 255, 255, 0.13);
    }
    .composer__field {
        background: rgba(255, 255, 255, 0.07);
        border-color: rgba(255, 255, 255, 0.14);
    }

    @keyframes chat-in {
        from { opacity: 0; transform: translateY(30px) scale(0.97); }
        to   { opacity: 1; transform: none; }
    }

    /* Filet lumineux au sommet du panneau */
    .chat::before {
        content: '';
        position: absolute;
        inset-inline: 8%;
        top: 0;
        height: 1px;
        z-index: 7;
        background: linear-gradient(90deg, transparent, rgba(255, 122, 168, 0.9), transparent);
        filter: drop-shadow(0 0 6px rgba(232, 68, 122, 0.8));
    }

    .chat__head { padding: 0.85rem 1.15rem; }
    .chat__thread { padding: 1.4rem 1.6rem 1.2rem; max-width: 900px; }
    .chat__composer { padding: 0.75rem 1rem; }
    .chat__jump { bottom: 88px; right: 1.2rem; }
    .msg { max-width: 68%; }
    .msg--cards { max-width: min(88%, 780px); }
    .gcard { width: 204px; }
}

/* Écrans intermédiaires : le panneau reste plein écran mais respire */
@media (min-width: 640px) and (max-width: 1023px) {
    .chat__thread { padding-inline: 1.4rem; }
}

/* --------------------------------------------------------------------------
   10. Préférences système
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
    .scene__orb, .scene__bubble, .scene__streak { translate: 0 0; }
}

@media (prefers-contrast: more) {
    :root {
        --ink-2: rgba(255, 255, 255, 0.86);
        --ink-3: rgba(255, 255, 255, 0.68);
        --line: rgba(255, 255, 255, 0.22);
        --line-2: rgba(255, 255, 255, 0.34);
        --bubble-her: rgba(255, 255, 255, 0.12);
    }
}
