/*  L'assistant : le lanceur present partout, la modale, et la page pleine.
 *
 *  Un seul fichier pour les trois, parce que le fil de conversation est le
 *  meme objet dans les deux cadres. Charge globalement depuis base.html.twig :
 *  le lanceur vit sur tous les ecrans de l'application.  */

/* ── Le lanceur ─────────────────────────────────────────────────────────── */

/*  UNE LANGUETTE COLLEE AU BORD DROIT, A MI-HAUTEUR.
 *
 *  Le modele est celui des onglets « chat » qu'on trouve sur les sites de
 *  service : un rectangle vertical soude au bord de l'ecran, l'icone en
 *  haut, le nom ecrit dans le sens de la hauteur. Il a un avantage sur la
 *  boule qu'il remplace — IL DIT CE QU'IL EST SANS QU'ON LE SURVOLE. La
 *  boule ne montrait son mot qu'au pointeur, donc jamais au doigt : sur
 *  telephone, elle restait une pastille muette.
 *
 *  ELLE EST VIOLETTE, ET CE N'EST PAS UN CHOIX DE GOUT.
 *
 *  Stackly donne une teinte a chacun de ses outils et s'y tient partout —
 *  Documents en indigo, Stock en turquoise, Finance en vert. La languette
 *  etait le dernier element de l'interface a ne pas dire quel outil elle
 *  ouvrait : noire, comme n'importe quel bouton primaire. Elle porte donc
 *  la teinte du module, celle qu'on voit deja sur son icone dans la barre
 *  laterale. Le gris du modele d'origine avait le defaut inverse du noir :
 *  il ne disait rien ET ne se voyait pas.
 *
 *  ELLE GRANDIT, ELLE NE GLISSE PAS. Ancree a `right: 0`, elle ne s'etend
 *  que vers l'interieur : la zone survolee ne fait que s'agrandir, et le
 *  point qu'on survole y reste. Une version precedente la faisait
 *  coulisser, et le pointeur se retrouvait hors du bouton une fois
 *  celui-ci deploye — elle battait alors indefiniment.
 *
 *  A mi-hauteur, elle ne rencontre rien : les pages ont leur gouttiere, et
 *  aucun controle ne vit contre le bord a cette hauteur. C'est ce qui a
 *  regle le recouvrement de la pagination.  */

.as-lanceur {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1040;

    width: 27px;
    padding: var(--space-4) 0 var(--space-5);
    border: none;
    /*  Soudee au bord : seuls les coins interieurs sont arrondis. */
    border-radius: var(--radius-card) 0 0 var(--radius-card);
    background: var(--mod-assistant);
    color: var(--ink-on-dark);
    box-shadow: var(--shadow-2);
    cursor: pointer;

    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);

    transition: width .2s var(--ease), background .2s var(--ease), box-shadow .2s var(--ease);
}

/*  L'icone reste droite. Seul le mot bascule : une icone couchee se
    reconnait moins bien qu'un mot lu de bas en haut.  */
.as-lanceur > i {
    font-size: 18px;
    line-height: 1;
}

/*  `vertical-rl` puis demi-tour : sans la rotation, le texte se lit de haut
    en bas, la tete a droite. Les onglets de bord se lisent de bas en haut.  */
.as-lanceur-mot {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-family: var(--font-ui);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/*  Anneau POSE A L'INTERIEUR : la languette touche le bord de l'ecran, un
    contour exterieur serait coupe sur sa moitie droite.  */
.as-lanceur:focus-visible {
    outline: 2px solid var(--ink-on-dark);
    outline-offset: -5px;
}

@media (hover: hover) and (pointer: fine) {
    .as-lanceur:hover,
    .as-lanceur:focus-visible {
        width: 48px;
        background: var(--mod-assistant-ink);
        box-shadow: var(--shadow-3);
    }
}

@media (prefers-reduced-motion: reduce) {
    .as-lanceur { transition: none; }
}

/*  Au doigt, la languette garde le plancher tactile en largeur. Le mot, lui,
    reste : c'est tout l'interet du modele, et la boule precedente ne le
    montrait jamais sur telephone.  */
@media (hover: none) {
    .as-lanceur { width: var(--touch-target); }
}

/*  Pendant que la modale est ouverte, le lanceur n'a plus de role : il
    transparait sous le voile, qui ne l'assombrit qu'a 38 %.  */
body:has(.as-modale:not([hidden])) .as-lanceur { display: none; }

/* ── L'ouverture et la fermeture ────────────────────────────────────────
   La modale apparaissait d'un coup, sans transition : on ne voyait pas d'ou
   elle venait, et le passage d'un ecran a l'autre etait brutal.

   Elle vient donc de la DROITE, la ou se trouve la languette qu'on vient de
   cliquer. Le mouvement est court — l'ouverture d'un panneau n'est pas un
   spectacle, elle sert seulement a relier le geste a son resultat. */

@keyframes as-voile-entre {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes as-voile-sort {
    from { opacity: 1; }
    to   { opacity: 0; }
}

@keyframes as-dialogue-entre {
    from { opacity: 0; transform: translateX(26px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

@keyframes as-dialogue-sort {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateX(20px) scale(.99); }
}

.as-modale .ui-modal-backdrop { animation: as-voile-entre .18s var(--ease) both; }
.as-modale .ui-modal-dialog   { animation: as-dialogue-entre .24s var(--ease) both; }

.as-modale.est-en-fermeture .ui-modal-backdrop { animation: as-voile-sort .15s var(--ease) both; }
.as-modale.est-en-fermeture .ui-modal-dialog   { animation: as-dialogue-sort .17s var(--ease) both; }

/*  Sur telephone la modale occupe tout l'ecran : elle monte depuis le bas,
    comme une feuille, plutot que de venir du cote.  */
@media (max-width: 768px) {
    @keyframes as-dialogue-entre {
        from { opacity: 0; transform: translateY(22px); }
        to   { opacity: 1; transform: none; }
    }

    @keyframes as-dialogue-sort {
        from { opacity: 1; transform: none; }
        to   { opacity: 0; transform: translateY(16px); }
    }
}

/*  Qui demande moins de mouvement n'en recoit aucun — mais la modale doit
    quand meme apparaitre et disparaitre.  */
@media (prefers-reduced-motion: reduce) {
    .as-modale .ui-modal-backdrop,
    .as-modale .ui-modal-dialog,
    .as-modale.est-en-fermeture .ui-modal-backdrop,
    .as-modale.est-en-fermeture .ui-modal-dialog {
        animation-duration: .01ms;
    }
}

/* ── La modale : 85 % de l'ecran ─────────────────────────────────────────
   On y lit un rapport structure, pas deux repliques : l'etroitesse d'une
   modale ordinaire y gaspillait la moitie de l'ecran.
   Les 85 % comptent l'en-tete, sinon la modale depasserait la hauteur
   demandee de la barre de titre. */

.as-modale { padding: var(--space-4) 0; }

.as-modale .ui-modal-dialog {
    width: 85vw;
    max-width: 1500px;
    /*  Le dialogue commun porte une gouttiere laterale ; la garder rognerait
        les 85 % demandes de deux fois la largeur de cette gouttiere. */
    padding: 0;
}

.as-modale .ui-modal-content {
    height: 85vh;
    max-height: 1000px;
    display: flex;
    flex-direction: column;
}

.as-modale .ui-modal-header { flex: none; }

.as-modale .ui-modal-body {
    padding: 0;
    flex: 1;
    min-height: 0;
    max-height: none;
    overflow: hidden;
    display: flex;
}

/*  Plein ecran sur telephone : 90 % d'un ecran de 390 px laisse des marges
    inutiles alors que chaque ligne compte.  */
@media (max-width: 768px) {
    .as-modale { padding: 0; align-items: stretch; }
    .as-modale .ui-modal-dialog { width: 100%; max-width: none; margin: 0; padding: 0; }
    .as-modale .ui-modal-content { border: none; border-radius: 0; height: 100dvh; display: flex; flex-direction: column; }
    .as-modale .ui-modal-body { flex: 1; min-height: 0; display: flex; }
}

/* ── Le fil ─────────────────────────────────────────────────────────────── */

.as {
    display: grid;
    grid-template-columns: 250px minmax(0, 1fr);
    /*  La grille ne doit jamais depasser son cadre : `minmax(0, …)` partout,
        et les deux colonnes autorisees a se retrecir sous leur contenu.  */
    max-width: 100%;
    min-height: 0;
    width: 100%;
}

/*  Sans clef d'API il n'y a ni fil ni historique : le message occupe seul
    toute la largeur.  */
.as:has(.as-indisponible) { grid-template-columns: 1fr; }

.as-colonne {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
}

/* ── L'historique ───────────────────────────────────────────────────────── */

.as-historique {
    display: flex;
    flex-direction: column;
    min-height: 0;
    /*  Sans cela, la bande de conversations qui defile horizontalement impose
        sa largeur de contenu a la colonne de grille : `1fr` ne descend jamais
        sous le minimum de son contenu. Le panneau faisait 869 px dans une
        fenetre de 500.  */
    min-width: 0;
    border-right: 1px solid var(--border-subtle);
    background: var(--surface-muted);
}

.as-historique-tete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-4) var(--space-3);
}

.as-historique-titre {
    margin: 0;
    font-size: var(--text-label);
    font-weight: var(--weight-semibold);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.as-neuf {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--ink);
    font-family: inherit;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    cursor: pointer;
}

.as-neuf:hover { border-color: var(--mod-assistant); color: var(--mod-assistant-ink); }
.as-neuf:focus-visible { outline: 2px solid var(--mod-assistant); outline-offset: 2px; }

.as-liste {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    margin: 0;
    padding: 0 var(--space-3) var(--space-4);
    list-style: none;
}

.as-liste-item {
    display: block;
    width: 100%;
    padding: var(--space-3);
    border: none;
    border-radius: var(--radius-field);
    background: none;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
}

.as-liste-item:hover { background: var(--surface); }
.as-liste-item:focus-visible { outline: 2px solid var(--mod-assistant); outline-offset: -2px; }
.as-liste-item.is-courante { background: var(--mod-assistant-tint); }

.as-liste-titre {
    display: block;
    font-size: var(--text-sm);
    color: var(--ink);
    /*  Un titre est la premiere question posee : il peut etre long, et une
        liste dont chaque ligne deborde ne se parcourt plus.  */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.as-liste-item.is-courante .as-liste-titre { font-weight: var(--weight-semibold); }

.as-liste-date {
    display: block;
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}

/*  Sur telephone, l'historique passerait sous le fil et le repousserait hors
    de l'ecran : il se replie en une bande horizontale au-dessus.  */
@media (max-width: 768px) {
    .as { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }

    .as-historique {
        border-right: none;
        border-bottom: 1px solid var(--border-subtle);
    }

    .as-historique-tete { padding-bottom: var(--space-2); }

    .as-liste {
        display: flex;
        gap: var(--space-2);
        overflow-x: auto;
        overflow-y: hidden;
        padding: 0 var(--space-3) var(--space-3);
    }

    .as-liste li { flex: none; max-width: 60vw; }
    .as-liste-item { border: 1px solid var(--border); }
    .as-liste-date { display: none; }
}

.as-modale .as { height: 100%; }

@media (max-width: 768px) {
    .as-modale .as { height: auto; flex: 1; }
}

.as-flux {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    .as-flux { scroll-behavior: auto; }
}

.as-tour { display: flex; }
.as-tour--moi { justify-content: flex-end; }

/*  Le panneau s'elargit, la ligne de texte non : au-dela d'une soixantaine
    de caracteres l'oeil perd le debut de la ligne suivante. Le rapport, plus
    structure que redige, supporte un peu plus large que les repliques. */
.as-bulle {
    max-width: 58rem;
    padding: var(--space-4);
    border-radius: var(--radius-card);
    font-size: var(--text-body);
    line-height: 1.65;
    color: var(--ink-secondary);
    background: var(--surface-muted);
    border: 1px solid var(--border-subtle);
    overflow-wrap: anywhere;
}

.as-tour--moi .as-bulle {
    background: var(--mod-assistant-tint);
    border-color: transparent;
    color: var(--ink);
    max-width: 40rem;
}

/*  La mise en forme que le modele produit : des titres en gras, des listes,
    des paragraphes. Rien d'autre n'est interprete — voir assistant.js.  */
.as-bulle strong { color: var(--ink); font-weight: var(--weight-semibold); }
.as-bulle p + p  { margin-top: var(--space-3); }
.as-bulle p      { margin: 0; }
.as-bulle ul,
.as-bulle ol     { margin: var(--space-3) 0 0; padding-left: var(--space-6); }
.as-bulle li + li { margin-top: var(--space-2); }
.as-bulle li p   { margin-top: var(--space-2); }
/*  Une liste imbriquee respire moins qu'une liste de premier niveau : elle
    detaille le point qui la porte, elle ne s'en detache pas.  */
.as-bulle li > ul,
.as-bulle li > ol { margin-top: var(--space-2); padding-left: var(--space-5); }
.as-bulle ol > li { margin-top: var(--space-4); }
.as-bulle ol > li:first-child { margin-top: 0; }
.as-bulle li::marker { color: var(--ink-muted); font-weight: var(--weight-semibold); }

/*  Le modele separe ses sections par une ligne ; sans marge elle se collait
    au titre suivant et ressemblait a un soulignement.  */
.as-bulle hr {
    margin: var(--space-5) 0 var(--space-4);
    border: none;
    border-top: 1px solid var(--border);
}

/*  Le rapport d'ouverture se distingue d'une reponse : c'est lui qu'on lit en
    premier, et il porte l'essentiel de la valeur.  */
.as-tour--rapport .as-bulle {
    background: var(--surface);
    border-color: var(--border);
    border-left: 3px solid var(--mod-assistant);
}

/* ── L'etat vide : des suggestions plutot qu'un rapport impose ───────────── */

.as-vide {
    /*  Il occupe la place laissee libre et s'y centre, la saisie restant en
        bas comme dans toute conversation. Aligne en haut, il laissait un
        grand blanc sous le champ.  */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: var(--space-4);
    padding: var(--space-6);
}

.as-vide-titre {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-title-3);
    font-weight: var(--weight-semibold);
    letter-spacing: -.02em;
    color: var(--ink);
}

.as-suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.as-suggestion {
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--ink-secondary);
    font-family: inherit;
    font-size: var(--text-sm);
    text-align: left;
    cursor: pointer;
}

.as-suggestion:hover {
    border-color: var(--mod-assistant);
    color: var(--mod-assistant-ink);
    background: var(--mod-assistant-tint);
}

.as-suggestion:focus-visible { outline: 2px solid var(--mod-assistant); outline-offset: 2px; }

.as-point {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    border: none;
    border-radius: var(--radius-button);
    background: var(--mod-assistant);
    color: #FFF;
    font-family: inherit;
    font-size: var(--text-body);
    font-weight: var(--weight-medium);
    cursor: pointer;
}

.as-point:hover { background: var(--mod-assistant-ink); }
.as-point:focus-visible { outline: 2px solid var(--mod-assistant-ink); outline-offset: 2px; }

.as-vide-note {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--ink-faint);
}

/*  Quand l'etat vide est la, le fil n'a rien a montrer : il s'efface au lieu
    de reserver de la hauteur et une gouttiere pour rien.  */
.as-colonne:has(.as-vide:not([hidden])) .as-flux { flex: 0 0 auto; padding: 0; }

/* ── L'attente ──────────────────────────────────────────────────────────── */

.as-attente {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--ink-muted);
    font-size: var(--text-sm);
    padding: var(--space-3) var(--space-4);
}

.as-attente-points { display: inline-flex; gap: 4px; }

.as-attente-points i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--mod-assistant);
    animation: as-pulse 1.1s ease-in-out infinite;
}

.as-attente-points i:nth-child(2) { animation-delay: .18s; }
.as-attente-points i:nth-child(3) { animation-delay: .36s; }

@keyframes as-pulse {
    0%, 60%, 100% { opacity: .25; }
    30%           { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .as-attente-points i { animation: none; opacity: .6; }
}

/* ── La saisie ──────────────────────────────────────────────────────────── */

.as-saisie {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-6);
    border-top: 1px solid var(--border-subtle);
    background: var(--surface);
}

.as-champ {
    flex: 1;
    min-height: var(--control-md);
    max-height: 9rem;
    resize: none;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-field);
    background: var(--surface);
    color: var(--ink);
    font-family: inherit;
    font-size: var(--text-body);
    line-height: 1.5;
}

.as-champ:focus {
    outline: none;
    border-color: var(--mod-assistant);
    box-shadow: 0 0 0 3px var(--mod-assistant-tint);
}

.as-envoyer {
    flex: none;
    width: var(--control-md);
    height: var(--control-md);
    border: none;
    border-radius: var(--radius-field);
    background: var(--mod-assistant);
    color: #FFF;
    font-size: 18px;
    display: grid;
    place-items: center;
    cursor: pointer;
}

.as-envoyer:disabled { opacity: .45; cursor: not-allowed; }
.as-envoyer:focus-visible { outline: 2px solid var(--mod-assistant-ink); outline-offset: 2px; }

.as-pied {
    margin: 0;
    padding: 0 var(--space-6) var(--space-4);
    font-size: var(--text-xs);
    color: var(--ink-faint);
    background: var(--surface);
}

/* ── Indisponible, et les erreurs ───────────────────────────────────────── */

.as-indisponible {
    display: flex;
    gap: var(--space-4);
    padding: var(--space-8) var(--space-6);
    color: var(--ink-secondary);
    font-size: var(--text-body);
}

.as-indisponible i { font-size: 22px; color: var(--ink-muted); flex: none; }
.as-indisponible p { margin: 0; }
.as-indisponible-titre { font-weight: var(--weight-semibold); color: var(--ink); margin-bottom: var(--space-2) !important; }

.as-erreur {
    margin: 0 var(--space-6) var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-field);
    border: 1px solid var(--border);
    background: var(--surface-muted);
    color: var(--ink-secondary);
    font-size: var(--text-sm);
}

/* ── La page pleine ─────────────────────────────────────────────────────── */

.as-page {
    max-width: 1400px;
    margin: 0 auto;
    padding-inline: var(--gutter-page);
    padding-block: var(--space-6) var(--space-8);
}

.as-entete { margin-bottom: var(--space-6); }

.as-surtitre {
    margin: 0 0 var(--space-2);
    font-size: var(--text-label);
    font-weight: var(--weight-semibold);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.as-titre {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-title-1);
    font-weight: var(--weight-semibold);
    letter-spacing: -.028em;
    color: var(--ink);
    text-wrap: balance;
}

.as-chapo {
    margin: var(--space-3) 0 0;
    max-width: 58ch;
    color: var(--ink-secondary);
    font-size: var(--text-body-lg);
}

.as-page .as {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card-lg);
    overflow: hidden;
    /*  Ce qui reste de la fenetre une fois l'en-tete de page pose, borne des
        deux cotes : jamais ecrase sur un portable, jamais demesure sur un
        grand ecran ou la ligne deviendrait illisible. */
    height: clamp(460px, calc(100vh - 290px), 1000px);
}

/*  L'en-tete de page est bien plus court sur telephone que sur un grand
    ecran : la reserve de 290 px y laissait une centaine de pixels de vide sous
    le panneau, et autant de moins pour lire.

    Ce bloc est en FIN de fichier a dessein. Place plus haut, dans la media
    query qui regroupe le reste du mobile, il perdait contre `.as-page .as`
    — meme specificite, mais declare plus bas. La cascade ne se discute pas.  */
@media (max-width: 768px) {
    .as-page { padding-block: var(--space-4) var(--space-5); }
    .as-page .as { height: clamp(380px, calc(100dvh - 190px), 900px); }
}
