/* ============================================================
   Stark Metals Trading: design system
   Inter (UI) + Fraunces (display) · graphite accent · light base
   ============================================================ */

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

:root{
 /* neutrals */
 /* --grey2 etait #78797d, soit 4,35:1 sur blanc et 4,02:1 sur --bg2 : sous la
    barre AA de 4,5:1. Il colore exclusivement du PETIT texte - les en-tetes de
    formulaire et les titres du bloc contact a 11,5px, les indices de champ, le
    sous-titre de la marque a 9px - donc c est bien le seuil 4,5 qui s applique,
    pas celui du grand texte.
    #6e6f73 donne 5,02:1 sur blanc, 4,64:1 sur --bg2 et 4,57:1 sur le #F5F4F2 de
    approach.html, en gardant exactement la meme teinte (meme ecart entre les
    canaux) : dix points sur 255, imperceptible.
    Les trois fonds ci-dessus sont les SEULS ou le jeton est pose. --bg3 existe
    dans les jetons mais n est utilise nulle part, donc il ne contraint rien.
    VERIFIE AVANT DE CHANGER : les douze usages du jeton sont tous du texte sur
    fond clair (--bg, --bg2, --bg3, et le fond clair de l en-tete de
    approach.html). Les huit contextes sombres - body.has-scene sur l accueil -
    redefinissent tous leur couleur explicitement et n utilisent pas ce jeton.
    L assombrir ne peut donc qu ameliorer, jamais nuire. */
 --ink:#15161a; --ink2:#3a3b3f; --grey:#6a6b6e; --grey2:#6e6f73;
 --line:#e8e8e7; --line2:#dbdbda;
 --bg:#ffffff; --bg2:#f6f6f5; --bg3:#eeeeed;
 /* accent: graphite */
 --accent:#33343A; --accent2:#000000; --accentlt:#B9BABD; --accent-wash:#F1F1F0;
 /* type */
 --sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
 --serif:'Fraunces','Georgia',serif;
 --nav-h:78px;
}

/* Cible du lien d evitement. tabindex="-1" est pose sur <main> par les
   generateurs ; sans la regle ci-dessous le navigateur cerne alors TOUTE la
   page d un anneau de 2px au premier saut. Copie exacte d approach.html:68,
   la seule page ou le couple etait deja en place. */
main:focus{outline:none}

html{scroll-behavior:smooth}
section[id],header[id]{scroll-margin-top:96px}
body{font-family:var(--sans);color:var(--ink);background:var(--bg);line-height:1.65;
 -webkit-font-smoothing:antialiased;font-size:16.5px;font-weight:400;overflow-x:hidden}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.wrap-narrow{max-width:880px;margin:0 auto;padding:0 32px}
a{text-decoration:none;color:inherit}
img{display:block;max-width:100%}
a:focus-visible,button:focus-visible,summary:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.skip{position:absolute;left:-9999px;top:0;z-index:300;background:var(--ink);color:#fff;padding:12px 20px;font-size:14px}
.skip:focus{left:0}

h1,h2,h3,h4{font-weight:600;letter-spacing:-.01em}
.eyebrow{display:inline-block;font-size:11.5px;letter-spacing:2.4px;text-transform:uppercase;
 color:var(--accent);font-weight:600;margin-bottom:22px}

/* ---------- reading progress ---------- */
/* scaleX et non width : une transition de largeur repasse par la mise en page a
   chaque image, et site.js l ecrit a CHAQUE image de defilement - donc un
   reflow synchrone du document entier par image, sur toute la duree du
   defilement, en concurrence directe avec la boucle de rendu de la scene.
   Une transformation part sur le fil de composition et ne touche pas la mise
   en page. scaleX(0) pose ICI et non par JavaScript : site.js est differe, la
   barre serait sinon pleine largeur jusqu a son execution. */
.progress{position:fixed;top:0;left:0;height:2px;width:100%;transform:scaleX(0);
 transform-origin:0 50%;z-index:200;
 background:linear-gradient(90deg,var(--accent),var(--accentlt));transition:transform .1s linear}

/* ---------- nav ---------- */
/* -webkit-sticky AVANT sticky : sur iOS 12 la valeur non prefixee est
   invalide, la declaration est jetee et la barre defile hors de l ecran. Les
   moteurs modernes rejettent -webkit-sticky comme valeur inconnue puis
   appliquent la ligne suivante : rien ne change nulle part ailleurs. */
.nav{position:-webkit-sticky;position:sticky;top:0;z-index:100;background:rgba(255,255,255,.94);
 -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
 border-bottom:1px solid var(--line);transition:box-shadow .3s,background .3s}
.nav.compact{box-shadow:0 6px 24px rgba(20,24,28,.07);background:rgba(255,255,255,.985)}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:var(--nav-h);
 max-width:1180px;margin:0 auto;padding:0 32px;transition:height .3s}
.nav.compact .nav-in{height:62px}
.brand{display:flex;align-items:center;gap:13px}
.brand img{height:70px;width:auto;transition:height .3s}
.nav.compact .brand img{height:52px}
.brand .nm{font-weight:700;font-size:18px;letter-spacing:1.5px;line-height:1}
.brand .sb{font-size:9px;letter-spacing:1.8px;color:var(--grey2);font-weight:500;margin-top:4px}
.nav-links{display:flex;align-items:center;gap:26px}
.nav-links>a,.drop>button{font-size:14.5px;font-weight:450;color:var(--ink2);transition:color .2s;
 letter-spacing:.3px;background:none;border:none;font-family:inherit;cursor:pointer;
 display:inline-flex;align-items:center;gap:6px;padding:0}
.nav-links>a:hover,.drop>button:hover,.nav-links>a[aria-current="page"]{color:var(--ink)}
.nav-links>a[aria-current="page"]{position:relative}
.nav-links>a[aria-current="page"]::after{content:'';position:absolute;left:0;right:0;bottom:-6px;
 height:2px;background:var(--accent)}
.drop{position:relative}
.drop>button svg{width:9px;height:9px;stroke:currentColor;fill:none;stroke-width:2.4;transition:transform .25s}
.drop.open>button svg{transform:rotate(180deg)}
.drop-menu{position:absolute;top:calc(100% + 18px);left:-18px;min-width:252px;background:#fff;
 border:1px solid var(--line);border-radius:3px;box-shadow:0 16px 44px rgba(20,24,28,.11);
 padding:8px 0;opacity:0;visibility:hidden;transform:translateY(-6px);transition:.22s;z-index:110}
.drop.open .drop-menu{opacity:1;visibility:visible;transform:translateY(0)}
.drop-menu a{display:block;padding:9px 22px;font-size:14px;color:var(--ink2);transition:.18s}
.drop-menu a:hover{background:var(--accent-wash);color:var(--accent)}
.drop-menu .sep{height:1px;background:var(--line);margin:8px 0}
.drop-menu a.all{font-weight:600;color:var(--ink)}
.lang{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;letter-spacing:.6px;
 font-weight:600;color:var(--grey2);border-left:1px solid var(--line2);padding-left:20px}
.lang a{transition:color .2s}
.lang a:hover{color:var(--ink)}
.lang a.on{color:var(--accent)}
/* Zone tactile de 44x44 (recommandation Apple ; le minimum WCAG 2.2 SC 2.5.8
   est 24x24, le bouton n en faisait que 39x30,5). min-width/min-height plutot
   que du padding : box-sizing est border-box sur tout le site, donc du padding
   se logerait A L INTERIEUR de la boite sans l agrandir d un pixel. Le trait
   lui-meme ne bouge pas : centre dans 44 px il rentre de 10,5 px, contre 8 px
   avant, et la marge negative de 2,5 px le remet exactement ou il etait, aligne
   sur le bord droit de .wrap et du logo.
   L espacement des trois barres passe de `gap` a une marge : `gap` en FLEX
   n existe qu a partir de Safari 14.1, donc sur un iPhone reste en iOS 12, 13
   ou 14.0 les trois traits se collaient en un seul pave plein et l icone ne
   ressemblait plus a un menu.
   La marge REMPLACE le gap, elle ne s y ajoute pas : il n existe aucune requete
   @supports capable de distinguer le gap flex du gap grid (Safari 12 accepte la
   propriete pour la grille), donc garder les deux donnerait 10 px sur les
   navigateurs modernes et 5 px sur les anciens. Une seule source d espacement,
   identique partout. */
.burger{display:none;background:none;border:none;cursor:pointer;flex-direction:column;
 align-items:center;justify-content:center;gap:0;padding:8px;
 min-width:44px;min-height:44px;margin-right:-2.5px}
.burger span{width:23px;height:1.5px;background:var(--ink);display:block;transition:.3s}
.burger span + span{margin-top:5px}

/* ---------- buttons ---------- */
.cta{display:inline-flex;align-items:center;gap:8px;background:transparent;color:var(--ink);
 padding:11px 22px;border-radius:2px;font-size:13.5px;font-weight:600;letter-spacing:.4px;
 border:1px solid var(--ink);transition:all .25s;font-family:inherit;cursor:pointer}
/* Sur ecran tactile :hover reste colle apres le tap : le bouton garde son
   etat survole jusqu au tap suivant ailleurs. On le reserve donc au pointeur,
   comme le fait deja la fin de ce fichier. :active et le style de repos ne
   changent pas, et rien ne change sur ordinateur. */
@media(hover:hover) and (pointer:fine){
 .cta:hover{background:var(--ink);color:#fff}
}
.cta svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;flex:none}
.cta-lg{padding:15px 30px;font-size:14.5px}
.cta-primary{border-color:var(--accent);color:var(--accent)}
@media(hover:hover) and (pointer:fine){
 .cta-primary:hover{background:var(--accent);color:#fff!important;border-color:var(--accent)}
}
.cta-light{border-color:rgba(255,255,255,.5);color:#fff}
@media(hover:hover) and (pointer:fine){
 .cta-light:hover{background:#fff;color:var(--ink);border-color:#fff}
}
.cta-solid{background:var(--accent);color:#fff;border-color:var(--accent)}
/* Meme raison que .cta et .cta-primary ci-dessus : sur ecran tactile :hover
   reste colle apres le tap. C etait le dernier :hover non garde du fichier ;
   il ne sert plus qu au bouton Send enquiry de contact.html. */
@media(hover:hover) and (pointer:fine){
 .cta-solid:hover{background:var(--accent2);border-color:var(--accent2);color:#fff}
}
.textlink{display:inline-flex;align-items:center;gap:7px;color:var(--accent);font-weight:600;
 font-size:14px;letter-spacing:.2px;border-bottom:1px solid transparent;transition:.2s}
.textlink svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2;transition:transform .25s}
.textlink:hover{border-bottom-color:var(--accent)}
.textlink:hover svg{transform:translateX(3px)}

/* ---------- hero ---------- */
.hero{position:relative;min-height:678px;display:flex;align-items:center;overflow:hidden;background:var(--ink)}
.hero-bg{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:0}
.hero-bg img,.hero-bg video{width:100%;height:100%;object-fit:cover;opacity:.5;
 filter:saturate(.85) contrast(1.06);position:absolute;top:0;right:0;bottom:0;left:0;inset:0}
.hero-bg video{z-index:1}
/* La video est INVISIBLE tant que `canplay` n a pas ete emis. Son affiche est
   la photographie elle-meme (site.js la recopie), avec le meme cadrage et le
   meme filtre, empilee juste au-dessus : les deux se composaient donc pendant
   toute la mise en memoire tampon, et le heros sortait a 1-(1-.82)^2 = 0,97
   au lieu des 0,82 sur lesquels les voiles de contraste ont ete mesures - un
   saut de luminosite visible au demarrage. En mode economie d energie sur
   iPhone et dans les navigateurs integres aux applications, `canplay` n arrive
   jamais : le doublement etait alors permanent. */
.hero-bg:not(.has-video) video{opacity:0}
.hero-bg.has-video img{opacity:0}
.hero-bg::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:2;
 background:linear-gradient(108deg,rgba(19,24,31,.94) 0%,rgba(19,24,31,.74) 48%,rgba(19,24,31,.4) 100%)}
/* fine grain: printed feel */
.grain::before{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:3;pointer-events:none;opacity:.05;
 background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")}
.hero-in{position:relative;z-index:4;padding:76px 0 68px;color:#fff;max-width:780px}
.hero .eyebrow{color:var(--accentlt)}
.hero h1{font-family:var(--serif);font-size:68px;line-height:1.02;font-weight:500;
 letter-spacing:-.032em;margin-bottom:26px}
.hero h1 em{font-style:italic;color:var(--accentlt);font-weight:400}
.hero p.lead{font-size:19px;color:#c7c7c4;max-width:612px;margin-bottom:36px;line-height:1.62}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap}

/* page hero (inner pages) */
.phero{position:relative;background:var(--ink);overflow:hidden}
.phero-bg{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:0}
.phero-bg img{width:100%;height:100%;object-fit:cover;opacity:.42;filter:saturate(.85) contrast(1.05)}
.phero-bg::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;
 background:linear-gradient(102deg,rgba(19,24,31,.93) 0%,rgba(19,24,31,.7) 55%,rgba(19,24,31,.42) 100%)}
.phero-in{position:relative;z-index:4;padding:104px 0 92px;color:#fff;max-width:800px}
.phero .eyebrow{color:var(--accentlt)}
.phero h1{font-family:var(--serif);font-size:52px;line-height:1.06;font-weight:500;
 letter-spacing:-.028em;margin-bottom:20px}
.phero p{font-size:18px;color:#c7c7c4;max-width:620px;line-height:1.62}
.crumb{font-size:12.5px;color:#9b9c99;margin-bottom:20px;letter-spacing:.3px}
.crumb a{color:var(--accentlt)}
.crumb a:hover{color:#fff}
.crumb span{margin:0 7px;opacity:.5}

/* ---------- KPI strip ---------- */
.trust{display:grid;grid-template-columns:repeat(4,1fr);gap:0;
 border-top:1px solid rgba(255,255,255,.14);margin-top:52px;padding-top:30px;position:relative;z-index:4}
.trust .t{padding:2px 26px;border-left:1px solid rgba(255,255,255,.13)}
.trust .t:first-child{padding-left:0;border-left:none}
.trust .t .v{font-family:var(--serif);font-size:40px;font-weight:500;color:#fff;
 letter-spacing:-.02em;line-height:1;margin-bottom:9px}
.trust .t .v .u{color:var(--accentlt);font-size:.62em;margin-left:2px}
.trust .t .l{font-size:12.5px;color:#a2a3a1;letter-spacing:.2px;line-height:1.45}

/* ---------- sections ---------- */
section{padding:120px 0}
section.tight{padding:88px 0}
.bg2{background:var(--bg2)}
.bg-wash{background:var(--accent-wash)}
.sec-head{max-width:740px;margin-bottom:66px;position:relative}
.sec-head h2{font-family:var(--serif);font-size:47px;font-weight:500;letter-spacing:-.026em;
 line-height:1.08;margin-bottom:20px;position:relative;padding-bottom:22px}
.sec-head h2::after{content:'';position:absolute;left:0;bottom:0;width:56px;height:2px;background:var(--accent)}
.sec-head.center{margin-left:auto;margin-right:auto;text-align:center}
.sec-head.center h2::after{left:50%;transform:translateX(-50%)}
.sec-head p{font-size:17.5px;color:var(--grey);line-height:1.6;max-width:624px}
.sec-head.center p{margin-left:auto;margin-right:auto}

/* ---------- scroll reveal ---------- */
.rv{opacity:0;transform:translateY(22px);transition:opacity .7s cubic-bezier(.22,.61,.36,1),transform .7s cubic-bezier(.22,.61,.36,1)}
.rv.in{opacity:1;transform:none}
/* Sans JavaScript, rien ne pose jamais .in : le formulaire de contact (4 blocs
   .rv) et le texte de legal.html (1 bloc) restaient a opacite 0, donc invisibles
   et inatteignables, sur une page par ailleurs entierement statique. La classe
   `js` est posee par un script en ligne dans le <head>, donc pendant l analyse
   du document : quand JavaScript fonctionne, ce selecteur ne s applique deja
   plus a la premiere peinture et il n y a aucun clignotement.
   Specificite (0,2,1), donc au-dessus de .rv (0,1,0) et de .rv.in (0,2,0),
   sans toucher a une seule des regles existantes. */
html:not(.js) .rv{opacity:1;transform:none;transition:none}
/* Sans JavaScript, le garde de site.js ne tourne pas et le navigateur POSTe
   pour de vrai vers l endpoint Formspree encore a l etat de gabarit : le
   visiteur quitte le site, atterrit sur une page d erreur, et sa demande est
   perdue sans que rien ne le lui dise. Le README promet exactement l inverse
   ("it will never silently swallow an enquiry").
   On ne masque QUE la commande d envoi, jamais les champs : le formulaire
   reste lisible et le <noscript> juste au-dessus donne l adresse et le
   telephone. Le selecteur teste l attribut action lui-meme : le jour ou le
   vrai identifiant Formspree est pose, la regle cesse de matcher toute seule
   et le bouton revient, sans qu il y ait rien a se rappeler de retirer. */
html:not(.js) form.enq[action*="REPLACE_WITH_YOUR_FORM_ID"] button[type="submit"]{display:none}
.rv-d1{transition-delay:.09s}.rv-d2{transition-delay:.18s}.rv-d3{transition-delay:.27s}
.rv-d4{transition-delay:.36s}.rv-d5{transition-delay:.45s}
@media(prefers-reduced-motion:reduce){
 .rv{opacity:1;transform:none;transition:none}
 html{scroll-behavior:auto}
}

/* ---------- marquee (European coverage) ---------- */
.marq{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
 background:var(--bg2);padding:26px 0;overflow:hidden;position:relative}
.marq::before,.marq::after{content:'';position:absolute;top:0;bottom:0;width:120px;z-index:2;pointer-events:none}
.marq::before{left:0;background:linear-gradient(90deg,var(--bg2),rgba(246,246,245,0))}
.marq::after{right:0;background:linear-gradient(270deg,var(--bg2),rgba(246,246,245,0))}
.marq-track{display:flex;gap:0;width:max-content;animation:marq 110s linear infinite}
.marq:hover .marq-track{animation-play-state:paused}
.marq-item{display:inline-flex;align-items:center;gap:14px;padding:0 26px;font-size:14px;
 font-weight:600;letter-spacing:.5px;color:var(--ink2);white-space:nowrap}
.marq-item::after{content:'';width:4px;height:4px;border-radius:50%;background:var(--accent);opacity:.65}
@keyframes marq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.marq-track{animation:none;flex-wrap:wrap;width:auto;justify-content:center}}

/* ---------- product / metal cards ---------- */
.prod-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.prod{border-radius:3px;overflow:hidden;background:#fff;border:1px solid var(--line);
 transition:border-color .3s,box-shadow .35s,transform .35s;display:flex;flex-direction:column}
.prod:hover{border-color:var(--accentlt);transform:translateY(-3px);box-shadow:0 16px 38px rgba(20,24,28,.075)}
.prod .ph{height:188px;position:relative;overflow:hidden;background:var(--ink)}
.prod .ph img{width:100%;height:100%;object-fit:cover;transition:transform .5s ease;
 filter:saturate(.78) contrast(1.06)}
.prod:hover .ph img{transform:scale(1.045)}
.prod .ph.photo{display:flex;align-items:flex-end;padding:20px}
.prod .ph.photo img{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:0}
.prod .ph.photo::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:1;
 background:linear-gradient(to top,rgba(16,17,20,.72),rgba(16,17,20,0) 62%)}
.prod .ph-name{position:relative;z-index:2;color:#fff;font-weight:600;font-size:22px;
 letter-spacing:.3px;font-family:var(--serif);text-shadow:0 1px 12px rgba(0,0,0,.5)}
.prod .bd{padding:24px 24px 26px;display:flex;flex:1;flex-direction:column}
.prod .bd h3{font-size:20px;font-weight:600;margin-bottom:6px}
.prod .bd .role{font-size:12.5px;color:var(--accent);font-weight:600;margin-bottom:13px;
 letter-spacing:.3px;text-transform:uppercase}
.prod .bd p{font-size:14px;color:var(--grey);margin-bottom:15px;line-height:1.6}
.prod .bd .meta{font-size:12px;color:var(--ink2);border-top:1px solid var(--line);padding-top:13px;
 line-height:1.5;margin-top:auto}
.prod .bd .meta b{color:var(--grey);font-weight:600}
.prod .bd .more{margin-top:14px;font-size:13px;font-weight:600;color:var(--accent);
 display:inline-flex;align-items:center;gap:6px;opacity:.55;transform:translateY(2px);transition:.3s}
.prod:hover .bd .more{opacity:1;transform:none}
.prod .bd .more svg{width:11px;height:11px;stroke:currentColor;fill:none;stroke-width:2.2}

/* element-symbol tile (metals without photography) */
.ph.elem{display:flex;align-items:center;justify-content:center;position:relative;
 background:linear-gradient(145deg,#1b1d22 0%,#26282e 100%)}
.ph.elem::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;opacity:.06;
 background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")}
.ph.elem .sym{position:relative;z-index:1;text-align:center;color:#fff;display:block}
.ph.elem .sym .s{display:block;font-family:var(--serif);font-size:58px;font-weight:500;line-height:1;letter-spacing:-.02em}
.ph.elem .sym .z{display:block;font-size:11px;letter-spacing:2.4px;text-transform:uppercase;color:var(--accentlt);
 margin-top:12px;font-weight:600}
.ph.elem .aw{position:absolute;top:14px;left:16px;z-index:1;font-size:11px;color:#8b8c8a;letter-spacing:.6px}

.also{margin-top:30px;border-top:1px solid var(--line);padding-top:24px;display:flex;flex-wrap:wrap;
 gap:12px 30px;align-items:baseline}
.also .lab{font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--grey2);font-weight:600}
.also .it{font-size:15.5px;font-weight:600;color:var(--ink)}
.also .it span{color:var(--grey);font-weight:400;font-size:13px}

/* ---------- grades ---------- */
.grade-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.grade{border:1px solid var(--line);border-radius:4px;padding:20px 22px;background:#fff;
 transition:border-color .25s,box-shadow .25s}
.grade:hover{border-color:var(--accentlt);box-shadow:0 12px 34px rgba(19,24,31,.06)}
.grade .gh{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}
.grade .gn{font-size:16.5px;font-weight:600}
.grade .isri{font-size:10px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;
 color:var(--accent);border:1px solid var(--accentlt);background:var(--accent-wash);
 border-radius:2px;padding:3px 8px;white-space:nowrap}
.grade p{font-size:13.5px;color:var(--grey);line-height:1.55}

/* ---------- process timeline ---------- */
.proc-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:30px;position:relative}
.proc-grid::before{content:'';position:absolute;top:23px;left:23px;right:23px;height:1px;background:var(--line2)}
.proc{position:relative;z-index:1}
.proc .ico{width:46px;height:46px;border-radius:3px;background:#fff;display:flex;align-items:center;
 justify-content:center;margin-bottom:20px;border:1px solid var(--line);transition:.3s}
.proc:hover .ico{border-color:var(--accent);background:var(--accent-wash)}
.proc .ico svg{width:22px;height:22px;stroke:var(--accent);fill:none;stroke-width:1.6}
.proc .n{font-family:var(--serif);font-size:14px;font-weight:500;color:var(--accent);
 margin-bottom:10px;letter-spacing:.5px}
.proc h3{font-size:18px;font-weight:600;margin-bottom:9px;letter-spacing:-.005em}
.proc p{font-size:14px;color:var(--grey);line-height:1.6}

/* ---------- capability / compliance cards ---------- */
.comp-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:24px}
.comp-grid.three{grid-template-columns:repeat(3,1fr)}
.comp{background:#fff;border:1px solid var(--line);border-radius:4px;padding:26px 24px 28px;
 transition:border-color .3s,box-shadow .35s,transform .35s}
.comp:hover{border-color:var(--accentlt);transform:translateY(-3px);box-shadow:0 16px 38px rgba(20,24,28,.07)}
.comp .ico{width:44px;height:44px;border-radius:3px;background:var(--bg2);border:1px solid var(--line);
 display:flex;align-items:center;justify-content:center;margin-bottom:18px;transition:.3s}
.comp:hover .ico{background:var(--accent-wash);border-color:var(--accentlt)}
.comp .ico svg{width:21px;height:21px;stroke:var(--accent);fill:none;stroke-width:1.6}
.comp h4{font-size:16px;font-weight:600;margin-bottom:8px}
.comp p{font-size:13.5px;color:var(--grey);line-height:1.6}

/* ---------- approach split ---------- */
.why{display:grid;grid-template-columns:1.05fr 1fr;gap:68px;align-items:center}
.why.rev{grid-template-columns:1fr 1.05fr}
.why-img{border-radius:4px;overflow:hidden;height:480px}
.why-img img{width:100%;height:100%;object-fit:cover;filter:saturate(.8) contrast(1.06)}
.why-list{list-style:none;margin-top:6px}
.why-list li{padding:22px 0;border-bottom:1px solid var(--line);display:flex;gap:18px;align-items:flex-start}
.why-list li:last-child{border-bottom:none}
.why-list .ck{flex:none;width:30px;height:30px;border-radius:2px;background:var(--accent-wash);
 border:1px solid var(--accentlt);color:var(--accent);display:flex;align-items:center;
 justify-content:center;margin-top:1px}
.why-list .ck svg{width:15px;height:15px;stroke:var(--accent);fill:none;stroke-width:2}
.why-list h4{font-size:16.5px;font-weight:600;margin-bottom:4px}
.why-list p{font-size:14px;color:var(--grey);line-height:1.55}

.approach-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;height:480px}
.atile{position:relative;border-radius:4px;overflow:hidden;margin:0;background:var(--ink)}
.atile img{width:100%;height:100%;object-fit:cover;filter:saturate(.9) contrast(1.03) brightness(.9);
 transition:transform .5s ease}
.atile:hover img{transform:scale(1.045)}
.atile figcaption{position:absolute;left:0;right:0;bottom:0;padding:12px 13px;color:#fff;font-size:12px;
 font-weight:600;letter-spacing:.2px;background:linear-gradient(to top,rgba(16,17,20,.85),rgba(16,17,20,0))}

/* ---------- dark band (video or photo) ---------- */
.band{position:relative;background:var(--ink);overflow:hidden}
.band-bg{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:0}
.band-bg img,.band-bg video{width:100%;height:100%;object-fit:cover;opacity:.28;
 filter:saturate(.85) contrast(1.05);position:absolute;top:0;right:0;bottom:0;left:0;inset:0}
.band-bg::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:2;
 background:linear-gradient(90deg,rgba(20,24,28,.96) 0%,rgba(20,24,28,.9) 52%,rgba(20,24,28,.72) 100%)}
.band-in{position:relative;z-index:4;padding:96px 0;max-width:820px;color:#fff}
.band .eyebrow{color:var(--accentlt)}
.band-q{font-family:var(--serif);font-size:31px;line-height:1.32;font-weight:500;
 margin-bottom:34px;letter-spacing:-.014em}
.band-list{display:grid;grid-template-columns:repeat(3,1fr);gap:28px 34px;
 border-top:1px solid rgba(255,255,255,.14);padding-top:30px}
.band-list .bi h4{font-size:14.5px;font-weight:600;color:#fff;margin-bottom:6px;
 display:flex;align-items:center;gap:9px}
.band-list .bi h4::before{content:'';width:5px;height:5px;border-radius:50%;background:var(--accentlt);flex:none}
.band-list .bi p{font-size:13.5px;color:#a2a3a1;line-height:1.6}

/* ---------- split panels (Traxys-style, refined) ---------- */
.panels{display:grid;grid-template-columns:1fr 1fr;gap:0}
.panel{position:relative;min-height:430px;display:flex;align-items:flex-end;overflow:hidden;background:var(--ink)}
.panel img{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;width:100%;height:100%;object-fit:cover;opacity:.68;
 filter:saturate(.82) contrast(1.06);transition:transform .8s cubic-bezier(.22,.61,.36,1),opacity .5s}
.panel:hover img{transform:scale(1.05);opacity:.8}
.panel::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:1;
 background:linear-gradient(to top,rgba(16,18,22,.9) 6%,rgba(16,18,22,.42) 58%,rgba(16,18,22,.12) 100%)}
.panel-in{position:relative;z-index:2;padding:52px 48px 48px;color:#fff;max-width:520px}
.panel-in h3{font-family:var(--serif);font-size:33px;font-weight:500;letter-spacing:-.022em;
 line-height:1.1;margin-bottom:14px}
.panel-in p{font-size:15.5px;color:#c7c7c4;margin-bottom:24px;line-height:1.6}

/* ---------- pricing basis table ---------- */
.ptable{border:1px solid var(--line);border-radius:4px;overflow:hidden;background:#fff}
.ptable table{width:100%;border-collapse:collapse}
.ptable th{text-align:left;font-size:11px;letter-spacing:1.5px;text-transform:uppercase;
 color:var(--grey2);font-weight:600;padding:16px 22px;background:var(--bg2);
 border-bottom:1px solid var(--line);white-space:nowrap}
.ptable td{padding:16px 22px;font-size:14.5px;color:var(--ink2);border-bottom:1px solid var(--line);
 vertical-align:top;line-height:1.5}
.ptable tr:last-child td{border-bottom:none}
.ptable td.m{font-weight:600;color:var(--ink);white-space:nowrap}
.ptable td.c{font-family:var(--serif);color:var(--accent);font-weight:500;white-space:nowrap}
.ptable-wrap{overflow-x:auto}
.note{border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:3px;
 background:var(--bg2);padding:22px 26px;font-size:14px;color:var(--ink2);line-height:1.65;margin-top:26px}
.note b{color:var(--ink);font-weight:600}

/* ---------- transaction structures ---------- */
.deal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.deal{border:1px solid var(--line);border-radius:4px;background:#fff;padding:0;overflow:hidden;
 transition:border-color .3s,box-shadow .35s}
.deal:hover{border-color:var(--accentlt);box-shadow:0 16px 38px rgba(20,24,28,.07)}
.deal .dh{padding:20px 24px;border-bottom:1px solid var(--line);background:var(--bg2)}
.deal .dh .k{font-size:11px;letter-spacing:1.6px;text-transform:uppercase;color:var(--accent);font-weight:600}
.deal .dh h4{font-size:18px;font-weight:600;margin-top:6px}
.deal .db{padding:20px 24px 24px}
.deal .db p{font-size:14px;color:var(--grey);line-height:1.6;margin-bottom:16px}
.deal .db dl{display:grid;grid-template-columns:auto 1fr;gap:9px 16px;font-size:13px;
 border-top:1px solid var(--line);padding-top:15px}
.deal .db dt{color:var(--grey2);font-weight:600;letter-spacing:.3px;white-space:nowrap}
.deal .db dd{color:var(--ink2)}

/* ---------- FAQ ---------- */
.faq{max-width:860px;border-top:1px solid var(--line)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{list-style:none;cursor:pointer;padding:24px 44px 24px 0;font-size:17px;font-weight:600;
 position:relative;transition:color .2s}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent)}
.faq summary::after{content:'';position:absolute;right:8px;top:31px;width:11px;height:11px;
 border-right:1.8px solid var(--accent);border-bottom:1.8px solid var(--accent);
 transform:rotate(45deg);transition:transform .3s}
.faq details[open] summary::after{transform:rotate(-135deg);top:34px}
.faq .ans{padding:0 44px 26px 0;font-size:15px;color:var(--grey);line-height:1.7}
.faq .ans p+p{margin-top:12px}

/* ---------- team / desk ---------- */
.desk-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.desk{border:1px solid var(--line);border-radius:4px;background:#fff;padding:28px 26px 30px}
.desk .lab{font-size:11px;letter-spacing:1.6px;text-transform:uppercase;color:var(--accent);
 font-weight:600;margin-bottom:12px}
.desk h4{font-size:19px;font-weight:600;margin-bottom:8px}
.desk p{font-size:14px;color:var(--grey);line-height:1.62}
.desk ul{list-style:none;margin-top:14px;border-top:1px solid var(--line);padding-top:14px}
.desk ul li{font-size:13.5px;color:var(--ink2);padding:5px 0;display:flex;gap:10px;align-items:flex-start}
.desk ul li::before{content:'';width:4px;height:4px;border-radius:50%;background:var(--accent);
 margin-top:8px;flex:none}

/* ---------- metrics / ESG figures ---------- */
.fig-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.fig{border:1px solid var(--line);border-radius:4px;background:#fff;padding:32px 28px 34px;text-align:left}
.fig .v{font-family:var(--serif);font-size:46px;font-weight:500;color:var(--accent);
 line-height:1;letter-spacing:-.028em;margin-bottom:12px}
.fig .v .u{font-size:.5em;color:var(--ink2);margin-left:3px}
.fig h4{font-size:16px;font-weight:600;margin-bottom:7px}
.fig p{font-size:13.5px;color:var(--grey);line-height:1.6}
.fig .src{font-size:11.5px;color:var(--grey2);margin-top:12px;border-top:1px solid var(--line);padding-top:10px}

/* ---------- prose ---------- */
.prose p{font-size:16.5px;color:var(--ink2);margin-bottom:16px;line-height:1.75;max-width:70ch}
.prose p.sub{font-size:15.5px;color:var(--grey)}
/* .prose h2 rend exactement comme .prose h3. Les huit sections de
   legal.html descendaient du <h1> directement au <h3>, sans <h2> : un
   niveau saute, que les lecteurs d ecran annoncent comme un trou dans le
   plan du document. Elles passent en <h2> ; la regle ci-dessous garantit
   que la typographie, elle, ne bouge pas. */
.prose h2,
.prose h3{font-family:var(--serif);font-size:27px;font-weight:500;letter-spacing:-.02em;
 margin:44px 0 16px;line-height:1.2}
.prose h4{font-size:17px;font-weight:600;margin:30px 0 10px}
.prose ul{list-style:none;margin:0 0 20px}
.prose ul li{font-size:15.5px;color:var(--ink2);padding:7px 0 7px 22px;position:relative;line-height:1.65;max-width:70ch}
.prose ul li::before{content:'';position:absolute;left:0;top:16px;width:5px;height:5px;
 border-radius:50%;background:var(--accent)}
.prose ol{counter-reset:c;list-style:none;margin:0 0 20px}
.prose ol li{counter-increment:c;font-size:15.5px;color:var(--ink2);padding:7px 0 7px 34px;
 position:relative;line-height:1.65;max-width:70ch}
.prose ol li::before{content:counter(c,decimal-leading-zero);position:absolute;left:0;top:7px;
 font-family:var(--serif);font-size:13px;color:var(--accent);font-weight:500}
.prose a:not(.cta):not(.textlink){color:var(--accent);border-bottom:1px solid var(--accentlt)}

/* ---------- contact ---------- */
.contact-grid{display:grid;grid-template-columns:1.15fr .85fr;gap:56px;align-items:start}
.cinfo{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));background:#fff;border:1px solid var(--line);
 border-radius:4px;overflow:hidden}
.contact-item{padding:26px 28px;min-width:0}
.contact-item:nth-child(odd){border-right:1px solid var(--line)}
.contact-item:nth-child(-n+2){border-bottom:1px solid var(--line)}
.cinfo h4{font-size:11.5px;color:var(--grey2);font-weight:600;text-transform:uppercase;
 letter-spacing:1.2px;margin:0 0 7px}
.cinfo .big{font-size:16.5px;font-weight:500}
.cinfo a{color:var(--ink);text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere}
.cinfo a:hover{color:var(--accent)}

/* min-width:0 est indispensable ici. form.enq est un ELEMENT DE GRILLE de
   .contact-grid, et un element de grille a min-width:auto : il refuse de
   descendre sous sa largeur min-content. Mesure a 320px : la piste faisait
   bien 284px, mais le formulaire restait a 305 et debordait donc de 21px,
   ce qui donnait un defilement horizontal sur toute la page (document 323px
   pour 320 de large). C est le meme geste que le min-width:0 deja pose sur
   .contact-item juste au-dessus, pour la meme raison. */
form.enq{background:#fff;border:1px solid var(--line);border-radius:4px;padding:30px 30px 34px;min-width:0}
form.enq .fh{font-size:11.5px;letter-spacing:1.4px;text-transform:uppercase;color:var(--grey2);
 font-weight:600;margin-bottom:22px;padding-bottom:14px;border-bottom:1px solid var(--line)}
.frow{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
/* Marge et non `gap` : le gap FLEX n existe qu a partir de Safari 14.1, donc
   sur un iPhone reste en iOS 12/13/14.0 chaque etiquette se collait a son champ
   et le formulaire de contact devenait un mur de texte. `gap:0` est OBLIGATOIRE
   et non decoratif : sans lui les navigateurs modernes cumuleraient les deux et
   l espacement passerait de 7 a 14 px. */
.field{display:flex;flex-direction:column;gap:0}
.field > * + *{margin-top:7px}
.field.full{grid-column:1/-1}
.field label{font-size:12.5px;font-weight:600;color:var(--ink2);letter-spacing:.2px}
.field label .req{color:var(--accent)}
.field input,.field select,.field textarea{font-family:inherit;font-size:14.5px;color:var(--ink);
 border:1px solid var(--line2);border-radius:2px;padding:11px 13px;background:#fff;transition:border-color .2s}
/* iOS Safari ZOOME la page des qu on met le doigt dans un champ dont la taille
   de police est inferieure a 16 px - et il ne dezoome pas en sortant. A 14,5 px
   le visiteur qui remplissait le formulaire de contact se retrouvait donc avec
   une page agrandie, defilant horizontalement, pour tout le reste de la visite.
   16 px uniquement sous 1080 px : la mise en page du formulaire sur ordinateur
   ne bouge pas d un pixel. Meme specificite que la regle ci-dessus mais placee
   apres, donc c est l ordre source qui tranche - aucun !important. */
@media(max-width:1080px){
 .field input,.field select,.field textarea{font-size:16px}
}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent)}
.field textarea{min-height:112px;resize:vertical;line-height:1.6}
.field .hint{font-size:11.5px;color:var(--grey2);line-height:1.5}
.consent{display:flex;gap:11px;align-items:flex-start;font-size:12.5px;color:var(--grey);
 line-height:1.55;margin:6px 0 20px}
.consent input{margin-top:3px;accent-color:var(--accent);width:15px;height:15px;flex:none}
form.enq .cta{width:100%;justify-content:center}
.form-note{font-size:12px;color:var(--grey2);margin-top:14px;line-height:1.55;text-align:center}

/* ---------- footer ----------
   Sized down deliberately: this block was 534px tall on desktop and 1286px on
   a 390px phone - taller, on a phone, than the entire rest of the home page.
   It is a colophon, not a section, so it is set at label scale throughout.
   WHERE THE FLOOR IS, for whoever shrinks it further: link rows may go under
   24px tall only while row PITCH (height + gap) stays at or above 24px - that
   is WCAG 2.2 SC 2.5.8's spacing exception, and it is the binding rule here,
   not the 24px height itself. 20px height + 5px gap = 25px pitch is
   conformant; 18 + 4 is not. Body-link type stops at 12px, labels at 10px.
   The greys (#c6c6c4, #a2a3a1, #8a8a88) are already at their contrast limit
   for this size - shrink type, never lighten colour.
   NOTE: font-size and min-height for several of these are re-declared in the
   accessibility pass further down the file and win by source order. Changing a
   value here alone may do nothing. Every such override is cross-referenced. */
footer{background:var(--ink);color:#fff;padding:44px 0 26px;position:relative;overflow:hidden}
.foot-top{display:grid;grid-template-columns:1.5fr .8fr .8fr .8fr;align-items:start;gap:34px;
 padding-bottom:26px;border-bottom:1px solid rgba(255,255,255,.12)}
.foot-brand{display:flex;align-items:center;gap:10px}
.foot-brand img{height:48px;width:auto;opacity:.95}
.foot-brand .nm{font-weight:700;font-size:15px;letter-spacing:1.4px}
/* font-size overridden at the micro-label rule below */
.foot-brand .sb{letter-spacing:1.6px;color:#a2a3a1;margin-top:2px}
.foot-intro p{max-width:300px;margin-top:12px;color:#a2a3a1;font-size:11.5px;line-height:1.55}
/* font-size overridden at the micro-label rule below */
.foot-col h4,.foot-links h4{text-transform:uppercase;letter-spacing:1.2px;
 color:var(--accentlt);margin-bottom:8px}
.foot-col p,.foot-col a{display:block;color:#c6c6c4;font-size:12.5px;line-height:1.5}
.foot-col a:hover{color:#fff}
.foot-links{display:flex;flex-direction:column;gap:5px;font-size:12.5px}
.foot-links a{color:#c6c6c4}
.foot-links a:hover{color:#fff}
/* The 8-item Metals list was the tallest thing in the footer on desktop, at
   283px against a 196px-wide column doing nothing with its second half. */
@media(min-width:761px){
 .foot-links[aria-label="Metals"]{display:grid;grid-template-columns:1fr 1fr;
  column-gap:14px;row-gap:5px}
 .foot-links[aria-label="Metals"] h4{grid-column:1/-1}
}
.foot-bot{padding-top:18px;font-size:11.5px;color:#8a8a88;line-height:1.5;
 display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap}
.foot-legal{display:flex;gap:8px 18px;flex-wrap:wrap}
.foot-legal a{color:#8a8a88}
.foot-legal a:hover{color:#c6c6c4}

/* ---------- responsive ---------- */
@media(max-width:1080px){
 .nav-links{display:none;position:absolute;top:var(--nav-h);left:0;right:0;background:#fff;
  flex-direction:column;gap:0;align-items:stretch;border-bottom:1px solid var(--line);padding:8px 0;
  box-shadow:0 12px 30px rgba(0,0,0,.08);
  /* 100vh sur iOS et sur Android, c est le GRAND viewport : la hauteur que la
     page aurait si la barre d adresse etait repliee. Le panneau depassait donc
     le bas de l ecran de ~114 px sur un iPhone et le bouton "Discuss a
     transaction", qui est le dernier de la liste, se retrouvait sous la barre
     du navigateur, hors d atteinte - alors meme que le panneau ne defilait pas
     puisque sa hauteur, elle, tenait dans 100vh. Les 120 px retranches ici
     couvrent le pire ecart du parc sans svh. Le vrai chiffre est juste dessous.
     PAS deux declarations max-height a la suite : la valeur contient var(), donc
     l unite inconnue n est detectee qu au calcul, ou la propriete retombe a son
     initiale (none) au lieu de revenir a la ligne precedente. Il faut @supports. */
  max-height:calc(100vh - var(--nav-h) - 120px);
  overflow-y:auto;-webkit-overflow-scrolling:touch;
  /* Empeche le defilement de se propager a la page une fois arrive en bout de
     liste - sinon le doigt continue et fait defiler le document DERRIERE le
     menu ouvert. Complete le verrou html.nav-open pose par site.js. */
  overscroll-behavior:contain}
 /* La hauteur exacte quand le navigateur sait la donner (Safari 15.4+,
    Chrome 108+) : le petit viewport, celui qui reste visible barre d adresse
    DEPLIEE. Plus besoin des 120 px de securite ci-dessus. */
 @supports (height:100svh){
  .nav-links{max-height:calc(100svh - var(--nav-h))}
 }
 .nav-links.open{display:flex}
 .nav-links>a,.drop>button{padding:15px 32px;width:100%;border-bottom:1px solid var(--bg2);justify-content:space-between}
 .nav-links>a[aria-current="page"]::after{display:none}
 .nav-links>a[aria-current="page"]{color:var(--accent)}
 .drop-menu{position:static;opacity:1;visibility:visible;transform:none;box-shadow:none;border:none;
  border-bottom:1px solid var(--bg2);border-radius:0;background:var(--bg2);display:none;min-width:0;padding:4px 0}
 .drop.open .drop-menu{display:block}
 .drop-menu a{padding:11px 46px}
 .lang{border-left:none;padding:14px 32px;border-bottom:1px solid var(--bg2)}
 .nav-links .cta{margin:14px 32px;justify-content:center}
 .burger{display:flex}
 .panels{grid-template-columns:1fr}
 .contact-grid{grid-template-columns:1fr;gap:38px}
}
@media(max-width:980px){
 .why,.why.rev{grid-template-columns:1fr;gap:40px}
 .why-img{height:340px;order:-1}
 .approach-grid{order:-1;height:340px}
 .foot-top{grid-template-columns:1fr 1fr;gap:24px}
 .foot-intro{grid-column:1/-1}
 .prod-grid{grid-template-columns:repeat(2,1fr)}
 .comp-grid,.comp-grid.three{grid-template-columns:1fr 1fr}
 .deal-grid,.fig-grid,.desk-grid{grid-template-columns:1fr 1fr}
 .proc-grid{grid-template-columns:repeat(2,1fr);gap:32px}
 .proc-grid::before{display:none}
 .band-list{grid-template-columns:1fr 1fr}
 .hero h1{font-size:54px}
 .phero h1{font-size:40px}
 .trust .t .v{font-size:34px}
}
@media(max-width:900px){
 .grade-grid{grid-template-columns:1fr 1fr}
}
@media(max-width:760px){
 .wrap,.wrap-narrow,.nav-in{padding-left:22px;padding-right:22px}
 .brand .sb{display:none}
 .brand img{height:56px}
 .nav.compact .brand img{height:48px}
 section{padding:68px 0}
 section.tight{padding:56px 0}
 .hero{min-height:auto}
 .hero-in{padding:54px 0 48px}
 .hero h1{font-size:39px}
 .hero p.lead{font-size:16.5px}
 .phero-in{padding:64px 0 56px}
 .phero h1{font-size:32px}
 .phero p{font-size:16px}
 .sec-head{margin-bottom:44px}
 .sec-head h2{font-size:30px;padding-bottom:18px}
 .sec-head p{font-size:16px}
 .trust{grid-template-columns:1fr 1fr;gap:24px;margin-top:38px;padding-top:24px}
 .trust .t{padding:2px 0;border-left:none}
 .trust .t .v{font-size:32px}
 .prod-grid,.comp-grid,.comp-grid.three,.deal-grid,.fig-grid,.desk-grid,
 .grade-grid,.proc-grid,.band-list{grid-template-columns:1fr}
 /* Phone footer, cut as far as it will go.
    The lists run as WRAPPING ROWS, not vertical stacks. That is where nearly
    all the height went: eight metals and six nav links as eight and six rows
    cost ~340px, and the same links flowed inline cost ~100px. Everything else
    here is type and spacing.
    NOTE: h4 font-size and the link min-heights are NOT set in this block. The
    accessibility pass further down re-declares both at equal specificity and
    wins on source order, so setting them here does nothing at all. They live
    in the late block at the end of this file. */
 footer{padding:20px 0 14px}
 .foot-top{grid-template-columns:1fr;gap:11px;padding-bottom:11px}
 .foot-intro,.foot-col,.foot-links{grid-column:1/-1}
 .foot-brand{gap:7px}
 .foot-brand img{height:24px}
 .foot-brand .nm{font-size:11.5px;letter-spacing:1.1px}
 .foot-intro p{font-size:10px;line-height:1.45;margin-top:7px;max-width:none}
 .foot-col h4,.foot-links h4{letter-spacing:1px;margin-bottom:3px}
 .foot-col p,.foot-col a{font-size:10px;line-height:1.4}
 /* row-gap 4 + the 20px min-height set later = a 24px vertical pitch, which is
    WCAG 2.2 SC 2.5.8's spacing minimum. Horizontally the shortest neighbours
    are "Lead" and "Zinc": about 22px each plus the 12px column gap gives ~34px
    centre to centre, comfortably clear. Do not reduce either gap. */
 /* Marges plutot que `gap` : le gap FLEX n arrive qu avec Safari 14.1, donc sur
    un iPhone reste en iOS 12/13/14.0 les huit metaux et les cinq liens de
    navigation se suivaient sans le moindre blanc - une seule chaine de texte,
    avec des zones tactiles jointives. Le pas ne change pas : 12 px horizontaux
    et 4 px verticaux, exactement comme le gap qu ils remplacent, donc le calcul
    de pas de 24 px du critere 2.5.8 documente plus bas reste vrai.
    Les gaps sont mis a zero explicitement, sinon les navigateurs modernes
    additionneraient les deux espacements. */
 .foot-links{flex-direction:row;flex-wrap:wrap;align-items:center;
  column-gap:0;row-gap:0;font-size:10px}
 .foot-links a{margin-right:12px;margin-bottom:4px}
 .foot-links h4{flex-basis:100%;margin-bottom:1px}
 .foot-bot{padding-top:9px;font-size:9px;line-height:1.4}
 .foot-legal{gap:4px 12px}
 .hero-cta{flex-direction:column}
 .hero-cta .cta{justify-content:center}
 .cinfo{grid-template-columns:1fr}
 .contact-item:nth-child(odd){border-right:none}
 .contact-item{border-bottom:1px solid var(--line)}
 .contact-item:last-child{border-bottom:none}
 .frow{grid-template-columns:1fr}
 .band-in{padding:58px 0}
 .band-q{font-size:23px}
 .panel-in{padding:40px 26px 36px}
 .panel-in h3{font-size:27px}
 .panel{min-height:340px}
 .fig .v{font-size:38px}
 .foot-bot{flex-direction:column;gap:10px}
}
@media(max-width:360px){
 .wrap,.wrap-narrow,.nav-in{padding-left:18px;padding-right:18px}
 .hero-in{padding:44px 0 40px}
 .hero h1{font-size:32px}
 .trust .t .v{font-size:28px}
}

@media print{
 .nav,.progress,.hero-cta,form.enq{display:none}
 body{font-size:11pt}
 .hero,.phero,.band{background:#fff;color:#000}
 .hero-bg,.phero-bg,.band-bg{display:none}
 .hero-in,.phero-in,.band-in{color:#000}
 .rv{opacity:1;transform:none}
 /* The footer was white text on an ink background that browsers drop when
    printing, so it came out white on white - and with the home page down to a
    single sentence, a printed copy was very nearly blank. The metals list is
    also no longer hidden: on the home page it is the only inventory a printed
    sheet carries. */
 footer,body.has-scene footer{background:#fff;color:#000}
 .foot-col p,.foot-col a,.foot-links a,.foot-bot,.foot-legal a,.foot-intro p,
 body.has-scene .foot-col h4,body.has-scene .foot-links h4,
 .foot-col h4,.foot-links h4,.foot-brand .sb{color:#000}
 .foot-top{border-bottom-color:#ccc}
}

/* desktop dropdown on hover (JS also handles click + keyboard) */
@media (hover:hover) and (min-width:1081px){
 .drop:hover .drop-menu{opacity:1;visibility:visible;transform:translateY(0)}
 .drop:hover>button svg{transform:rotate(180deg)}
}
/* nav dropdown needs a hover bridge so the pointer can travel to the menu */
@media (min-width:1081px){ .drop::after{content:'';position:absolute;left:0;right:-40px;top:100%;height:22px} }
/* clickable metal cards keep body-copy colour */
a.prod,a.prod:hover{color:inherit}
.also .it a{border-bottom:1px solid var(--accentlt)}
.also .it a:hover{color:var(--accent)}

/* ==========================================================================
   Accessibility pass : verified in Chrome at 360/375/393/768/1024/1440/1920
   1. Every interactive target reaches the 24x24px minimum (WCAG 2.2 AA,
      Target Size Minimum). Sizes below were measured, not guessed.
   2. Two micro-labels sat under the readable floor (9px and 10px).
   ========================================================================== */

/* --- 1. tap targets --- */
.nav-links > a,
.drop > button{min-height:24px}

.drop-menu a{min-height:26px;display:flex;align-items:center}

.crumb a,
.crumb span{min-height:24px;display:inline-flex;align-items:center}

/* min-height here is dead - the rule at "any remaining link laid out inline
   inside a nav list" below re-declares it at equal specificity and wins. Only
   the display/alignment survives. */
.foot-links a,
.foot-col a{display:flex;align-items:center}

/* min-width was inert: the shortest label, "Legal", is already ~33px wide.
   min-height stays 24px - .foot-legal is a horizontal row with nothing to
   trade the spacing exception against if it wraps. */
.foot-legal a{min-height:24px;display:inline-flex;align-items:center;
 justify-content:center}

/* the language switch is two very short labels; give them a real hit area */
.lang a{min-height:24px;min-width:28px;display:inline-flex;align-items:center;
 justify-content:center}

/* --- 2. text below the readable floor --- */
/* .foot-brand .sb dropped from this pair - it is set once, at the footer
   micro-label rule below, and having it here too made three live declarations
   for one property in one file. */
.brand .sb{font-size:10.5px;letter-spacing:1.5px}

.grade .isri{font-size:11px}

/* --- 3. remaining targets found in the second browser pass --- */

/* consent checkbox was rendering at the browser default 15x15 */
.consent input[type="checkbox"],
form.enq input[type="checkbox"]{width:24px;height:24px;flex:none;accent-color:var(--accent);
 cursor:pointer;margin:0}
/* Meme raison que .field : sans gap flex, la case a cocher de 24 px touchait sa
   phrase. gap:0 explicite, sinon la marge s ajouterait au gap sur les moteurs
   recents. */
.consent{display:flex;gap:0;align-items:flex-start}
.consent > * + *{margin-left:12px}

/* email and phone in the contact block are standalone actions, not prose links */
.cinfo .big a{min-height:24px;display:inline-flex;align-items:center}

/* any remaining link laid out inline inside a nav list.
   THIS is the declaration that sets footer link row height - the 26px above is
   overridden here. The footer lists drop to 20px, which is legal only because
   .foot-links carries gap:5px: 20 + 5 = 25px pitch, over SC 2.5.8's 24px.
   If that gap is ever removed, this must go back to 24. */
.drop-menu a,.nav-links > a{min-height:24px}
.foot-links a{min-height:20px}
/* .foot-col's two links are flush siblings with no gap to lend them, so they
   keep the full height. There are only two, so it costs 8px. */
.foot-col a{min-height:24px}

/* --- 4. micro-label floor: nothing below 12px anywhere --- */
.eyebrow,
.also .lab,
.ph.elem .sym .z,
.ph.elem .aw,
.ptable th,
.deal .dh .k,
.desk .lab,
.fig .src,
.cinfo h4,
form.enq .fh,
.field .hint,
.grade .isri,
.brand .sb{font-size:12px}

/* keep the letterspacing readable now the labels are slightly larger */
.brand .sb{letter-spacing:1.2px}

/* The footer's own labels are pulled out of that 12px group. The floor above
   was self-imposed, not a WCAG requirement: nothing in 2.2 sets a minimum type
   size, and these are uppercase tracked labels of one or two words, not running
   text. 11px and 10px stay legible at that tracking; do not go lower.
   The header wordmark keeps 12px - it is the only one of the three that has to
   be read against a white bar on the other fifteen pages. */
.foot-col h4,.foot-links h4{font-size:11px}
.foot-brand .sb{font-size:10px;letter-spacing:1.1px}

/* --- 5. inline links inside legal prose ---
   WCAG 2.2 exempts targets inline in a sentence, but vertical padding on an
   inline element grows the hit area without changing the line box, so the
   text still flows exactly as before. */
.prose a:not(.cta):not(.textlink){padding-top:2px;padding-bottom:2px;padding-block:2px}


/* --- coverage marquee: flags --- */
.marq-item img{width:26px;height:auto;aspect-ratio:3/2;object-fit:cover;border-radius:2px;
 border:1px solid rgba(21,22,26,.14);box-shadow:0 1px 2px rgba(20,24,28,.10);flex:none}
.marq-item{gap:11px}
@media(max-width:760px){
 .marq{padding:20px 0}
 .marq-item{padding:0 18px;font-size:13px;gap:9px}
 .marq-item img{width:22px}
 .marq-track{animation-duration:80s}
}

/* ==========================================================================
   Primary call to action and focus states
   The nav button was an outlined pill and the focus ring used the same accent,
   so activating it produced a halo of one tint on another. The button is now
   solid ink, which reads as the primary action without leaning on the accent,
   and focus rings take their colour from the ground they sit on.
   ========================================================================== */

.cta-primary{background:var(--ink);border-color:var(--ink);color:#fff}
/* Sur ecran tactile :hover reste colle apres le tap : le bouton garde son
   etat survole jusqu au tap suivant ailleurs. On le reserve donc au pointeur,
   comme le fait deja la fin de ce fichier. :active et le style de repos ne
   changent pas, et rien ne change sur ordinateur. */
@media(hover:hover) and (pointer:fine){
 .cta-primary:hover{background:var(--accent2);border-color:var(--accent2);color:#fff !important}
}
.cta-primary svg{stroke:#fff}
.cta-primary:active{background:#000;border-color:#000;transform:translateY(1px)}

/* no tinted flash on tap; the :active state below is the feedback */
a,button,summary,input,select,textarea,label{-webkit-tap-highlight-color:transparent}
.cta:active{transform:translateY(1px)}

/* focus ring: ink on light ground, white on dark ground */
a:focus-visible,button:focus-visible,summary:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible{
 outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}

.hero a:focus-visible,.hero button:focus-visible,
.phero a:focus-visible,
.band a:focus-visible,
.strip a:focus-visible,
footer a:focus-visible,
.panel:focus-visible,
.cta-light:focus-visible{outline-color:#fff}

/* text selection in the brand palette rather than the browser default */
::selection{background:var(--ink);color:#fff}

/* ==========================================================================
   Mobile menu fix
   .nav-links > a got width:100%, and the CTA is also a direct child, so it
   was 100% of the menu PLUS its own 32px side margins: it hung 32px off the
   right edge on every phone width. width:auto lets align-items:stretch size
   it correctly inside the margins.
   ========================================================================== */
@media(max-width:1080px){
 .nav-links .cta{width:auto;margin:14px 22px;justify-content:center}
 .nav-links{padding-bottom:4px}
}

/* inline link inside running text: grow the hit area without moving the line */
.sec-head p .textlink,
.proc p .textlink{padding-top:3px;padding-bottom:3px;padding-block:3px}

/* ==========================================================================
   Nav CTA: restore the button
   `.nav-links > a` (specificity 0,2,1) sets background:none, border:none and
   padding:0, which beat `.cta` / `.cta-primary` (0,1,0). The primary button in
   the header was therefore rendering as plain text. These rules match that
   specificity so the button is a button again.
   ========================================================================== */
.nav-links > a.cta{
 background:var(--ink);
 border:1px solid var(--ink);
 border-radius:2px;
 color:#fff;
 padding:11px 20px;
 min-height:42px;
 font-size:13.5px;
 font-weight:600;
 letter-spacing:.4px;
 transition:background .25s,border-color .25s,transform .1s;
}
/* Sur ecran tactile :hover reste colle apres le tap : le bouton garde son
   etat survole jusqu au tap suivant ailleurs. On le reserve donc au pointeur,
   comme le fait deja la fin de ce fichier. :active et le style de repos ne
   changent pas, et rien ne change sur ordinateur. */
@media(hover:hover) and (pointer:fine){
 .nav-links > a.cta:hover{background:var(--accent2);border-color:var(--accent2);color:#fff}
}
.nav-links > a.cta:active{background:#000;border-color:#000;transform:translateY(1px)}
.nav-links > a.cta svg{stroke:#fff;width:13px;height:13px}

/* slightly tighter once the header compacts on scroll */
.nav.compact .nav-links > a.cta{padding:9px 18px;min-height:38px}

@media(max-width:1080px){
 .nav-links > a.cta{width:auto;margin:14px 22px;justify-content:center;min-height:48px}
}

/* inline links in the "also traded" run: bigger hit area, same line height */
.also .it a{padding-top:3px;padding-bottom:3px;padding-block:3px}

/* ==========================================================================
   Image scale
   The photography was doing too much of the work: card images at 188px and
   page images at 480-520px made the layout read as a stock-photo grid rather
   than a trading desk. Everything below is pulled back so the type leads and
   the images support it.
   ========================================================================== */

.prod .ph{height:150px}
.why-img{height:420px}
.approach-grid{height:420px}
.why-img[style]{height:430px !important}   /* the inline 520px on metal pages */

@media(max-width:980px){
 .why-img,.why-img[style]{height:300px !important}
 .approach-grid{height:300px}
}
@media(max-width:760px){
 .prod .ph{height:170px}                   /* single column, so it can breathe */
 .why-img,.why-img[style]{height:250px !important}
 .approach-grid{height:250px}
}

/* the metal name was printed on the photo and again as the card heading
   directly underneath; keep the heading, drop the duplicate */
.prod .ph-name{display:none}
.prod .ph.photo{display:block;padding:0}
.prod .ph.photo::after{background:linear-gradient(to top,rgba(16,17,20,.34),rgba(16,17,20,0) 55%)}


/* ==========================================================================
   Interior page banner without a photograph
   Every interior hero was repeating an image that already appears further
   down the same page. They now carry type on ink, with a soft directional
   wash so the panel has depth without borrowing a picture.
   ========================================================================== */
.phero-plain{background:var(--ink)}
.phero-plain::before{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;z-index:0;pointer-events:none;
 background:
  radial-gradient(120% 140% at 82% 0%, rgba(255,255,255,.07) 0%, rgba(255,255,255,0) 58%),
  linear-gradient(160deg, #1c1e24 0%, #15161a 52%, #101116 100%)}
.phero-plain .phero-in{position:relative;z-index:2;padding-top:88px;padding-bottom:78px}
.phero-plain::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;z-index:1;
 background:linear-gradient(90deg,var(--accent) 0%,rgba(255,255,255,.22) 34%,rgba(255,255,255,0) 70%)}
@media(max-width:760px){.phero-plain .phero-in{padding-top:56px;padding-bottom:52px}}

/* ==========================================================================
   Contract documents
   ========================================================================== */
.docs{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.doc{display:flex;gap:22px;align-items:flex-start;background:#fff;border:1px solid var(--line);
 border-radius:4px;padding:28px 28px 26px;transition:border-color .3s,box-shadow .35s,transform .35s}
.doc:hover{border-color:var(--accent);transform:translateY(-3px);
 box-shadow:0 16px 38px rgba(20,24,28,.08)}
.doc-ico{flex:none;width:46px;height:46px;border-radius:3px;background:var(--accent-wash);
 border:1px solid var(--accentlt);display:flex;align-items:center;justify-content:center}
.doc-ico svg{width:22px;height:22px;stroke:var(--accent);fill:none;stroke-width:1.6;
 stroke-linecap:round;stroke-linejoin:round}
.doc-k{font-size:12px;letter-spacing:1.4px;text-transform:uppercase;color:var(--accent);
 font-weight:600;margin-bottom:9px}
.doc-bd h3{font-size:19px;font-weight:600;line-height:1.28;margin-bottom:10px;letter-spacing:-.01em}
.doc-bd p{font-size:14px;color:var(--grey);line-height:1.62;margin-bottom:16px}
.doc-meta{display:flex;flex-wrap:wrap;gap:8px 10px;border-top:1px solid var(--line);padding-top:14px}
.doc-meta span{font-size:11.5px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;
 color:var(--grey2);border:1px solid var(--line2);border-radius:2px;padding:4px 9px}
.doc-meta span:first-child{color:var(--accent);border-color:var(--accentlt);background:var(--accent-wash)}
@media(max-width:900px){.docs{grid-template-columns:1fr}}
@media(max-width:760px){.doc{flex-direction:column;gap:16px;padding:24px 22px}}

/* ==========================================================================
   Ocean + cargo hero scene (home page only)
   Everything here is gated behind body.has-scene, which exists on index.html
   and nowhere else, so the other 15 pages are untouched.
   ========================================================================== */

/* The stage sits at -1: the propagated body background still paints below it,
   and every existing layer (hero children 0-4, .nav 100, .progress 200,
   .skip 300) stays exactly where it was. No existing z-index moves. */
#scene{position:fixed;top:0;right:0;bottom:0;left:0;inset:0;z-index:-1;overflow:hidden;pointer-events:none;background:#03101f}
#scene .webgl-canvas-host,
#scene .webgl-canvas-host .webgl-canvas{width:100%;height:100%;display:block}
#scene .webgl-canvas-host{opacity:0;transition:opacity 700ms ease}
#scene.is-ready .webgl-canvas-host{opacity:1}
/* Rendering stops once the hero leaves the viewport, but the canvas is NOT
   hidden. It used to be (visibility:hidden), and because <main> now holds only
   the hero, that fired as soon as you scrolled on a phone: the ship blinked out
   a few hundred pixels down. Leaving the last frame painted costs nothing - the
   footer below is opaque ink, so nothing translucent can show it - and the ship
   is simply there again the moment you scroll back up. */
#scene.is-offscreen{visibility:visible}

/* Focus vignette: the cargo stays sharp, everything outward is blurred and
   darkened. Carried over verbatim from the reference scene. */
#scene .webgl-vignette{position:absolute;top:0;right:0;bottom:0;left:0;inset:0;pointer-events:none;
 backdrop-filter:blur(23px) saturate(.75) brightness(.85);
 -webkit-backdrop-filter:blur(23px) saturate(.75) brightness(.85);
 background:
  linear-gradient(90deg,rgba(3,12,30,0) 52%,rgba(3,11,28,.5) 76%,rgba(2,8,22,.92) 100%),
  radial-gradient(ellipse 50% 40% at 50% 50%,rgba(3,12,30,0) 0%,rgba(3,11,28,.62) 60%,rgba(2,8,20,.94) 100%);
 -webkit-mask-image:radial-gradient(ellipse 46% 32% at 50% 50%,rgba(0,0,0,0) 0%,rgba(0,0,0,0) 42%,rgba(0,0,0,.8) 70%,rgba(0,0,0,1) 100%);
 mask-image:radial-gradient(ellipse 46% 32% at 50% 50%,rgba(0,0,0,0) 0%,rgba(0,0,0,0) 42%,rgba(0,0,0,.8) 70%,rgba(0,0,0,1) 100%)}

/* --- letting the scene through the hero ---------------------------------- */
/* .hero is opaque ink by default. Only once the canvas has actually faded in
   do we open it up, so a failed or gated scene shows the photograph exactly
   as before. */
body.has-scene.scene-ready .hero{background:transparent}
/* EXCEPTION TELEPHONE : html.is-phone rouvre la photographie pendant
   scene-pending (bloc en fin de fichier). L invariant decrit ci-dessous ne vaut
   donc que pour la tablette et l ordinateur. Sur telephone la photographie
   porte volontairement l attente, puis se fond en 700 ms a l arrivee de
   scene-ready - il y a ~1,37 Mo a transferer la-bas, et un fond bleu marine nu
   pendant plusieurs secondes etait le defaut d origine.
   Fade the photograph, NOT .hero-bg itself: the hero's whole text contrast
   comes from .hero-bg::after, which is a child of it.
   KEYED ON scene-pending, so the photograph NEVER appears on a machine that is
   going to run the scene - no picture of a port flashing up for a second and
   then being replaced by the ocean. What fills the gap instead is #scene's own
   background (#03101f) under body.has-scene's #070b11: the same near-black the
   water resolves to, so the canvas fading in over it reads as the scene
   arriving, not as one backdrop swapping for another.
   scene-pending is set during parsing and cleared only when the gate gives up,
   so this covers loading AND running; the photograph is reserved entirely for
   the no-scene path, where it is the whole hero. */
body.has-scene.scene-pending .hero-bg img,
body.has-scene.scene-pending .hero-bg video{opacity:0}
body.has-scene .hero-bg img,
body.has-scene .hero-bg video{transition:opacity 700ms ease}

/* Every section below the hero must be opaque or the fixed canvas shows
   through it. Element-only specificity (0,0,2), so .bg2, .band and .panel
   all still win. */


/* --- navigation floating over the scene ----------------------------------
   Everything here used to be scoped `:not(.compact)`, on the reasoning that
   site.js adds .compact past 40px of scroll so "the solid bar returns for
   free". On a white page it does. On this one it meant the entire header
   flipped to rgba(255,255,255,.985) the instant you started scrolling - a
   white band across a night sea, with the wordmark going invisible on it
   because its light-on-dark rule switched off in the same tick.
   So: the nav is treated as a dark surface at EVERY scroll position, and only
   the background differs between the two states - fully transparent over the
   hero, dark glass once compacted. Nothing below may be re-scoped back to
   :not(.compact) in isolation; the type, burger, CTA and focus rings are all
   part of the same surface and have to travel together. */
/* Transparent at EVERY scroll position, compacted or not. The bar first went
   white past 40px of scroll, then dark glass; both read as a band appearing
   across the top of the scene. There is no band now - the ocean runs behind
   the logo and the burger exactly as it does everywhere else.
   Legibility is bought with a shadow on the marks themselves instead of a
   surface behind them, the same trade as the h1. The open mobile menu keeps
   its dark sheet: that is a panel you summon, not the bar. */
body.has-scene .nav,
body.has-scene .nav.compact{background:transparent;border-bottom-color:transparent;
 box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}

/* Without a surface behind them these sit straight on the water, so each one
   carries its own shading: a tight shadow for edge definition and a wide soft
   one that darkens the few pixels immediately around the glyph. */
body.has-scene .nav .brand .nm,
body.has-scene .nav .brand .sb,
body.has-scene .nav .nav-links > a,
body.has-scene .nav .drop > button{
 text-shadow:0 1px 2px rgba(4,8,15,.55), 0 1px 12px rgba(4,8,15,.65)}
body.has-scene .nav .brand img{filter:drop-shadow(0 1px 4px rgba(4,8,15,.6))}
body.has-scene .nav .burger span{box-shadow:0 1px 3px rgba(4,8,15,.7)}
/* The outlined CTA loses its edge against bright water without this. */
body.has-scene .nav .nav-links > a.cta{box-shadow:0 2px 14px rgba(4,8,15,.45)}
body.has-scene .nav .brand .nm{color:#fff}
body.has-scene .nav .brand .sb{color:rgba(255,255,255,.62)}
body.has-scene .nav .nav-links > a,
body.has-scene .nav .drop > button{color:rgba(255,255,255,.86)}
body.has-scene .nav .nav-links > a:hover,
body.has-scene .nav .drop > button:hover{color:#fff}
body.has-scene .nav .nav-links > a[aria-current="page"]{color:#fff}
body.has-scene .nav .burger span{background:#fff}
/* Solid white pill, ink lettering - the one opaque element in a transparent
   bar, which is what makes it read as the action rather than another link.
   .nav-links > a.cta is (0,2,1) in the base sheet; this is (0,3,1). */
body.has-scene .nav .nav-links > a.cta{background:#fff;
 border-color:#fff;color:var(--ink)}
body.has-scene .nav .nav-links > a.cta svg{stroke:var(--ink)}
/* Behind a real pointer: on a touch screen :hover sticks after the tap, so
   touch gets :active instead and never keeps a hover state. */
@media(hover:hover) and (pointer:fine){
 body.has-scene .nav .nav-links > a.cta:hover{background:#e8e9ea;
  border-color:#e8e9ea;color:var(--ink)}
 body.has-scene .nav .nav-links > a.cta:hover svg{stroke:var(--ink)}
}
body.has-scene .nav .nav-links > a.cta:active{background:#dcdee0;
 border-color:#dcdee0;color:var(--ink)}
/* The focus-ring exception list does not cover .nav; without this, keyboard
   focus is a near-black ring on near-black glass. Must stay un-scoped, or it
   disappears again the moment the bar compacts. */
body.has-scene .nav a:focus-visible,
body.has-scene .nav button:focus-visible{outline-color:#fff}

/* The mobile sheet: dark glass, not the white slab it was. This panel is what
   holds Metals / Copper / ... / Discuss a transaction, so every one of its
   parts - sheet, row dividers, submenu tray, link colour, CTA - has to be
   converted in the same pass. Half-converting it is worse than leaving it
   white: ink text on dark glass, or a black CTA on a black sheet. */
@media(max-width:1080px){
 .nav-links{top:100%}
 body.has-scene .nav .nav-links{background:rgba(7,11,17,.92);
  -webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
  border-bottom:1px solid rgba(255,255,255,.10);
  box-shadow:0 18px 40px rgba(0,0,0,.5)}
 /* the base sheet separates rows with a --bg2 hairline: bright ladder lines */
 body.has-scene .nav .nav-links > a,
 body.has-scene .nav .drop > button{border-bottom-color:rgba(255,255,255,.08)}
 /* the expanded Metals tray is #f6f6f5 in the base sheet */
 body.has-scene .nav .drop-menu{background:rgba(255,255,255,.05);
  border-bottom-color:rgba(255,255,255,.08)}
 body.has-scene .nav .drop-menu a{color:rgba(255,255,255,.74)}
 body.has-scene .nav .drop-menu a:hover,
 body.has-scene .nav .drop-menu a:active{background:rgba(255,255,255,.10);color:#fff}
 body.has-scene .nav .drop-menu .sep{background:rgba(255,255,255,.12)}
 body.has-scene .nav .drop-menu a.all{color:#fff}
 /* on a dark sheet the primary action is the light one - it was solid --ink,
    i.e. a black block on a black panel */
 body.has-scene .nav .nav-links > a.cta{background:#fff;border-color:#fff;
  color:var(--ink)}
 body.has-scene .nav .nav-links > a.cta svg{stroke:var(--ink)}
 body.has-scene .nav .nav-links > a.cta:active{background:#e8e9ea;
  border-color:#e8e9ea;color:var(--ink)}
}

/* Desktop Metals dropdown: a solid white 252px panel floating over the ocean. */
@media(min-width:1081px){
 body.has-scene .drop-menu{background:rgba(9,13,20,.90);
  -webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
  border-color:rgba(255,255,255,.12);box-shadow:0 20px 48px rgba(0,0,0,.55)}
 body.has-scene .drop-menu a{color:rgba(255,255,255,.78)}
 body.has-scene .drop-menu a:hover{background:rgba(255,255,255,.09);color:#fff}
 body.has-scene .drop-menu a.all{color:#fff}
 body.has-scene .drop-menu .sep{background:rgba(255,255,255,.12)}
}

/* The reading-progress bar ends in --accentlt, a near-white stroke pinned
   above the dark bar. */
body.has-scene .progress{
 background:linear-gradient(90deg,rgba(255,255,255,.62),rgba(255,255,255,.16))}

/* The scene now runs on phones and tablets too; only motion preference and
   print remove it. The WebGPU adapter probe in index.html handles capability. */
@media(prefers-reduced-motion:reduce){#scene{display:none}}
@media print{#scene{display:none}}

/* --- scrim and vignette, retuned for the scene ---------------------------
   The stock hero scrim is rgba(19,24,31,.94) at the left because it sits over
   a photograph at 50% opacity. Over a live ocean it simply erased the ocean.
   This ramps far harder to the right, keeping the text column dark enough to
   read while opening the water where the cargo actually is. */
body.has-scene.scene-ready .hero-bg::after{
 background:linear-gradient(100deg,
  rgba(8,13,20,.90) 0%,
  rgba(8,13,20,.72) 26%,
  rgba(8,13,20,.40) 52%,
  rgba(8,13,20,.14) 78%,
  rgba(8,13,20,.04) 100%)}
/* The reference vignette assumed a ship centred in a full viewport. Here the
   hero is a band across the top of the page, so the clear zone is widened and
   the right-hand darkening is pulled back from .92 to something that still
   hides the far sea without producing a black wall.
   The mask plateau is pushed out from 48% to 58% and the ramp softened, because
   the hull was sitting just outside the old plateau and picking up both the
   darkening and the 23px backdrop blur - the ship itself was being dimmed and
   softened. Effective alpha at the hull drops from about .16 to about .05.
   This rule is (1,2,1) and sits outside any media query, so it governs the
   vignette at EVERY width: the phone override further down has to repeat the
   body.has-scene prefix to reach it. */
body.has-scene #scene .webgl-vignette{
 background:
  linear-gradient(90deg,rgba(3,12,30,0) 64%,rgba(3,11,28,.22) 84%,rgba(2,8,22,.44) 100%),
  radial-gradient(ellipse 66% 54% at 52% 46%,rgba(3,12,30,0) 0%,rgba(3,11,28,.26) 62%,rgba(2,8,20,.56) 100%);
 -webkit-mask-image:radial-gradient(ellipse 62% 48% at 52% 46%,rgba(0,0,0,0) 0%,rgba(0,0,0,0) 58%,rgba(0,0,0,.55) 80%,rgba(0,0,0,.85) 100%);
 mask-image:radial-gradient(ellipse 62% 48% at 52% 46%,rgba(0,0,0,0) 0%,rgba(0,0,0,0) 58%,rgba(0,0,0,.55) 80%,rgba(0,0,0,.85) 100%)}

/* ==========================================================================
   Home page over the ocean
   The scene is behind the whole document now, so nothing on this page may be
   opaque white. Sections carry a dark veil instead: enough to read against,
   thin enough that the water still moves through it. Everything is scoped to
   body.has-scene, so the other 15 pages keep their white paper look.
   ========================================================================== */

body.has-scene{background:#070b11;color:#e8e9ea}


/* Every section on the home page is transparent: the ocean is the page
   background from top to bottom, exactly like the hero. */
body.has-scene main > section{background:transparent;position:relative}

/* --- type ---------------------------------------------------------------- */
body.has-scene .sec-head h2,
body.has-scene h2,body.has-scene h3,body.has-scene h4{color:#fff}
body.has-scene .sec-head p,
body.has-scene .proc p,
body.has-scene .prod .bd p,
body.has-scene .why-list p,
body.has-scene .faq details p,
body.has-scene .also .it span{color:#c9cccf}
body.has-scene .sec-head h2::after{background:rgba(255,255,255,.55)}
body.has-scene .eyebrow{color:#adb1b5}
body.has-scene .also .lab{color:#8f9398}
body.has-scene .also{border-top-color:rgba(255,255,255,.14)}
body.has-scene .also .it{color:#fff}

/* --- cards and panels ---------------------------------------------------- */
body.has-scene .prod{background:rgba(13,18,26,.66);border-color:rgba(255,255,255,.12)}
body.has-scene .prod:hover{background:rgba(16,22,31,.78);border-color:rgba(255,255,255,.28);
 box-shadow:0 18px 44px rgba(0,0,0,.45)}
body.has-scene .prod .bd h3{color:#fff}
body.has-scene .prod .bd .role{color:#adb1b5}
body.has-scene .prod .bd .meta{color:#c9cccf;border-top-color:rgba(255,255,255,.12)}
body.has-scene .prod .bd .meta b{color:#8f9398}
body.has-scene .prod .bd .more{color:#fff}

/* --- process ------------------------------------------------------------- */
body.has-scene .proc .ico{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.16)}
body.has-scene .proc .ico svg{stroke:#fff}
body.has-scene .proc .n{color:#adb1b5}
body.has-scene .proc-grid::before{background:rgba(255,255,255,.14)}

/* --- approach list ------------------------------------------------------- */
body.has-scene .why-list li{border-bottom-color:rgba(255,255,255,.12)}
body.has-scene .why-list .ck{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.18)}
body.has-scene .why-list .ck svg{stroke:#fff}

/* --- faq ----------------------------------------------------------------- */
body.has-scene .faq{border-top-color:rgba(255,255,255,.14)}
body.has-scene .faq details{border-bottom-color:rgba(255,255,255,.12)}
body.has-scene .faq summary{color:#fff}
body.has-scene .faq summary::after{border-color:rgba(255,255,255,.7)}

/* --- contact block ------------------------------------------------------- */
body.has-scene .cinfo{background:rgba(13,18,26,.66);border-color:rgba(255,255,255,.14)}
body.has-scene .contact-item{border-color:rgba(255,255,255,.12) !important}
body.has-scene .cinfo h4{color:#8f9398}
body.has-scene .cinfo .big{color:#fff}
body.has-scene .cinfo .sm{color:#c9cccf}
body.has-scene .cinfo a{color:#fff;text-decoration-color:rgba(255,255,255,.45)}

/* --- buttons over the dark page ------------------------------------------ */
body.has-scene .cta:not(.cta-light):not(.cta-primary){border-color:rgba(255,255,255,.45);color:#fff}
body.has-scene .cta:not(.cta-light):not(.cta-primary):hover{background:#fff;color:var(--ink)}
body.has-scene .cta:not(.cta-light):not(.cta-primary):hover svg{stroke:var(--ink)}
body.has-scene .textlink{color:#fff}
body.has-scene .note{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.14);
 border-left-color:rgba(255,255,255,.5);color:#c6c9cc}
body.has-scene .note b{color:#fff}

/* Measured, not guessed: with the ocean behind the trust band these sat at
   4.11:1 against a moving background. Raised until the worst sample across
   eight scroll depths cleared 4.5:1. */
body.has-scene .band-list .bi p,
body.has-scene .band-list li span,
body.has-scene .trust .t .l,
body.has-scene .strip p,
body.has-scene .foot-intro p,
body.has-scene .foot-col p{color:#c4c6c4}


/* The image panels carry their own scrim; over the ocean it was not enough
   for their body copy. Deepened, and the text lifted with it. */
body.has-scene .panel::after{background:linear-gradient(to top,
 rgba(6,10,16,.94) 0%,rgba(6,10,16,.74) 42%,rgba(6,10,16,.34) 72%,rgba(6,10,16,.18) 100%)}
body.has-scene .panel-in p{color:#dcdee0}

/* --- readability on narrow screens ---------------------------------------
   The panel and band scrims were ramped for a wide landscape tile. In portrait
   the same gradient stops land much higher up the image, so body copy sat as
   low as 1.61:1 against the brightest frames. Measured, then deepened until
   the worst sample across eight scroll depths cleared 4.5:1. */
@media(max-width:820px){



 body.has-scene .panel::after{background:linear-gradient(to top,
  rgba(5,8,13,.97) 0%,rgba(5,8,13,.90) 46%,rgba(5,8,13,.74) 74%,rgba(5,8,13,.58) 100%)}
 body.has-scene .band-bg img{opacity:.16}
 body.has-scene .panel img{opacity:.38}
}
@media(max-width:820px){body.has-scene .panel-in p{color:#e6e8ea}}

/* ==========================================================================
   Product cards on phones
   One card per row meant one card per screen: you could never compare two
   metals without scrolling. Two columns with a tighter card keeps the same
   reading order and puts three rows in view, like the desktop grid.
   ========================================================================== */
@media(max-width:640px){
 body.has-scene .prod-grid,
 .prod-grid{grid-template-columns:repeat(2,1fr);gap:12px}
 .prod .ph{height:96px}
 .prod .bd{padding:14px 14px 16px}
 .prod .bd h3{font-size:15.5px;margin-bottom:4px;letter-spacing:-.005em}
 .prod .bd .role{font-size:12px;letter-spacing:.3px;margin-bottom:8px;line-height:1.3}
 .prod .bd p{font-size:12.5px;line-height:1.5;margin-bottom:10px}
 /* the commercial-basis line is reference detail, not comparison material:
    it is on the metal's own page, so it goes rather than squeezing the card */
 .prod .bd .meta{display:none}
 .prod .bd .more{font-size:12px;margin-top:2px}
}
@media(max-width:380px){
 .prod-grid{gap:10px}
 .prod .ph{height:84px}
 .prod .bd{padding:12px 11px 14px}
 .prod .bd h3{font-size:14.5px}
 .prod .bd p{font-size:12px}
}

/* --- vignette on phones ---------------------------------------------------
   Sections stay transparent, so the ocean IS the page background. On a narrow
   screen the text column sits exactly where the desktop vignette keeps the
   water clear for the ship, which measured 2.10:1. Rather than putting a veil
   back on the sections, the backdrop itself is darkened: the mask is dropped
   so the darkening covers the whole frame, with the centre lighter so the hull
   still reads. */
@media(max-width:820px){
 /* MUST carry body.has-scene: the retune at line 911 is (1,2,1) and sits
    outside any media query, so a bare `#scene .webgl-vignette` here is (1,1,0)
    and loses on every declaration except backdrop-filter. Written that way this
    whole block silently did nothing, which is why the phone stayed dark however
    hard these numbers were pulled down. */
 #scene .webgl-vignette{backdrop-filter:none;-webkit-backdrop-filter:none}
 body.has-scene #scene .webgl-vignette{
  -webkit-mask-image:none;mask-image:none;
  background:
   linear-gradient(180deg,rgba(4,9,17,.06) 0%,rgba(4,9,17,.16) 38%,rgba(4,9,17,.30) 100%),
   radial-gradient(ellipse 74% 30% at 52% 24%,rgba(4,9,17,0) 0%,rgba(4,9,17,.10) 62%,rgba(4,9,17,.24) 100%)}
}

/* ==========================================================================
   Backdrop level
   Sections are transparent, so the ocean is the page background everywhere.
   The original levels were measured against body copy sitting over the water,
   and they were correct for that page. <main> now holds a single h1 and nothing
   else, so there is no body copy left to protect: at 68px (39px on a phone) the
   applicable bar is WCAG large-text 3:1, not 4.5:1.
   The old composite removed 74.5% of the rendered ocean at frame centre and
   77.7% under the headline - roughly 17:1 against white, five to six times more
   margin than the page needs. These levels put the sea back: 40.6% at centre,
   44.0% under the h1, which still measures 8.8:1 over lit swell and 4.8:1
   against a foam crest. Re-derive these if body copy ever returns to <main>. */
#scene::after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;inset:0;pointer-events:none;z-index:3;
 background:
  linear-gradient(180deg,rgba(4,8,15,.20) 0%,rgba(4,8,15,.34) 55%,rgba(4,8,15,.46) 100%),
  radial-gradient(ellipse 58% 34% at 52% 30%,rgba(4,8,15,0) 0%,rgba(4,8,15,.12) 60%,rgba(4,8,15,.28) 100%)}
/* The phone override for #scene::after lives at the end of this file, next to
   the mobile hero rules. There used to be a second copy here with much heavier
   values; identical selector, identical media query, so the later one won and
   this one had never rendered a pixel. It is gone - it only served to send
   anyone tuning phone brightness to the wrong block. */


/* --- hero identical to every other section --------------------------------
   The hero carried its own scrim (.hero-bg::after) while the sections below
   are transparent, so the first screen read as a different colour from the
   second. With the backdrop now darkened inside #scene, that scrim is doing
   nothing except creating that seam, so it is dropped - but only once the
   canvas is actually up. It used to be dropped the moment the gate DECIDED the
   scene would run, which traded a brief cross-fade for a multi-second blank
   screen. The 700ms transitions below cross-fade the two states anyway.
   (This wins over the 100deg retune at line 900: same specificity, later.) */
body.has-scene.scene-pending .hero-bg::after{background:none}
body.has-scene.scene-pending .hero{background:transparent}

/* --- full-height hero on phones ------------------------------------------
   With the page stripped back there is no longer anything to scroll past in
   the first screen, and the hull had nowhere to sit that was not behind the
   buttons. Giving the hero the whole viewport opens a band below the calls to
   action for it. svh, not vh: vh on iOS is the LARGE viewport, so the bottom
   of the hero would sit under the browser toolbar.
   Scoped to .scene-pending, which is set only when the gate has decided the
   scene will actually run. On a phone with no WebGPU the class is cleared and
   the hero falls back to its normal height, instead of handing the visitor a
   full viewport of dimmed photograph carrying one sentence. */
@media(max-width:820px){
 /* SAME HEIGHT with the scene and without it.
    The no-scene hero used to be 62svh against the scene's 100svh, so a phone
    that cannot run WebGPU did not get a degraded version of the page - it got
    a visibly different page, hero a third shorter and the footer riding up.
    That is exactly what came back from an iPhone: "the old page". One height
    for both paths, and the fallback becomes what it should have been all
    along - the same composition, carried by the photograph. */
 body.has-scene .hero{min-height:100svh}
 body.has-scene.scene-pending .hero{min-height:100svh;padding-bottom:0}
 body.has-scene .hero-in{padding-top:44px;padding-bottom:0}
}
@supports not (height: 100svh){
 @media(max-width:820px){
  body.has-scene .hero{min-height:100vh}
  body.has-scene.scene-pending .hero{min-height:100vh}
 }
}

/* Mobile backdrop. THIS is the live phone veil - the one to edit. Measured
   composite before: 0.630 at frame centre, 0.691 at the hull row, i.e. only 37%
   and 31% of the rendered ocean reaching the eye. Now 0.341 / 0.40, so roughly
   twice as much sea on a phone, and with the vignette above also cut the total
   drops from 0.630 to about 0.38 at centre. The single 39px h1 still measures
   4.0:1 against a full-strength foam crest, over the 3:1 large-text bar. */
@media(max-width:820px){
 #scene::after{background:
  linear-gradient(180deg,rgba(4,8,15,.04) 0%,rgba(4,8,15,.16) 45%,rgba(4,8,15,.34) 100%),
  radial-gradient(ellipse 76% 26% at 52% 22%,rgba(4,8,15,0) 0%,rgba(4,8,15,.06) 62%,rgba(4,8,15,.20) 100%)}
}

/* The footer was the last opaque block, so it drew a hard line across the
   bottom of an otherwise continuous scene. On the home page it becomes
   transparent too: the ocean runs from the top of the hero to the last line
   of the page.
   It carries a scrim rather than being fully transparent. The scene no longer
   stops and hides itself once the hero scrolls away, so the footer really does
   sit over live water now instead of over the flat page colour - and footer
   type is 11-12.5px, which is exactly the size the backdrop veils were cut for
   the h1's sake. This keeps the water moving through it at 14-38% while giving
   the small type a ground it can be read against. */
body.has-scene footer{border-top:none;background:transparent}

/* Push the footer to the bottom of the screen.
   The home page is short - one hero and a colophon - so on a tall or wide
   monitor the document ended before the viewport did and the footer floated in
   the middle of the ocean with more water below it. A flex column pins it down
   without giving it a background of its own. #scene, .progress and .skip are
   fixed/absolute so they stay out of this flow; only .nav, main and footer are
   in it. Scoped to the home page: the other fifteen all have enough content. */
body.has-scene{min-height:100svh;display:flex;flex-direction:column}
body.has-scene main{flex:1 0 auto}
body.has-scene footer{flex:0 0 auto}
@supports not (height:100svh){body.has-scene{min-height:100vh}}

/* The footer text sits directly on the water now that it carries no scrim of
   its own. #scene::after is a fixed layer whose gradient is darkest at the
   bottom of the VIEWPORT, which is exactly where the footer is once it is
   pinned - so the ground is there without a seam. These two greys were lifted
   to hold up over moving water rather than over the flat page colour. */
body.has-scene .foot-links a,
body.has-scene .foot-col p,
body.has-scene .foot-col a{color:#d3d5d6}
body.has-scene .foot-intro p{color:#b9bcbe}
body.has-scene .foot-bot,
body.has-scene .foot-legal a{color:#a3a6a8}

/* ==========================================================================
   Home hero when the scene is NOT running
   This is the state most phones actually get: no WebGPU adapter, reduced
   motion, save-data, or a low-memory device. The gate removes #scene but
   `has-scene` stays on <body>, so the page keeps its dark treatment with no
   ocean behind it - and the hero fell back to the stock scrim, which is
   rgba(19,24,31,.94) at the left because it was drawn for a photograph at 50%
   opacity on a white page. Composited, roughly 7% of the picture survived.
   That, not the scene, is the "too dark on mobile" the visitor sees.
   EXCEPTION TELEPHONE : voir le bloc html.is-phone en fin de fichier. Sur
   telephone la photographie est aussi affichee PENDANT scene-pending. Ce qui
   suit decrit la tablette et l ordinateur.
   Keyed on :not(.scene-pending): the photograph belongs to this path ONLY. If
   the scene is loading or running, scene-pending is set and none of this
   applies, so the picture can never flash up in front of the ocean.
   ========================================================================== */
body.has-scene:not(.scene-pending) .hero-bg img{opacity:.82}
/* La video ne prend les .82 qu une fois `canplay` emis ; avant cela elle reste
   transparente et laisse la photographie porter le heros seule, sinon les deux
   se composent (voir la note pres de .hero-bg video plus haut). */
body.has-scene:not(.scene-pending) .hero-bg.has-video video{opacity:.82}
body.has-scene:not(.scene-pending) .hero-bg:not(.has-video) video{opacity:0}
/* (0,4,2) so it still beats the rule above: once the video is playing the
   poster underneath must stay hidden or the two composite. */
body.has-scene:not(.scene-pending) .hero-bg.has-video img{opacity:0}

/* .68 at the start, not .62. Measured on the rendered page: at .62 the worst
   pixel behind the first line of the headline was 3.05:1, which passes the 3:1
   large-text bar by nothing at all - on a backdrop that is a playing video.
   .68 buys back margin at the left edge only, where the type is, and still
   shows several times more of the picture than the .94 this replaced. */
body.has-scene:not(.scene-pending) .hero-bg::after{
 background:linear-gradient(108deg,
  rgba(10,14,20,.68) 0%,rgba(10,14,20,.48) 48%,rgba(10,14,20,.26) 100%)}

/* In portrait the 108deg ramp runs out across the screen instead of down it,
   so its lightest stop lands on the right-hand side exactly where the h1 is
   full width. Measured 2.81:1 there. A vertical ramp puts the dark end under
   the type and still opens the top of the frame: worst-case bright pixel
   measures 4.27:1 against white, clearing the 3:1 bar for the 39px h1. */
@media(max-width:820px){
 body.has-scene:not(.scene-pending) .hero-bg::after{
  background:linear-gradient(180deg,
   rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%)}
}

/* Home-page footer labels. `body.has-scene h4{color:#fff}` is (0,1,2) and beats
   `.foot-col h4,.foot-links h4{color:var(--accentlt)}` at (0,1,1), so on this
   one page the group labels render pure white while the links under them are
   grey - the labels shouted louder than their own lists. Put back in their
   place explicitly. */
body.has-scene .foot-col h4,
body.has-scene .foot-links h4{color:#9fa3a7}

/* Headline legibility over a moving backdrop.
   Measured on the rendered page, background only, with the h1 hidden: the worst
   pixel behind the first line came out at 3.05:1 on desktop and 3.43:1 on a
   phone. That clears the 3:1 WCAG large-text bar the 68px/39px h1 is judged
   against, but with no margin - and the backdrop is a video or a live ocean, so
   a brighter frame can arrive at any moment.
   A shadow is the right tool rather than more scrim: it protects the glyphs
   where they actually are, and costs nothing anywhere else. Darkening the
   gradient again would just undo the brightness this pass was asked for. */
body.has-scene .hero h1{
 text-shadow:0 1px 2px rgba(4,8,15,.42), 0 2px 26px rgba(4,8,15,.55)}

/* ==========================================================================
   Phone footer: the declarations that have to come last
   Everything here is also declared earlier in the file, by the accessibility
   pass, at exactly the same specificity. Source order is the only thing that
   decides it, so these live at the end. Putting them back up in the <=760
   block silently reverts them.
   Row pitch is what WCAG 2.2 SC 2.5.8 actually constrains, not row height:
   18px rows with the 6px gap set above is a 24px pitch, which conforms. Drop
   either number and the other has to rise.
   ========================================================================== */
@media(max-width:760px){
 /* Les deux font-size qui etaient ici, 8,5px et 8px, ont ete retirees.
    Elles ne venaient PAS de la passe accessibilite, contrairement a ce que
    l en-tete de ce bloc laisse entendre : _backup-v3 montre un pied a 11px
    partout, sans exception telephone, et le 8,5px n apparait qu en v4. Or la
    passe accessibilite a ecrit dix lignes plus haut, en toutes lettres,
    « 11px and 10px stay legible at that tracking; do not go lower ». Placees
    ici, en fin de fichier et a specificite egale, ces deux lignes gagnaient
    par simple ordre de source et ramenaient le pied a 8,5px et 8px sur TOUT
    telephone - exactement le piege que l en-tete de ce bloc decrit, mais
    joue a l envers. Les tailles tactiles ci-dessous, elles, restent : ce sont
    bien celles de la passe accessibilite. */
 /* 20px + the 4px row-gap above = 24px pitch. This is the floor: any smaller
    and the footer links stop being reliably tappable, and SC 2.5.8 fails. */
 .foot-links a{min-height:20px}
 /* Les listes Metals et Navigation passent par l'exception d'espacement du
    critere 2.5.8 : 20px de haut + 4px d'interligne = un pas de 24px. Ces
    liens-ci n'ont pas d'interligne et se suivaient a 20px pile - mesure sur
    iPhone. Ils remontent donc a 24px pleins.
    min-height et non padding : box-sizing est border-box sur tout le site,
    le padding se logerait DANS les 20px sans deplacer la boite d'un pixel.
    La typographie ne bouge pas, seule la zone tactile grandit. */
 .foot-col a{min-height:24px}
 .foot-legal a{min-height:24px}
}

/* ==========================================================================
   Print, home page
   The @media print block near the top resets the footer to black on white, but
   every one of those selectors is a class lighter than the body.has-scene
   footer colours declared later in this file, and media queries add no
   specificity - so on index.html the footer printed light grey on white and
   the headline printed black on the #070b11 page colour. Both are restated
   here, after everything, where they actually win.
   ========================================================================== */
@media print{
 body.has-scene{background:#fff !important;color:#000}
 body.has-scene .hero,
 body.has-scene.scene-pending .hero,
 body.has-scene.scene-ready .hero{background:#fff !important}
 body.has-scene .hero h1{color:#000;text-shadow:none}
 body.has-scene footer{background:#fff !important;color:#000}
 body.has-scene .foot-col p,
 body.has-scene .foot-col a,
 body.has-scene .foot-links a,
 body.has-scene .foot-intro p,
 body.has-scene .foot-bot,
 body.has-scene .foot-legal a,
 body.has-scene .foot-col h4,
 body.has-scene .foot-links h4,
 body.has-scene .foot-brand .sb{color:#000}
 body.has-scene .foot-top{border-bottom-color:#ccc}
}

/* ==========================================================================
   "Discuss a transaction" - fond blanc, lettres encre, partout

   Le bouton etait plein noir (.nav-links > a.cta, ligne 786) sur les 15
   pages hors accueil. La page d'accueil avait deja la version claire, via
   body.has-scene, qui est plus specifique (0,4,1) et reste donc prioritaire :
   sur le fond 3D elle garde sa bordure blanche, sans cercle sombre.

   Ici la barre est blanche : un bouton blanc a bordure blanche serait
   invisible. La bordure passe donc a --ink, ce qui donne un bouton contour
   plutot qu'un aplat. Meme specificite que la regle de base (0,2,1) et
   place plus bas dans le fichier : c'est l'ordre source qui tranche.
   ========================================================================== */
.nav-links > a.cta{background:#fff;border-color:var(--ink);color:var(--ink)}
.nav-links > a.cta svg{stroke:var(--ink)}
.nav-links > a.cta:active{background:#e4e4e3;border-color:var(--ink);
 color:var(--ink);transform:translateY(1px)}
/* Sur ecran tactile :hover reste colle apres le tap : on le reserve au pointeur. */
@media(hover:hover) and (pointer:fine){
 .nav-links > a.cta:hover{background:#f1f1f0;border-color:var(--ink);color:var(--ink)}
 .nav-links > a.cta:hover svg{stroke:var(--ink)}
}

/* Les deux "Discuss a transaction" places dans le corps des pages
   (compliance.html, metals.html). Cible a.cta-solid et non .cta-solid :
   "Send enquiry" est un <button> qui envoie le formulaire de contact et
   reste plein, sinon il ne se distingue plus de rien. */
a.cta-solid{background:#fff;border-color:var(--ink);color:var(--ink)}
a.cta-solid svg{stroke:var(--ink)}
a.cta-solid:active{background:#e4e4e3;border-color:var(--ink);color:var(--ink)}
@media(hover:hover) and (pointer:fine){
 a.cta-solid:hover{background:#f1f1f0;border-color:var(--ink);color:var(--ink)}
 a.cta-solid:hover svg{stroke:var(--ink)}
}

/* ==========================================================================
   Voile d attente de la scene 3D (page d accueil uniquement)

   POURQUOI IL N Y A AUCUNE ANIMATION CONTINUE
   La premiere version balayait un reflet le long de la regle, en boucle. Cout
   mesure sur l arrivee de la premiere image de l ocean, a 4x de bridage
   processeur, 9 tirs par version en alternance :
       page temoin                      5542 ms
       copie identique du temoin        5608 ms   <- plancher de bruit, +66
       voile avec balayage continu      5920 ms   <- +378
   Le voile IMMOBILE, lui, coute zero. Le balayage disputait donc des images au
   fil qui prepare WebGPU pendant tout le telechargement. Retirer overflow
   hidden de la piste ramenait le cout sans le supprimer.
   La barre n avance donc plus que sur des JALONS REELS - adaptateur obtenu,
   module telecharge - deux transitions de 240 ms, soit une demi-seconde de
   mouvement au lieu de treize secondes. Et elle dit la verite au visiteur, ce
   qu un balayage decoratif ne faisait pas.
   La duree n est pas decorative non plus : le cout mesure suit le TEMPS PENDANT
   LEQUEL quelque chose bouge, pas le nombre de pixels. Mesure sur un vrai GPU
   (NVIDIA Turing), pas sur un rasteriseur logiciel.

   APPARITION instantanee : l etat visible est l etat INITIAL, et une
   transition ne se joue jamais sur le style de depart - rien ne fond a
   l entree, le voile est la des la premiere image, avec le fond bleu marine.
   DISPARITION : body.scene-ready arrive avec la premiere image peinte de
   l ocean ; le voile part en 240 ms pendant que la toile monte en 700 ms.

   HAUTEUR NULLE, debordement visible : le voile ne prend pas un pixel dans le
   flux. Ni son apparition ni sa disparition ne peuvent deplacer le titre, et
   sur les machines qui ne montrent jamais la scene il ne laisse aucun trou.
   Il est dans .hero-in, donc left:0 EST le bord gauche du titre a toutes les
   tailles : .hero .wrap est un element flex qui se retracte sur le titre, son
   bord ne peut pas etre recalcule de l exterieur.
   ========================================================================== */
.boot{position:relative;height:0;overflow:visible;z-index:5;pointer-events:none;
  opacity:0;visibility:hidden;
  transition:opacity 240ms ease, visibility 0s linear 240ms}
.boot-in{position:absolute;top:34px;left:0}
.boot-t{display:block;margin:0 0 13px;
  font:500 12px/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.66);
  text-shadow:0 1px 3px rgba(4,8,15,.8)}
.boot-r{display:block;position:relative;height:1px;width:min(260px,52vw);
  background:rgba(255,255,255,.17)}
/* scaleX et non width : une transition de largeur repasse par la mise en page
   a chaque image, une transformation non. Origine a gauche, valeur de depart
   dans la feuille - le premier etat ne doit rien attendre de JavaScript. */
.boot-r i{position:absolute;top:0;bottom:0;left:0;width:100%;
  transform-origin:0 50%;transform:scaleX(var(--boot-p,.06));
  background:rgba(255,255,255,.92);
  transition:transform 240ms cubic-bezier(.4,0,.2,1)}
/* DEUX conditions, et il faut les deux.
   is-booting : pose pendant l analyse de la tete, il garantit la premiere
     image. Sans WebGPU, en mouvement reduit ou en economie de donnees il n est
     jamais pose et rien n apparait, pas meme une image.
   scene-pending : la page attend encore la scene. Efface par l echeance douce
     de 2 s, par l abandon, et par la demolition de ocean-scene.js. C est lui
     qui empeche le voile de balayer par-dessus la photographie de repli, et
     de revenir apres coup si le peripherique WebGPU est perdu. */
html.is-booting body.scene-pending:not(.scene-ready) .boot{opacity:1;visibility:visible}
/* Ecran tres bas - telephone en paysage. Le titre lui-meme deborde deja du
   heros a cette hauteur : mesure a 844x390, sa derniere ligne finit sous la
   ligne de flottaison, et tout ce qu on place dessous est invisible. On ne
   montre donc rien plutot qu un voile que personne ne verra. */
@media (max-height:520px){.boot{display:none}}
@media (prefers-reduced-motion:reduce){.boot{display:none}}
@media print{.boot{display:none}}

/* ==========================================================================
   Verrou de defilement du panneau de navigation
   Pose et retire par site.js (setSheet). Sans lui, un doigt pose sur la feuille
   ouverte faisait defiler le DOCUMENT derriere elle sur iOS comme sur Android :
   on refermait le menu deux sections plus bas que la ou on l avait ouvert.
   overscroll-behavior:none complete overscroll-behavior:contain pose sur la
   feuille elle-meme : l un empeche la chaine de defilement de sortir de la
   liste, l autre empeche le rebond elastique de la page.
   Sur html ET sur body : selon le navigateur, l element qui defile est l un ou
   l autre. Ignore par les moteurs qui ne connaissent pas la propriete, ou
   overflow:hidden fait deja l essentiel du travail.
   ========================================================================== */
html.nav-open,html.nav-open body{overflow:hidden;overscroll-behavior:none}

/* ==========================================================================
   Telephone en PAYSAGE, largeur 821-1080 px
   Les regles telephone s arretent a max-width:820px, mais un iPhone 13 couche
   mesure 844 px de large, un 14/15 Pro Max 926 a 956, un Pixel 7 Pro 892. Ces
   appareils tombaient donc dans les regles de bureau : .hero garde son
   min-height:678px alors que le viewport ne fait que ~390 px de haut, et le
   titre - seul contenu de la page d accueil - finissait sous la ligne de
   flottaison. Le voile de flou plein ecran de la vignette restait actif lui
   aussi, sur exactement le materiel qui peut le moins se le permettre.
   Borne a max-width:1080px (bascule du menu burger) pour ne jamais toucher une
   fenetre de bureau volontairement basse, et a min-width:821px pour ne pas
   marcher sur le bloc telephone existant, qui est deja correct.
   ========================================================================== */
@media (max-height:600px) and (orientation:landscape) and (min-width:821px) and (max-width:1080px){
 /* min-height:0 et non auto : le mot-cle auto n a de sens que pour un element
    flex, et les moteurs anciens le jettent comme invalide - la declaration
    precedente (678px) reprendrait alors la main et le correctif ne servirait a
    rien. 0 est strictement equivalent ici et compris partout. */
 .hero{min-height:0}
 body.has-scene .hero,
 body.has-scene.scene-pending .hero{min-height:0;padding-bottom:0}
 .hero-in{padding-top:40px;padding-bottom:36px}
 #scene .webgl-vignette{backdrop-filter:none;-webkit-backdrop-filter:none}
}

/* ==========================================================================
   Ecran tres bas : le heros ne peut pas rester vide
   Le voile d attente est masque juste au-dessus (@media max-height:520px) parce
   qu il tomberait sous la ligne de flottaison. Mais scene-pending, lui, tient
   toujours la photographie a opacite 0 : le visiteur en paysage n avait donc ni
   voile, ni photographie, ni video - un rectangle #03101f nu pendant tout
   l amorcage. On lui rend la photographie.
   :not(.scene-ready) est OBLIGATOIRE : scene-pending reste pose pendant que la
   scene tourne (elle est reposee par rearm()), donc sans ce test ces deux
   regles recouvriraient l ocean d une photographie, definitivement.
   ========================================================================== */
@media (max-height:520px){
 body.has-scene.scene-pending:not(.scene-ready) .hero-bg img{opacity:.82}
 body.has-scene.scene-pending:not(.scene-ready) .hero-bg.has-video video{opacity:.82}
 body.has-scene.scene-pending:not(.scene-ready) .hero-bg::after{
  background:linear-gradient(180deg,
   rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%)}
}

/* ==========================================================================
   Plafond des 15 secondes : scene-slow
   Pose par le bloc de tete de index.html en meme temps qu il retire is-booting.
   A cet instant le voile "Loading the live scene" s eteint, mais scene-pending
   est toujours la sur le chemin de succes : le heros redevenait un rectangle
   #03101f vide, sans photographie, sans video et sans la moindre explication -
   et il le restait indefiniment. C est ce que le visiteur decrivait par "la
   video se charge encore et on ne voit pas la 3D".
   Cette classe rend la photographie SANS toucher a scene-pending : la scene
   peut donc toujours arriver apres coup et se fondre par-dessus. rearm() retire
   scene-slow au moment ou l ocean est monte.
   Doit rester A LA FIN du fichier : les regles qu elle doit battre
   (body.has-scene.scene-pending .hero-bg img, et les voiles de contraste) sont
   a specificite egale ou proche, donc c est l ordre source qui tranche.
   ========================================================================== */
body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg img{opacity:.82}
body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg.has-video video{opacity:.82}
body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg.has-video img{opacity:0}
body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg::after{
 background:linear-gradient(108deg,
  rgba(10,14,20,.68) 0%,rgba(10,14,20,.48) 48%,rgba(10,14,20,.26) 100%)}
@media(max-width:820px){
 body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg::after{
  background:linear-gradient(180deg,
   rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%)}
}

/* ==========================================================================
   Telephone : la photographie porte l attente, puis se fond dans l ocean
   Pose par le bloc de tete de index.html (html.is-phone).

   Sur ordinateur, scene-pending masque la photographie pour eviter un
   echange photo -> ocean : la scene arrive en une seconde, on prefere le
   fond de #scene. Sur telephone c est le mauvais arbitrage - il y a ~1,37 Mo
   a transferer, donc plusieurs secondes de rectangle #03101f nu avec un
   titre dessus, ce qui est exactement ce que le visiteur decrivait.

   Ici la photographie du port reste donc visible pendant tout le chargement,
   sous le voile de progression, et s efface en 700 ms quand l ocean est monte.
   Le mecanisme est entierement dans le :not(.scene-ready) : des que
   ocean-scene.js pose scene-ready, ces regles cessent de matcher et la regle
   de base (opacite 0) reprend la main - avec la transition de 700 ms deja
   declaree ligne 940. Aucune ligne de JavaScript n est necessaire.

   Specificite (0,5,3) contre (0,3,2) pour la regle de base : elle gagne par
   specificite, pas seulement par ordre source.
   ========================================================================== */
html.is-phone body.has-scene.scene-pending:not(.scene-ready) .hero-bg img{opacity:.82}
html.is-phone body.has-scene.scene-pending:not(.scene-ready) .hero-bg.has-video video{opacity:.82}
/* Le voile de contraste doit revenir avec elle : sans lui le titre blanc passe
   sous 3:1 sur les cretes claires de la photographie. Memes valeurs que le
   ramp portrait mesure pour le chemin sans scene. */
/* PILOTE EN OPACITE, pas en background.
   `background:none` (la regle scene-pending plus haut) n est pas interpolable
   depuis un degrade, et .hero-bg::after ne porte aucune transition dans tout le
   fichier : le voile disparaissait donc en UNE image a l arrivee de
   scene-ready, alors que la photographie, elle, met 700 ms a s effacer. Entre
   les deux, le titre blanc se retrouvait a 1,49:1 sur la photographie encore
   presque opaque - environ 170 ms sous la barre des 3:1, precedes d un flash de
   luminosite. En opacite, le voile part au meme rythme que la photographie
   qu il protege et que la toile qui arrive. */
html.is-phone body.has-scene.scene-pending .hero-bg::after{
 background:linear-gradient(180deg,
  rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%);
 opacity:1;transition:opacity 700ms ease}
html.is-phone body.has-scene.scene-pending.scene-ready .hero-bg::after{opacity:0}
/* Le bloc scene-slow de la fin du fichier est en (0,5,2) et primait la regle
   telephone ci-dessus, en (0,4,3) : des que scene-slow etait pose - c est-a-dire
   pendant toute attente longue et pendant tout remontage apres perte du
   peripherique - le telephone reprenait le voile en rampe 108deg, calibre pour
   le PAYSAGE, sur un ecran en portrait. Cette regle-ci est en (0,6,3) : elle
   gagne sur les deux, dans les deux orientations, quel que soit l ordre source.
   Seul `background` est redeclare : l opacite et la transition restent celles
   de la regle ci-dessus. */
html.is-phone body.has-scene.scene-slow.scene-pending:not(.scene-ready) .hero-bg::after{
 background:linear-gradient(180deg,
  rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%)}
/* La photographie est dans .hero, pas dans #scene : le heros doit donc
   redevenir opaque le temps qu elle porte l ecran, sinon la couleur de #scene
   transparait sur ses bords pendant le decodage. */
html.is-phone body.has-scene.scene-pending:not(.scene-ready) .hero{background:var(--ink)}

/* ==========================================================================
   Telephone : pas de flou plein ecran sur la vignette
   Le bloc @media(max-width:820px) plus haut annule deja backdrop-filter, mais
   il raisonne en LARGEUR : un Galaxy Z Fold deplie (674x841, donc un telephone)
   passe a 841 px de large en paysage et retrouve le flou de 23 px sur toute la
   surface - la passe la plus couteuse de la scene, sur du materiel mobile.
   html.is-phone est pose a partir de `screen`, avec exactement le seuil de
   pickTier : il ne bascule donc pas a la rotation, et il ne touche aucune
   tablette. Placee en fin de fichier, cette regle gagne par l ordre source sur
   la declaration d origine, qui est a specificite egale.
   ========================================================================== */
html.is-phone #scene .webgl-vignette{backdrop-filter:none;-webkit-backdrop-filter:none}

/* ==========================================================================
   Telephone en PAYSAGE : les reglages mobiles etaient claves sur la LARGEUR
   Les deux blocs @media(max-width:820px) plus haut - le fond de scene allege
   et la rampe verticale du voile du heros - ne voient jamais un telephone
   couche : un iPhone 13 fait 844 px de large dans ce sens, un 17 Pro Max 956.
   Le visiteur y recevait donc les valeurs calibrees pour un ecran de bureau :
   ocean nettement plus sombre qu en portrait sur le MEME appareil, et rampe
   108deg dont le bord clair tombe exactement la ou le titre est pleine largeur.
   html.is-phone est pose a partir de `screen`, avec le meme seuil que
   pickTier : il ne bascule pas a la rotation. Placees en fin de fichier, ces
   regles gagnent par l ordre source sur les declarations d origine, qui sont a
   specificite egale ou inferieure.
   ========================================================================== */
html.is-phone #scene::after{background:
 linear-gradient(180deg,rgba(4,8,15,.04) 0%,rgba(4,8,15,.16) 45%,rgba(4,8,15,.34) 100%),
 radial-gradient(ellipse 76% 26% at 52% 22%,rgba(4,8,15,0) 0%,rgba(4,8,15,.06) 62%,rgba(4,8,15,.20) 100%)}
html.is-phone body.has-scene:not(.scene-pending) .hero-bg::after{
 background:linear-gradient(180deg,
  rgba(10,14,20,.30) 0%,rgba(10,14,20,.46) 42%,rgba(10,14,20,.66) 100%)}

/* ==========================================================================
   Le fondu du voile, pour TABLETTE ET ORDINATEUR aussi
   Le bloc html.is-phone ci-dessus pilote le voile en opacite et le fait
   disparaitre en 700 ms, en phase avec la photographie. Hors telephone, rien
   ne le faisait : des que scene-ready arrivait, la regle
   `body.has-scene.scene-pending .hero-bg::after{background:none}` reprenait la
   main en UNE image, alors que la photographie ou la video, elle, met bien
   700 ms a s effacer. Le voile partait donc d un coup au-dessus d une image
   encore presque opaque - saut de luminosite, et titre blanc momentanement
   sous le seuil de contraste.
   Chemins reellement concernes : retour arriere depuis le cache, remontage
   apres perte du peripherique WebGPU, et toute arrivee de la scene apres que
   l echeance douce a decouvert la photographie.
   ========================================================================== */
/* Le degrade doit rester DECLARE dans les deux etats, sinon rien ne se fond :
   `body.has-scene.scene-pending .hero-bg::after{background:none}` plus haut
   gagne, l opacite s anime sur une boite deja transparente, et le voile part
   toujours en une image. Memes valeurs que les autres voiles du fichier, donc
   aucun saut de couleur : seule l opacite bouge. */
body.has-scene.scene-pending:not(.scene-ready) .hero-bg::after{
 background:linear-gradient(108deg,
  rgba(10,14,20,.68) 0%,rgba(10,14,20,.48) 48%,rgba(10,14,20,.26) 100%);
 opacity:1;transition:opacity 700ms ease}
body.has-scene.scene-pending.scene-ready .hero-bg::after{
 background:linear-gradient(108deg,
  rgba(10,14,20,.68) 0%,rgba(10,14,20,.48) 48%,rgba(10,14,20,.26) 100%);
 opacity:0;transition:opacity 700ms ease}

/* ==========================================================================
   Telephone en PAYSAGE : la vignette aussi
   Le bloc @media(max-width:820px) plus haut retire le masque plein ecran de la
   vignette et allege ses degrades. Comme les deux autres reglages mobiles, il
   raisonne en LARGEUR : un iPhone couche fait 844 a 956 px, un Z Fold deplie
   841. Ces appareils gardaient donc le masque radial et les valeurs de bureau -
   ocean nettement plus sombre et coque assombrie par le masque, sur exactement
   le materiel qui a le moins de surface pour la montrer.
   Memes valeurs qu au bloc 820px, a la virgule pres : rien de nouveau n est
   invente ici, on etend seulement la portee au bon ensemble d appareils.
   html.is-phone est calcule sur `screen` et ne bascule pas a la rotation.
   Specificite (1,3,1) contre (1,2,1) pour la regle de reference : elle gagne
   par specificite, pas seulement par ordre source.
   ========================================================================== */
html.is-phone body.has-scene #scene .webgl-vignette{
 -webkit-mask-image:none;mask-image:none;
 background:
  linear-gradient(180deg,rgba(4,9,17,.06) 0%,rgba(4,9,17,.16) 38%,rgba(4,9,17,.30) 100%),
  radial-gradient(ellipse 74% 30% at 52% 24%,rgba(4,9,17,0) 0%,rgba(4,9,17,.10) 62%,rgba(4,9,17,.24) 100%)}


/* ==========================================================================
   Telephone en portrait : le titre remonte pour degager la coque
   Le heros est un flex avec align-items:center, et sur telephone son contenu
   se reduit au seul <h1> : le bloc se retrouvait donc centre verticalement,
   titre de 450 a 570 px sur un iPhone 13, avec 371 px de vide au-dessus.
   Mesure de la coque au meme moment : ~32 % de la hauteur d ecran, centree a
   624 px, donc etalee de 489 a 759 px. Son tiers superieur passait derriere le
   titre, et seule sa partie basse restait lisible - d ou l impression que le
   navire "apparait en bas".
   On ne touche PAS au solveur de cadrage : PORTRAIT_SHIP_FRAC reste a 0.74.
   Monter le navire l aurait enfonce davantage derriere le texte, donc rendu
   MOINS visible, l inverse de ce qui est demande. C est le titre qui liberait
   la place. Il passe en haut du heros, la coque se degage entierement.
   Portrait seulement : en paysage la composition est celle du bureau et le
   titre partage la largeur avec la coque, il ne doit pas bouger.
   ========================================================================== */
@media(max-width:820px) and (orientation:portrait){
 body.has-scene .hero{align-items:flex-start}
 body.has-scene .hero-in{padding-top:92px}
}
