@import url("/assets/shared-3588f70f.css");
@import url("/assets/public_carts-32b64cc2.css");
@import url("/assets/public_products-f688f9f8.css");
@import url("/assets/desktop-aaa9f57f.css");

/* Gouttière latérale des pages publiques. Une valeur unique coûtait 16,4 % de
   la largeur sur un iPhone de 390 px contre 4,4 % sur un écran de 1440, et
   depuis que les grilles n'affichent qu'une carte par rangée, c'est elle qui
   décide de la taille des pochettes. Mesuré en production le 2026-08-02 :
   +32 px de visuel sur /vinyles, /medias et la fiche produit, aucun
   débordement, et desktop identique au pixel à 768 comme à 1440.
   Le seuil est celui où les grilles passent à trois colonnes, pas un de plus.
   ⚠️ Cette règle DOIT rester dans le corps du fichier : desktop.css,
   shared.css, public_carts.css et public_products.css sont @importés en tête,
   donc insérés AVANT — une media query posée là-bas serait annulée en silence
   à spécificité égale (régression 7bce86f, restée invisible deux mois). */
html {
  margin: 0 1rem;
}

@media (min-width: 768px) {
  html {
    margin: 0 2rem;
  }
}

html,
body {
  background-color: var(--color-surface);
  color: var(--color-text);
  font-family: "PT Sans", sans-serif;
  font-style: normal;
  font-weight: 400;
  height: 100%;
  min-height: 100dvh;
  min-height: 100vh;
}

h1,
h2,
h3 {
  /*font-family: "Trade Winds", system-ui;*/
  font-weight: 400;
  font-style: normal;
}

h1 {
  font-size: 2.5rem;
}

h2 {
  font-size: 2rem;
}

h3 {
  font-size: 1.5rem;
}

.input {
  color: var(--color-text-inverted);
}

#main {
  display: flex;
  align-items: flex-start;
}

#view {
  font-size: 1.5rem;
  max-width: 1200px;
  margin: 0 auto;
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: 100px;
  /* 20rem à l'origine : 320 px pour éloigner le dernier contenu du bas de la
     fenêtre, à une époque où aucun pied de page n'existait. Depuis n19 il en
     existe un, et ces 320 px sont devenus un trou noir au milieu de la page. */
  padding-bottom: 4rem;
  width: 100%;
  flex: 1;
  min-width: 0;
  z-index: 10;
  position: relative;
  view-transition-name: main-content;
}

/* ============================================================
   ÉCHELLE PUBLIQUE — .ui-button
   Le corps de texte public tourne à 24px (#view ci-dessus) — bien
   au-dessus de l'échelle fulgore, calibrée pour l'admin (--lg y
   vaut 16px). On ne touche ni aux couleurs, ni au focus-ring, ni
   au radius des variantes fulgore (hérités tels quels depuis
   button.css) : on redéfinit uniquement font-size / padding /
   gap / taille d'icône, et seulement ici.

   Isolation : application.css est chargée par DEUX layouts —
   application.html.erb:19 (public, le vrai layout) ET
   lookbook.html.erb:5 (previews Lookbook, montées en dev via
   routes.rb:2). La garde n'est donc PAS l'exclusivité du fichier :
   lookbook.html.erb n'a pas de wrapper #view, donc #view .ui-button
   n'y matche jamais. Si #view est un jour ajouté à ce layout, les
   previews hériteraient de l'échelle publique. #view existe AUSSI
   dans admin.html.erb:30, mais ce layout charge "admin" (admin.css),
   jamais "application" : l'admin est isolé par le FICHIER chargé,
   pas par le sélecteur. Ne JAMAIS déplacer ce bloc vers shared.css,
   qui est chargé par application.css ET admin.css.
   ============================================================ */
#view .ui-button {
  /* fulgore (button.css) impose font-family: var(--font-family-base),
     mappée sur une pile système par palette.css — on la neutralise
     ici pour hériter PT Sans du body, propre à l'échelle publique. */
  font-family: inherit;
  gap: var(--space-3);
  font-size: var(--font-size-xl);
  padding: var(--space-3) var(--space-6);

  .svg {
    height: var(--space-5);
    min-width: var(--space-5);
    max-width: none;
  }
}

#view .ui-button--sm {
  font-size: var(--font-size-base);
  padding: var(--space-2) var(--space-4);
}

#view .ui-button--lg {
  gap: var(--space-4);
  font-size: var(--font-size-2xl);
  padding: var(--space-4) var(--space-8);

  .svg {
    height: var(--space-6);
    min-width: var(--space-6);
  }
}

.back-link {
  margin: var(--space-12) auto;
  grid-column: span 2;
}

/* Homepage */

#view > #logo {
  width: min(80%, 800px);
  height: auto;
  margin-inline: auto;
  display: block;
}

.links-container {
  display: grid;
  gap: 1rem;
  height: fit-content;
  text-align: center;
}

/* LoginForm */

.admin-login-form {
  border-color: var(--color-border);
  border-radius: 1rem;
  border: 1px var(--color-border) solid;
  margin: 3rem auto;

  form {
    height: 100%;

    .form-inputs-container {
      align-content: center;
      height: 80%;
      margin: 0 auto;
      width: 80%;

      .input-container {
        color: var(--color-text-inverted);
        display: block;
        font-size: 2rem;
        grid-row-gap: 0.5rem;
        margin: 1rem auto;

        .input {
          width: -webkit-fill-available;
        }
      }
    }
    .form-buttons-container {
      text-align: center;
    }
  }
}

/* STATIC_PAGES */

.page-title {
  font-size: 2rem;
  margin: 0 auto;
  text-transform: uppercase;
  width: fit-content;
}

.static-page-container {
  display: grid;
  align-items: center;
  gap: 1rem;
}

.page-body {
  p {
    margin: 1rem 0.5rem;
  }
  ul {
    margin: 1rem 0.5rem 1rem 2rem;
    list-style: disc;
  }
  h3 {
    text-decoration: underline;
  }
}
.page-body.f-1 {
  font-size: 1.5rem;
}

#contact-button {
  display: flex;
  margin: var(--space-8) auto auto auto;
}

.links {
  display: grid;
  gap: var(--space-4);
  margin: var(--space-12) auto 0 auto;
  text-align: center;
  width: fit-content;

  /* Liens sociaux : ni cadre ni fer à gauche (JC, 2026-07-27). Le cadre vient
     de `.ui-button--secondary` (fulgore), neutralisé ici et ici seulement — le
     langage de boutons du reste du site public n'est pas touché. */
  .ui-button {
    border: none;
    justify-content: center;
    width: 12rem;
  }
}

#band {
  margin: 2rem auto;
}

/* GRILLES PUBLIQUES — albums, produits et vidéos */

/* Échelle de colonnes des grilles publiques : POINT DE RÉGLAGE UNIQUE.
   Ne jamais redéclarer grid-template-columns pour .albums-index,
   .products-container ni .videos-index ailleurs — surtout pas dans
   desktop.css ni medias.css, tous deux @importés en TÊTE de ce fichier
   (medias.css via shared.css) : leurs règles sont insérées AVANT ce corps,
   et à spécificité égale c'est ce bloc qui l'emporte. Une media query posée
   là-bas serait annulée en silence (régression 7bce86f : /albums est resté
   bloqué sur une seule colonne jusqu'au 2026-07-27). */
.albums-index,
.products-container,
.videos-index {
  display: grid;
  gap: var(--space-4);
  /* Un seul item par rangée en mobile (JC, 2026-07-27) : à deux colonnes, une
     pochette tombait sous 160 px de large et les titres wrappaient sur trois
     lignes. La 2ᵉ colonne n'arrive qu'à 768 px. */
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--space-12);
}

@media (min-width: 768px) {
  .albums-index,
  .products-container,
  .videos-index {
    gap: var(--space-6);
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1400px) {
  .albums-index,
  .products-container,
  .videos-index {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Carte de grille : un seul traitement, pour un album comme pour un produit.
   Aucune surface derrière le visuel — le fond noir de la page porte la
   profondeur, et une carte grise l'aplatissait (JC, 2026-07-27). Les pochettes
   livrées sur carré noir se fondent donc dans la page : c'est voulu. */
.album-item,
.product-item,
.video-item {
  border-radius: var(--radius-md);
  padding: var(--space-3);
  transition: box-shadow var(--duration-normal) ease;

  &:hover {
    box-shadow: 0 4px 20px rgba(255, 255, 255, 0.08);
  }
}

/* Le lien remplit la carte : c'est lui qui aligne les prix d'une même rangée.
   Chaque enfant porte sa piste explicitement, pour que l'absence de statut ne
   décale rien. */
.album-link,
.product-link,
.video-link {
  color: inherit;
  display: grid;
  /* minmax(0, 1fr) et non `auto` : une colonne de grille implicite se
     dimensionne au max-content, et WebKit laisse alors l'image déborder sa
     carte (mesuré : 211 px dans une carte de 155 px). */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  height: 100%;
  line-height: 1.3;
  text-decoration: none;
}

.album-link,
.video-link {
  grid-template-rows: auto 1fr;
}

/* image · statut · titre (extensible) · prix.
   La ligne « statut » garde une hauteur minimale même vide : sans elle, elle se
   replie à 0 sur les produits sans pastille et les titres se décalent de 25 px
   d'une carte à l'autre. `var(--space-6)` vaut exactement la marge négative de
   la pastille, donc la ligne réserve ce que la pastille occupe réellement.
   ⚠️ Ne PAS chercher à superposer la pastille et l'image dans la même cellule :
   éprouvé le 2026-07-27, WebKit écrase alors la piste de l'image (242 px → 90)
   dès qu'un second élément partage la cellule. */
.product-link {
  grid-template-rows: auto minmax(var(--space-6), auto) 1fr auto;
}

.album-item .main-picture,
.product-item .main-picture {
  display: block;
  grid-row: 1;
}

.album-item .main-picture img,
.product-item .main-picture img {
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-md);
  display: block;
  object-fit: cover;
  width: 100%;
}

/* La pastille partage la ligne 1 avec l'image : c'est un CALQUE sur le bas du
   visuel, pas une ligne de la carte. Lui donner sa propre ligne la ferait se
   replier à 0 sur les produits sans statut, et les titres se décalaient alors
   de 25 px d'une carte à l'autre (mesuré à 1440 : 491 contre 466).
   `max-width` + `padding-inline` la contiennent : dimensionnée par son texte
   (`width: fit-content` + `padding-inline: var(--space-8)` dans
   public_products.css), « Précommande » débordait sur la carte voisine à
   390 px. */
.product-item .product-status {
  grid-row: 2;
  max-width: 100%;
  padding-inline: var(--space-3);
}

/* Titres de carte : sous la taille du visuel qu'ils légendent. Scopé aux
   grilles — .product-title sert AUSSI la fiche produit et la ligne de panier,
   qui ne doivent pas bouger. */
.albums-index .album-title,
.products-container .product-title,
.videos-index .video-title {
  align-self: start;
  font-size: var(--font-size-xl);
  line-height: 1.3;
  margin: 0;
  padding-top: 0;
  text-align: center;
}

.albums-index .album-title {
  grid-row: 2;
}

.products-container .product-title {
  grid-row: 3;
}

.product-item .current-price {
  grid-row: 4;
}

.videos-index .video-title {
  grid-row: 2;
}

/* Couverture vidéo : emboîtement absolu, et NON l'aspect-ratio-sur-l'image
   des pochettes. Trois raisons, toutes vérifiées :
   1. les couvertures sont en 16/9 (1280×720, 480×360) — les rogner en carré
      coûterait 44 % de la largeur sur un plan live rarement centré ;
   2. une vidéo sans couverture garde sa boîte au lieu de se replier sur son
      texte alternatif ;
   3. `inset: 0` neutralise le `style="aspect-ratio:4/3"` INLINE que
      UI::Display::Picture#dev_placeholder pose en développement — sans quoi
      la vignette rendrait 4/3 en dev quoi qu'on déclare ici.
   Motif repris tel quel de .public-videos-facade (app/components/public/videos/
   facade.css), déjà éprouvé sur ces mêmes images. */
.video-cover {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  display: block;
  grid-row: 1;
  overflow: hidden;
  position: relative;
}

/* Cible à la fois <picture> et <img> : UI::Display::Picture porte la même
   classe sur les deux. */
.video-item .main-picture {
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.video-item img.main-picture {
  object-fit: cover;
}

/* Calque de lecture, posé DANS .video-cover et non dans une cellule de
   grille : la superposition en cellule écrase la piste de l'image en WebKit
   (cf. l'avertissement de .product-link plus haut). Purement décoratif —
   le lien est déjà lu par le titre de la vidéo.
   rgba volontaire : le picto flotte sur une couverture arbitraire, claire ou
   sombre selon la vidéo, jamais sur un fond connu. */
.video-play {
  align-items: center;
  background: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-full);
  color: var(--color-text);
  display: flex;
  height: var(--space-12);
  justify-content: center;
  left: 50%;
  pointer-events: none;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  transition: background var(--duration-fast) var(--easing-default);
  width: var(--space-12);
  z-index: var(--z-raised);
}

.video-link:hover .video-play,
.video-link:focus-visible .video-play {
  background: rgba(0, 0, 0, 0.7);
}

.video-play .play-icon {
  height: var(--icon-size-md);
  width: var(--icon-size-md);
}

/* FICHE PRODUIT — ORDRE MOBILE : POINT DE RÉGLAGE UNIQUE

   Sous 768 px, l'achat remonte dans le premier écran : titre → photo
   principale → prix + bouton. Les photos secondaires passent en bandeau de
   deux vignettes sous l'achat, la description ferme la page. Mesuré avant le
   changement sur /products/Eerie-LP-Alien-Green-Marble en 390×844 : le prix
   tombait à 1792 px et le bouton à 1952 px, soit 2,3 écrans de défilement
   avant de pouvoir acheter, pour 778 px de photos et 620 px de texte posés
   devant. C'est la seule page du site qui vend.

   Le bloc vit ICI, dans le corps de ce fichier, et non dans
   public_products.css ni desktop.css : les deux sont @importés en TÊTE
   d'application.css, donc insérés AVANT ce corps — à spécificité égale c'est
   le corps qui gagne, en silence (régression 7bce86f, restée invisible deux
   mois). Ne pas redéclarer cet ordre ailleurs.

   `display: contents` sur .pictures est le pivot : il fait remonter ses trois
   enfants (.main-picture, .picture.item-0, .picture.item-1) au rang d'items de
   la grille .product-show, ce qui permet de glisser l'achat ENTRE la photo
   principale et les secondaires sans toucher au DOM — donc sans casser les
   placements explicites de desktop.css, qui référencent .pictures comme un
   item unique à ≥ 1025 (grid-template-areas) et à ≥ 1400 (colonne sticky). */
@media (max-width: 767px) {
  .product-show {
    /* Deux colonnes : elles ne servent QUE le bandeau de vignettes ci-dessous.
       minmax(0, 1fr) et non `auto` — une colonne implicite se dimensionne au
       max-content et WebKit laisse alors l'image déborder (piège éprouvé sur
       les cartes de grille le 2026-07-27). */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-4);

    /* Tout occupe la largeur entière par défaut. Ne cible que les enfants
       réels : sous display: contents, .main-picture et .picture restent fils
       de .pictures au sens du sélecteur, d'où leur piste explicite plus bas.
       Aucun row-gap : l'espacement vertical vient des marges de chaque bloc
       (3rem sur la description, 2rem sur le statut vide), et un gap s'y
       ajouterait au lieu de les remplacer — 112 px qui sortiraient le bouton
       du premier écran. */
    > * { grid-column: 1 / -1; }

    .pictures { display: contents; }

    h1.product-title      { order: 1; }
    .main-picture         { order: 2; grid-column: 1 / -1; }
    .product-status,
    .empty-product-status { order: 3; }
    /* Avant l'achat : la date de précommande conditionne le clic, on ne
       l'apprend pas après avoir cliqué. */
    .preorder-message     { order: 4; }
    .price-and-cart       { order: 5; }
    /* Le bandeau réduit : une vignette par colonne, donc deux par rangée.
       `margin-top` est indispensable et non décoratif : display: contents
       détruit le `gap: 1rem` que .pictures portait, et sans lui le bandeau
       vient coller le bas du bouton d'achat — mesuré à 0 px, vu sur capture.
       Il ne coûte rien à la ligne de flottaison, la rangée étant sous elle. */
    .picture              { order: 6; grid-column: span 1; margin-top: var(--space-4); }
    #product-description  { order: 7; }
    .making-of-link       { order: 8; }
  }
}

/* NAVIGATION */

#navbar {
  align-items: center;
  background-color: var(--color-surface);
  color: var(--color-text);
  display: grid;
  /* Trois colonnes depuis que le logo et le bouton menu sont deux éléments
     distincts : le logo est redevenu un lien vers l'accueil. La colonne
     souple est celle DU MILIEU — le panier, avec son margin-left: auto — ce
     qui rejette le bouton menu à l'extrême droite. En `auto auto 1fr`, les
     deux premières colonnes se serraient à gauche et le burger se retrouvait
     collé au logo (constaté en production le 2026-08-02). */
  grid-template-columns: auto 1fr auto;
  /* La barre est `position: fixed; width: 100%` : elle échappe au
     `html { margin: 0 2rem }` et court d'un bord à l'autre. Sans gouttière
     propre, le logo touchait le bord gauche à 0 px depuis toujours, et le
     bouton menu a rejoint le bord droit à 0 px en passant dernier — c'est le
     panier, avec son padding, qui tenait cette place avant. Deux offenders
     `edgeHugging` et deux `viewportGutter` sur chaque route, mesurés en
     production. 1rem rend 16 px à la boîte de chaque contrôle, et aligne
     leur contenu visible sur les 32 px de gouttière de la page. */
  padding-inline: 1rem;
  height: 90px;
  left: 0;
  position: fixed;
  text-align: center;
  top: 0;
  width: 100%;
  z-index: 1000;
  view-transition-name: navbar;

  /* Ex-.logo-toggle, quand le logo était le bouton du menu. Il est maintenant
     un lien vers l'accueil ; le nom suit la fonction. */
  .home-link {
    cursor: pointer;
    padding: 0.5rem 1rem;
    display: flex;
    align-items: center;

    #logo {
      height: 70%;
      width: 5rem;
    }
  }

}

#cart-wrapper {
  margin-left: auto;
  padding-right: 1.5rem;
  position: relative;
  display: flex;
  align-items: center;

  #cart-button {
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
  }

  svg {
    height: 3rem;
    width: 3rem;
  }

  #cart-counter {
    background-color: var(--color-text);
    color: var(--color-text-inverted);
    border-radius: 9999px;
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1;
    min-width: 1.5rem;
    height: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.4rem;
    position: absolute;
    top: -0.5rem;
    right: 1rem;
    pointer-events: none;
  }
}

/* ORDERS */

#checkout {
  .public-orders-news-consent-form,
  .preorder-message {
    margin: 3rem auto;
    text-align: center;
  }
}

#comment-thanks,
#comment {
  text-align: center;
  margin: 3rem auto;

  .leave-comment {
    margin: 3rem auto 1rem auto;
  }
}
#comment-thanks {
  font-size: 3rem;
}

#success {
  #message {
    text-align: center;

    .icon {
      font-size: 3rem;
    }
  }

  .email-sent {
    text-align: center;
  }
}

/* UI */

.facebook,
#bandcamp,
#instagram,
#spotify {
  height: 2rem;
}

/* USERS */


/* ERRORS */

.public-errors-address-error,
.public-errors-country-error,
.public-errors-cart-error,
.public-errors-error500,
.public-errors-error404 {
  text-align: center;
}

.album-show {
  .accordion-section {
    font-size: 2rem;
    margin: 1rem;
    padding: 1rem 0;

    .collapsible-header {
      border-bottom: 1px solid var(--color-border-strong);
      margin-bottom: 2rem;
    }
  }
  .public-albums-making-of {
    .container {
      display: grid;
      gap: 2rem;
    }
    .public-image {
      display: grid;
      gap: 1rem;
    }
  }
  .share-buttons {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    width: fit-content;
    margin-left: auto;
  }
  .public-albums-products {
    .container {
      display: grid;
      gap: 2rem;
    }
    .product-show {
      border-bottom: 1px solid var(--color-border-strong);

      .product-title {
        display: none;
      }
    }
  }
}
