Nom | URL | HEAD | BODY | CSS |
|---|---|---|---|---|
BASE | <link rel="stylesheet" href="https://sites.super.so/snippets/lightbox.css"/> <link href="https://evenbloom.github.io/Visu/public/css/main.css" rel="stylesheet"/> <link rel="stylesheet" href="https://sites.super.so/snippets/v2/carousel.css"> | <script src="https://sites.super.so/snippets/v2/carousel.js"></script> <script src="https://sites.super.so/snippets/v2/lightbox.js"></script> <script> (function(){ const HOME_URL = "https://sebastien-wierinck-workshop.super.site/works/"; const SCROLL_TRIGGER = 400; // px avant d'afficher les boutons function isHome(){ return location.pathname === "/" || location.pathname === ""; // adapte si ta home est ailleurs : // return location.pathname.startsWith("/works/"); } function ensureTriangleButtons(){ if(!document.querySelector('.sw-back-triangle')){ const back = document.createElement('button'); back.className = 'sw-tri-btn sw-back-triangle'; back.setAttribute('aria-label','Retour'); back.title = 'Retour'; back.addEventListener('click', ()=>{ const ref = document.referrer || ""; const sameHost = ref.startsWith(location.origin); if (sameHost && history.length > 1) history.back(); else location.href = HOME_URL; }); document.body.appendChild(back); } if(!document.querySelector('.sw-top-triangle')){ const top = document.createElement('button'); top.className = 'sw-tri-btn sw-top-triangle'; top.setAttribute('aria-label','Haut de page'); top.title = 'Haut de page'; top.addEventListener('click', ()=>{ window.scrollTo({ top: 0, behavior: 'smooth' }); }); document.body.appendChild(top); } } function toggleButtons(){ const buttons = document.querySelectorAll('.sw-tri-btn'); if(window.scrollY > SCROLL_TRIGGER){ buttons.forEach(b => b.classList.add('visible')); } else { buttons.forEach(b => b.classList.remove('visible')); } } function init(){ // si tu gardais l'ancien bouton .sw-back, on le retire document.querySelector('.sw-back')?.remove(); if (isHome()) document.body.classList.add('is-home'); else document.body.classList.remove('is-home'); ensureTriangleButtons(); toggleButtons(); } (document.readyState === 'loading') ? document.addEventListener('DOMContentLoaded', init) : init(); window.addEventListener('scroll', toggleButtons); // Super peut réinjecter du DOM → observer et redéclencher const obs = new MutationObserver((muts)=>{ if ([...muts].some(m=>m.addedNodes && m.addedNodes.length)){ clearTimeout(window.__sw_tri_deb); window.__sw_tri_deb = setTimeout(init,120); } }); obs.observe(document.documentElement, { childList:true, subtree:true }); })(); </script> <script> /* Réorganisation sémantique des pages projet (global) / (function(){ const isProjectPage = () => document.querySelector(".notion-page__properties-layout"); // normalise du texte (pour matcher 'Type' / 'Material' / 'Matière'…) const norm = (s) => (s||"") .normalize("NFD").replace(/[\u0300-\u036f]/g,"") .toLowerCase().trim(); function buildProjectHeader(){ const article = document.querySelector("article.notion-root"); if (!article || article.classList.contains("project-upgraded")) return; const propsLayout = article.querySelector(".notion-page__properties-layout"); if (!propsLayout) return; // pas une fiche projet // Liste des propriétés visibles en haut de page const props = Array.from(propsLayout.querySelectorAll(".notion-page__property")); if (!props.length) return; // Trouver Type et Matière par leur label const byLabel = (label) => props.find(p => norm(p.querySelector(".notion-page__property-name")?.textContent) === norm(label)); const typeProp = byLabel("type") || props[0]; const materialProp = byLabel("material") || byLabel("matiere") || byLabel("materiau") || props[1] || props[0]; // Description (bloc de texte natif juste sous les propriétés) const descEl = article.querySelector(".notion-property.notion-property__text.notion-semantic-string") || article.querySelector(".notion-property.notion-semantic-string") || null; // 1. Vrai titre Notion (heading de la page) let titleText = (article.querySelector(".notion-header__title .notion-semantic-string")?.textContent || "").trim(); // 2. Si pas trouvé → fallback, mais on évite meta:title if(!titleText){ titleText = article.querySelector("h1")?.textContent?.trim() || document.querySelector('meta[property="og:title"]')?.content?.trim() || document.title.replace(/\s[–|-]\s*[^–|-]+$/,"").trim() || decodeURIComponent(location.pathname.split("/").filter(Boolean).pop() || "").replace(/[-_]+/g," "); } // Construire le header const header = document.createElement("header"); header.className = "project-header"; const h3 = document.createElement("h3"); h3.className = "project-title"; h3.textContent = titleText; header.appendChild(h3); const meta = document.createElement("div"); meta.className = "project-meta"; meta.appendChild(typeProp.cloneNode(true)); meta.appendChild(materialProp.cloneNode(true)); header.appendChild(meta); if (descEl){ const descClone = descEl.cloneNode(true); descClone.classList.add("project-desc"); header.appendChild(descClone); } // Injecter le header avant la zone des propriétés propsLayout.parentNode.insertBefore(header, propsLayout); // Masquer les originaux pour éviter les doublons propsLayout.style.display = "none"; if (descEl) descEl.style.display = "none"; // Marqueur pour ne pas rerunner inutilement article.classList.add("project-upgraded"); } // Lancer quand le DOM est prêt + si Super ré-injecte le contenu const start = () => { if (isProjectPage()) buildProjectHeader(); }; (document.readyState === "loading") ? document.addEventListener("DOMContentLoaded", start) : start(); const mo = new MutationObserver(() => start()); mo.observe(document.documentElement, {childList:true, subtree:true}); })(); </script> <script> (function () { // Liste officielle des catégories de séries et leur URL const SERIES_MAP = { 'All': '/series/all', 'OnSite': '/series/onsite', 'Panels': '/series/panels', 'Public': '/series/public-furniture', 'CraftLab': '/series/craftlab', 'Proposal': '/series/proposals', 'Proposals': '/series/proposals', 'R&D': '/series/r-d', 'Explorations': '/series/explorations' }; // Normalise un chemin pour éviter les / en trop function normalizePath(path) { return path.replace(/\/+$/, ''); } const currentPath = normalizePath(location.pathname); // Parcourt tous les .notion-pill du site document.querySelectorAll('.notion-pill').forEach(function (pill) { const label = pill.textContent.trim(); // On ne s'occupe que des labels présents dans SERIES_MAP if (!SERIES_MAP[label]) return; const url = SERIES_MAP[label]; const targetPath = normalizePath(url); // Ajoute une classe d'identification pill.classList.add('sw-series-pill'); pill.style.cursor = 'pointer'; pill.setAttribute('role', 'button'); pill.setAttribute('tabindex', '0'); // État actif si on est sur la page correspondante if (targetPath === currentPath) { pill.classList.add('is-active'); } // Fonction de navigation function go() { window.location.href = url; } // Click souris pill.addEventListener('click', function (e) { e.preventDefault(); go(); }); // Navigation clavier (Enter ou Espace) pill.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); go(); } }); }); })(); </script> <script> window.addEventListener('load', ()=>{ ['https://swws.net/series/all','https://swws.net/series/onsite'].forEach(url=>{ const link = document.createElement('link'); link.rel = 'prefetch'; link.href = url; document.head.appendChild(link); }); }); </script> | /* ===== Triangles minimalistes (monochrome) — scope SW ===== / :root{ / zone cliquable (cercle invisible) : au moins 44px / --sw-hit-size: 50px; / taille des triangles / --sw-tri-left-w: 24px; / largeur base triangle gauche / --sw-tri-left-h: 24px; / hauteur triangle gauche / --sw-tri-up-w: 24px; / largeur base triangle haut / --sw-tri-up-h: 24px; / hauteur triangle haut / / espaces au bord / --sw-gap: 16px; / couleur : on utilise currentColor (hérite du thème) / --sw-fg: currentColor; / opacité légère au repos (facultatif) / --sw-rest: .85; } @media (max-width: 768px){ :root{ --sw-hit-size: 46px; --sw-gap: 12px; } } / Bouton générique (cercle invisible) / .sw-tri-btn{ position: fixed; inline-size: var(--sw-hit-size); block-size: var(--sw-hit-size); border-radius: 999px; / hit-area circulaire / background: transparent; / invisible / color: var(--sw-fg); z-index: 9999; cursor: pointer; / caché par défaut : visible uniquement après scroll / opacity: 0; pointer-events: none; transition: opacity .25s ease, transform .15s ease; } / rendu focus clavier (a11y) / .sw-tri-btn:focus-visible{ outline: 2px solid currentColor; outline-offset: 2px; } / état visible (ajouté par JS au delà du seuil de scroll) / .sw-tri-btn.visible{ opacity: var(--sw-rest); pointer-events: auto; } @media (hover:hover){ .sw-tri-btn.visible:hover{ opacity: 1; transform: scale(1.02); } } .sw-tri-btn:active{ transform: scale(.98); } / respecte prefers-reduced-motion / @media (prefers-reduced-motion: reduce){ .sw-tri-btn{ transition: opacity .01s linear; } .sw-tri-btn:active{ transform: none; } } / ----- Triangle RETOUR (bas-gauche) : petit triangle ◄ ----- / .sw-back-triangle{ left: var(--sw-gap); bottom: var(--sw-gap); display: grid; place-items: center; } .sw-back-triangle::before{ content:""; display:block; / triangle via bordures (monochrome) / border-top: calc(var(--sw-tri-left-h)/2) solid transparent; border-bottom: calc(var(--sw-tri-left-h)/2) solid transparent; border-right: var(--sw-tri-left-w) solid currentColor; } / ----- Triangle TOP (bas-droite) : petit triangle ▲ ----- / .sw-top-triangle{ right: var(--sw-gap); bottom: var(--sw-gap); display: grid; place-items: center; } .sw-top-triangle::before{ content:""; display:block; border-left: calc(var(--sw-tri-up-w)/2) solid transparent; border-right: calc(var(--sw-tri-up-w)/2) solid transparent; border-bottom: var(--sw-tri-up-h) solid currentColor; } / Option : masquer le bouton "retour" sur la home / body.is-home .sw-back-triangle{ display: none !important; } / ==== Lightbox overlay (force overlay plein écran) ==== / #lightbox-overlay{ position: fixed !important; / clé: sortir du flux / inset: 0 !important; / top:0; right:0; bottom:0; left:0 / z-index: 100000 !important; / au-dessus de tout (triangles, header, etc.) / display: none; / caché par défaut / align-items: center; justify-content: center; background: rgba(0,0,0,.85); / fond sombre / padding: clamp(8px, 4vw, 40px); } / l'init de ton script met "display:flex" -> on accepte les 2 variantes / #lightbox-overlay[style="display: flex"], #lightbox-overlay.open{ display: flex !important; } #lightbox-image{ max-width: min(96vw, 2400px); max-height: 90vh; object-fit: contain; box-shadow: 0 10px 40px rgba(0,0,0,.5); border-radius: 6px; } /* bouton fermer / #lightbox-close{ position: absolute; top: 12px; right: 12px; width: 44px; height: 44px; border-radius: 999px; background: rgba(255,255,255,.9); border: 1px solid rgba(0,0,0,.08); display: grid; place-items: center; cursor: pointer; z-index: 100001; / au-dessus de l'image / } / empêcher le scroll de la page si le lightbox est ouvert (optionnel) / body.lightbox-open { overflow: hidden; } / ce qui marche jusqu ici grader tout / / === Works — grille stable (gauche fixe, droite fluide) === / @media (min-width:1024px){ / Colonne gauche fixe (280px) + colonne droite qui prend tout le reste / .page__works .notion-collection__header-wrapper{ display:grid !important; grid-template-columns: 280px minmax(0, 1fr) !important; gap:28px; align-items:start; } / Menu filtres = colonne 1, sticky, pas de scroll horizontal / .page__works .notion-dropdown__menu-wrapper{ grid-column:1 !important; width:280px !important; position:sticky; top:96px; max-height:calc(100vh - 120px); overflow-y:auto; overflow-x:hidden; padding-right:4px; } / Galerie (ALL + autres vues) = colonne 2, pleine largeur / .page__works .notion-collection__header-wrapper > .notion-collection-gallery, .page__works .notion-collection__header-wrapper > .notion-collection-gallery.small, .page__works .notion-collection__header-wrapper > .notion-collection-gallery.large{ grid-column:2 !important; width:100% !important; max-width:none !important; flex:1 1 auto !important; / neutralise tout 50% résiduel / min-width:0 !important; } / Sécurité : les enfants de la grille peuvent rétrécir */ .page__works .notion-collection__header-wrapper > { min-width:0; } } / === Works — pills + actif jaune (robuste <a>/<button>/<span>) === */ .page__works .notion-dropdown__option, .page__works .notion-dropdown__option { text-decoration:none !important; } .page__works .notion-dropdown__option{ display:inline-block; margin:0 0 10px 0; border:0; box-shadow:none; } .page__works .notion-dropdown__option > a, .page__works .notion-dropdown__option > button, .page__works .notion-dropdown__option > span, .page__works .notion-dropdown__option{ / fallback */ padding:8px 14px; border:1px solid var(--color-border,#dcdcdc); border-radius:9999px; background:transparent; line-height:1.2; transition:background-color .15s ease, border-color .15s ease, color .15s ease; } .page__works .notion-dropdown__option:hover, .page__works .notion-dropdown__option:hover > a, .page__works .notion-dropdown__option:hover > button, .page__works .notion-dropdown__option:hover > span{ background:rgba(255,237,207,.20); border-color:rgba(255,237,207,.60); } .page__works .notion-dropdown__option.active, .page__works .notion-dropdown__option.is-active, .page__works .notion-dropdown__option[aria-selected="true"], .page__works .notion-dropdown__option.active > *, .page__works .notion-dropdown__option.is-active > *, .page__works .notion-dropdown__option[aria-selected="true"] > { background:#FEEDCF !important; border-color:#FEEDCF !important; color:#1b1b1b !important; font-weight:600; } / Works — pills carrées (angles à 90°) / .page__works .notion-dropdown__option > a, .page__works .notion-dropdown__option > button, .page__works .notion-dropdown__option > span, .page__works .notion-dropdown__option{ / fallback si pas d'enfant direct / border-radius: 0 !important; / angles vifs / } / (optionnel) focus clavier net sur angle vif / .page__works .notion-dropdown__option:focus-visible, .page__works .notion-dropdown__option > a:focus-visible, .page__works .notion-dropdown__option > button:focus-visible, .page__works .notion-dropdown__option > span:focus-visible{ outline: 2px solid #1b1b1b; outline-offset: 2px; } / H1/h2 Notion / .notion-header__title, .notion-heading .notion-semantic-string{ font-weight:800; line-height:1.05; letter-spacing:-.012em; font-size: clamp(28px, 4.2vw, 42px); } / Paragraphe intro plus calme / .notion-text{ font-size: clamp(16px, 2.2vw, 18px); color:var(--fg); } / --- Header projet (sobre, garde les styles natifs des propriétés) --- / .project-header { margin: 24px 0 32px; } .project-header .project-title { / taille raisonnable, responsive, sans toucher à la typo du thème / font-size: clamp(3rem, 2.2vw, 1.6rem); font-weight: 600; margin: 0 0 12px; } / Ligne 2 : deux colonnes 50/50 (Type / Matière) / .project-header .project-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; margin: 0 0 12px; } / Ligne 3 : description (on garde la classe native clonée) / .project-header .project-desc { margin-top: 4px; } / Mobile : empiler Type et Matière / @media (max-width: 720px){ .project-header .project-meta { grid-template-columns: 1fr; } } / ===== Fiche projet — alignements fins ===== / / 2 colonnes (Type / Material) avec alignement haut / .project-header .project-meta{ display: grid; grid-template-columns: 1fr 1fr; gap: 18px 28px; / ligne / colonne / align-items: start; / top-aligned / margin: 6px 0 14px; } / Chaque propriété (label + valeurs) sur une seule ligne / .project-header .project-meta > .notion-page__property{ display: flex; align-items: flex-start; / top-aligned entre label et pills / gap: 10px; margin: 0; } / Neutralise la “colonne label” de Notion dans le header / .project-header .project-meta .notion-page__property-name-wrapper{ width: auto !important; min-width: 0 !important; margin: 0 !important; padding: 0 !important; flex: 0 0 auto; } / Label (Type / Material) sobre et calé / .project-header .project-meta .notion-page__property-name{ font-size: .92em; line-height: 1.3; color: #666; margin: 0; } / Valeurs (pills), sans marges parasites + wrap propre / .project-header .project-meta .notion-property{ margin: 0 !important; } .project-header .project-meta .notion-select, .project-header .project-meta .notion-multi_select{ margin: 0; } .project-header .project-meta .notion-pill{ margin: 0 8px 8px 0; } / Mobile : empile Type / Material / @media (max-width: 760px){ .project-header .project-meta{ grid-template-columns: 1fr; } } / --- Harmoniser les titres de projet avec les H2 --- / .project-title { font-family: "Space Grotesk", system-ui, -apple-system, Segoe UI, Roboto, sans-serif; font-weight: 600; / même graisse que les headings / line-height: 1.15; letter-spacing: 0; color: var(--text-color, #222); text-transform: none; margin: 0 0 0.6em 0; / Taille fluide cohérente avec H2 / font-size: clamp(1.75rem, 3.5vw, 2.25rem); } / Option : resserrer un peu sur mobile / @media (max-width: 768px) { .project-title { font-size: 1.6rem; } } / === SWWS — Titres des cartes Notion : fond blanc + hover jaune ============ / .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background: ##eee; / fond / color: #000; / texte / padding: 4px 12px; display: inline-block; border-radius: 0px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; } / OnSite — pills / / --- Effets hover & actif unifiés pour les pills --- / / Hover : fond noir, texte beige clair / .notion-pill:hover { background-color: #000000 !important; color: #feedcf !important; border-color: #000000 !important; transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; } / Actif (catégorie courante ou clic JS) */ .notion-pill.is-active, .notion-pill.sw-series-pill.is-active { background-color: #000000 !important; color: #feedcf !important; border-color: #000000 !important; } | |
HOME | ||||
TEMPLATE | sites.super.so |
| ||
HOMEPAGE | <!-- === SWWS Landing Hero — HTML only =================== -->
<section id="swws-hero" class="swws-hero" aria-label="Sebastien Wierinck WorkShop — Hero">
<!-- Calques du diaporama (fond) -->
<div class="swws-bg-2"></div>
<div class="swws-bg-3"></div>
<div class="swws-bg-4"></div>
<!-- Contenu principal -->
<div class="swws-hero__content">
<span class="swws-eyebrow">
<span class="swws-dot"></span>
Sebastien Wierinck WorkShop
</span>
<h2 class="swws-h2">
<span>A design practice</span>
<span>at the intersection of</span>
<span>furniture, public art,</span>
<span>and digital craft.</span>
</h2>
<p class="swws-contact">
</p>
<a class="swws-cta" id="sw-mail-link" title="Send us an email">
Contact us
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 4h16v16H4z" stroke="currentColor" stroke-width="2" fill="none"/>
<path d="M4 4l8 7 8-7" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</a>
</div>
<button class="swws-scroll-indicator" aria-label="Scroll to content">
<svg viewBox="0 0 24 24" width="28" height="28" stroke="currentColor" fill="none" stroke-width="2">
<path d="M6 9l6 6 6-6"/>
</svg>
</button>
<script>
// --- EMAIL PROTECTION ---
const mailName = "sw";
const mailDomain = "swws.net";
const mailLink = document.getElementById("sw-mail-link");
mailLink.href = | /* === SWWS Landing Hero — Styles =================== / @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap'); .swws-hero, .swws-hero * { box-sizing: border-box; } .swws-hero { position: relative; height: 100dvh; width: 100%; isolation: isolate; overflow: clip; display: grid; place-items: center; color: #fff; text-align: center; background: #000; font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif; } / === Fond diaporama === / .swws-hero::before, .swws-hero::after, .swws-bg-2, .swws-bg-3, .swws-bg-4 { content: ""; position: absolute; inset: 0; background-size: cover; background-position: center; filter: brightness(0.65) saturate(130%); animation: fadeSlideshow 25s infinite both; animation-timing-function: ease-in-out; opacity: 0; z-index: 0; pointer-events: none; will-change: opacity; } / === Images du diaporama (5 images, 25s total) === / .swws-hero::before { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/775095d7-97ff-423c-8787-04648236bdb6/005/w=3840,quality=90,fit=scale-down'); animation-delay: 0s; } .swws-hero::after { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/e00f1546-30d8-444d-a663-cb1d9946d1b6/Buffet-Enfilade-SebastienWierinckSebastienNormand061/w=3840,quality=90,fit=scale-down'); animation-delay: 5s; } .swws-bg-2 { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/335a8dc2-1eb5-4821-a21d-e2c8f9fdaec8/WORMS-SWWSSbastienNormand012_WEB/w=3840,quality=90,fit=scale-down'); animation-delay: 10s; } .swws-bg-3 { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/f6a0da9d-d7c7-41c3-b17a-c9ea5bf66fec/CD104-02/w=1920,quality=90,fit=scale-down'); animation-delay: 15s; } .swws-bg-4 { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/29cd6995-4e66-4d1b-8201-cd78b7abdfdf/J1-OS015-001c/w=1920,quality=90,fit=scale-down'); animation-delay: 20s; } / === Animation du diaporama avec chevauchement doux === / @keyframes fadeSlideshow { 0% { opacity: 0; } 2% { opacity: 1; } / fade-in plus tôt / 24% { opacity: 1; } / reste visible plus longtemps / 28% { opacity: 0; } / fade-out progressif / 100% { opacity: 0; } } / === Version mobile : changer une image (ex. slide 3) === / @media (max-width: 720px), (max-aspect-ratio: 3/4) { .swws-hero::after { background-image: url('https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/9287334a-a8a7-4177-9d78-f8666b50dc5a/DRAPED_CONSOLE_prototype_Sebastien-Wierinck-24/w=1080,quality=90,fit=scale-down'); background-position: center top; } } / === Contenu === / .swws-hero__content { position: relative; z-index: 5; padding: 2rem 1rem; max-width: min(900px, 90vw); } .swws-eyebrow { display: inline-flex; align-items: center; gap: .6rem; padding: .4rem .7rem; border-radius: 999px; background: rgba(255,255,255,.12); backdrop-filter: blur(8px); font-weight: 600; font-size: 18px; letter-spacing: .08em; text-transform: uppercase; } .swws-dot { width:.5rem; aspect-ratio:1; border-radius:50%; background:#FFFF00; box-shadow:0 0 .5rem #FFFF00; } .swws-h2 { margin: 1rem 0 .6rem; font-weight: 700; font-size: clamp(32px, 6vw, 72px); line-height: 1.05; letter-spacing: -0.015em; } .swws-h3 { margin: .5rem 0 1.5rem; font-weight: 400; font-size: clamp(20px, 2.5vw, 28px); line-height: 1.4; opacity: .92; } .swws-contact { font-weight: 400; font-size: 16px; line-height: 1.7; color: #fff; opacity: 0.9; margin-bottom: 2rem; } .swws-contact a { color: #fff; text-decoration: underline; text-underline-offset: 3px; transition: color .2s ease; } .swws-contact a:hover { color: #feedcf; } / === Bouton jaune === / .swws-cta { display: inline-flex; align-items: center; gap: .6rem; padding: .9rem 1.4rem; border-radius: 0px; color: #111; background: rgba(254,237,207,0.9); border: 1px solid rgba(255,255,0,.35); text-decoration: none; font-weight: 600; font-size: 15px; box-shadow: 0 10px 30px rgba(0,0,0,.25); transition: transform .2s ease, box-shadow .2s ease, background .2s ease, color .2s ease; } .swws-cta:hover { transform: translateY(-2px); box-shadow: 0 14px 40px rgba(0,0,0,.35); background: rgba(255,255,0,1); color: #111; } .swws-cta svg { width: 18px; height: 18px; } .swws-hero__bottom-fade { position: absolute; inset: auto 0 0 0; height: 160px; background: linear-gradient(to bottom, transparent, #fff); pointer-events: none; z-index: 6; } @media (prefers-color-scheme: dark) { .swws-hero__bottom-fade { background: linear-gradient(to bottom, transparent, #0b0d16); } } / === SWWS — YOYO Horizontal Gallery (aspect ratio edition) === / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection__header-wrapper { margin-bottom: 12px; } / Rail horizontal / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-gallery { display: grid !important; grid-auto-flow: column; grid-auto-columns: minmax(180px, 36vw); gap: 18px; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; padding: 8px 24px 24px; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; scrollbar-width: none; position: relative; } #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-gallery::-webkit-scrollbar { display: none; } / Cartes / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-card.gallery { scroll-snap-align: center; border-radius: 12px; overflow: hidden; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease; } #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-card.gallery:hover { transform: translateY(-2px); border-color: rgba(255,255,255,0.18); box-shadow: 0 10px 30px rgba(0,0,0,.25); } / Couverture image — proportion fixe / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-card__cover { width: 100%; aspect-ratio: 4 / 5; / 👈 proportion stable (4:5 = vertical élégant) / object-fit: cover !important; object-position: center 45% !important; display: block; } / Contenu sous l’image / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-card__content { padding: 12px 12px 14px; color: #5B5B5B; font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif; font-size: 14px; line-height: 1.45; background: transparent; } / Effet “edges fade” pour indiquer le scroll / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-gallery { -webkit-mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%); mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%); } / ---- Mobile adjustments ---- / @media (max-width: 720px) { #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-gallery { grid-auto-columns: 30vw; / carte presque plein écran / gap: 16px; padding: 8px 12px 24px; } #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-card__cover { aspect-ratio: 5 / 4; / plus proche du carré, mieux sur téléphone / } } / YOYOLIGHT — ne cacher le header vide qu'en version téléphone / @media (max-width: 768px) { #block-29a95fdcc23e804aaabfc41158ab7cef > .notion-collection__header-wrapper { display: none !important; margin: 0 !important; padding: 0 !important; } / petit espace fluide entre le titre H2 et la galerie / #block-29a95fdcc23e804aaabfc41158ab7cef .notion-collection-gallery { margin-top: 8px !important; } } / === Hero H2 Dynamic Line Reveal ====================== / .swws-h2 { display: flex; flex-direction: column; align-items: center; overflow: hidden; } .swws-h2 span { display: block; transform: translateY(120%); opacity: 0; animation: swwsLineReveal 0.9s ease-out forwards; } / Animation: chaque ligne remonte et apparaît / @keyframes swwsLineReveal { to { transform: translateY(0); opacity: 1; } } / Décalage progressif (effet cascade) / .swws-h2 span:nth-child(1) { animation-delay: 0.2s; } .swws-h2 span:nth-child(2) { animation-delay: 0.45s; } .swws-h2 span:nth-child(3) { animation-delay: 0.7s; } .swws-h2 span:nth-child(4) { animation-delay: 0.95s; } / Ajuste la typo et le rythme visuel / .swws-h2 { font-weight: 700; font-size: clamp(32px, 6vw, 72px); line-height: 1.1; letter-spacing: -0.015em; text-align: center; color: #fff; font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif; } / Respecte les préférences utilisateur / @media (prefers-reduced-motion: reduce) { .swws-h2 span { animation: none !important; opacity: 1 !important; transform: none !important; } } / === SWWS — Callout “GO TO PORTFOLIO” ===================== / #block-29b95fdcc23e8082ad10e30472ee6809 { background: #000 !important; border: none !important; padding: 3rem 1.5rem !important; text-align: center !important; } #block-29b95fdcc23e8082ad10e30472ee6809 .notion-callout__content { color: #fff !important; text-align: center !important; } #block-29b95fdcc23e8082ad10e30472ee6809 h2 { color: #fff !important; font-size: clamp(28px, 4vw, 48px); letter-spacing: 0.04em; font-weight: 700; text-transform: uppercase; margin: 0; } #block-29b95fdcc23e8082ad10e30472ee6809 a.notion-link { color: #fff !important; text-decoration: none !important; border-bottom: 2px solid #fff; padding-bottom: 4px; transition: color .25s ease, border-color .25s ease; } #block-29b95fdcc23e8082ad10e30472ee6809 a.notion-link:hover { color: #ffeb3b !important; border-color: #ffeb3b; } / === SWWS — Callout “SECONDARY / WHITE VERSION” ===================== / #block-2a195fdcc23e80efadffc6de8a38332c { background: #fff !important; border: none !important; padding: 3rem 1.5rem !important; text-align: center !important; } #block-2a195fdcc23e80efadffc6de8a38332c .notion-callout__content { color: #000 !important; text-align: center !important; } #block-2a195fdcc23e80efadffc6de8a38332c h2 { color: #000 !important; font-size: clamp(28px, 4vw, 48px); letter-spacing: 0.04em; font-weight: 700; text-transform: uppercase; margin: 0; } #block-2a195fdcc23e80efadffc6de8a38332c a.notion-link { color: #000 !important; text-decoration: none !important; border-bottom: 2px solid #000; padding-bottom: 4px; transition: color .25s ease, border-color .25s ease; } #block-2a195fdcc23e80efadffc6de8a38332c a.notion-link:hover { color: #ffeb3b !important; / même jaune accent / border-color: #ffeb3b; } / === Responsive (mobile) ===================== / @media (max-width: 768px) { #block-29b95fdcc23e8082ad10e30472ee6809, #block-2a195fdcc23e80efadffc6de8a38332c { padding: 2rem 1rem !important; } #block-29b95fdcc23e8082ad10e30472ee6809 h2, #block-2a195fdcc23e80efadffc6de8a38332c h2 { font-size: clamp(22px, 5vw, 36px); } } / === Scroll indicator (arrow down) === / .swws-scroll-indicator { position: absolute; bottom: 10vh; left: 50%; transform: translateX(-50%); background: none; border: none; color: #feedcf; / ton beige clair / cursor: pointer; opacity: 0.8; transition: opacity 0.3s ease, transform 0.3s ease; z-index: 10; animation: swwsArrowBounce 1.6s ease-in-out infinite; } .swws-scroll-indicator:hover { opacity: 1; transform: translate(-50%, 2px); } @keyframes swwsArrowBounce { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 8px); } } @media (prefers-reduced-motion: reduce) { .swws-scroll-indicator { animation: none; } } .swws-scroll-indicator svg { width: 60px; / ajuster ici / height: 202px; / garder le même ratio */ } | ||
CONTACT | <section class="sw-contact-section" id="contact">
<div class="sw-contact-inner">
<h2 class="sw-contact-title">
Contact — Get in touch
</h2>
<p class="sw-contact-text">
Always open to collaborations, commissions, and professional opportunities.<br>
Feel free to reach out — I personally read every message.<br><br>
<span class="sw-contact-text-fr">
Une idée, un projet, une collaboration ? Je lis chaque message personnellement et réponds dès que possible.
</span>
</p>
<!-- Formulaire Tally -->
<div class="sw-contact-form-wrapper">
<iframe
src="https://tally.so/r/318lyQ?transparentBackground=1&hideTitle=1"
width="100%"
height="920"
frameborder="0"
marginheight="0"
marginwidth="0"
title="Contact Form"
></iframe>
</div>
<!-- Email + WhatsApp -->
<p class="sw-contact-alt">
You can also write directly to
<a class="sw-mail"
href="mailto:sw@swws.net">
sw@swws.net
</a><br>
or send a message via
<a id="sw-wa-link" class="sw-wa-link" href="#" target="_blank" rel="noopener">
WhatsApp
</a>.<br><br>
<span class="sw-contact-alt-fr">
Vous pouvez aussi écrire directement à
<a class="sw-mail"
href="mailto:sw@swws.net">
sw@swws.net
</a><br>
ou m’envoyer un message via
<a id="sw-wa-link-fr" class="sw-wa-link" href="#" target="_blank" rel="noopener">
WhatsApp
</a>.
</span>
</p>
</div>
</section>
<script>
function initSWContact() {
// --- WHATSAPP PROTECTION ---
const waNumber = "33632493112"; // ton numéro sans le +
const waText = encodeURIComponent("Bonjour, je vous contacte depuis le site SWWS.");
["sw-wa-link", "sw-wa-link-fr"].forEach(id => {
const link = document.getElementById(id);
if (link && (!link.href || !link.href.includes("wa.me"))) {
link.href = | .sw-contact-section { padding: 4rem 0; } .sw-contact-inner { max-width: 720px; margin: 0 auto; } .sw-contact-title { font-family: "Space Grotesk", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 3.2rem; line-height: 1.15; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 1rem; } .sw-contact-text { margin-bottom: 2rem; font-family: "Inter", "Helvetica Neue", Arial, sans-serif; font-size: 1rem; line-height: 1.6; font-weight: 500; opacity: 0.9; } .sw-contact-text-fr { display: block; margin-top: 0.5rem; font-size: 0.95em; opacity: 0.7; } .sw-contact-form-wrapper { border-radius: 1.25rem; border: 1px solid rgba(0, 0, 0, 0.08); padding: 1.5rem; backdrop-filter: blur(12px); background-color: rgba(255, 255, 255, 0.6); } .sw-contact-alt { margin-top: 1.25rem; font-family: "Inter", "Helvetica Neue", Arial, sans-serif; font-size: 0.9rem; line-height: 1.5; opacity: 0.85; } .sw-contact-alt-fr { display: block; margin-top: 0.5rem; font-size: 0.85em; opacity: 0.65; } .sw-mail { text-decoration: underline; } .sw-wa-link { color: inherit; text-decoration: underline; transition: opacity 0.2s ease; } .sw-wa-link:hover { opacity: 0.7; } /* Responsive */ @media (max-width: 768px) { .sw-contact-section { padding: 2.5rem 1rem; } .sw-contact-title { font-size: 1.8rem; } } | ||
WORKS | <script> /* SWWS /works — persist filter index safely for Super.so */ (function(){ if (!/\/works(\/|$)/.test(location.pathname)) return; const KEY = 'swws:filterIndex'; const KEY_TEXT = 'swws:filterText'; const KEY_SCROLL = 'swws:scrollY'; const norm = s => (s||'').trim().toLowerCase(); function getButtons() { return Array.from(document.querySelectorAll('button, .super-filter button, .filters button, a')) .filter(b => b.offsetParent && b.textContent.trim().length); } // Sauvegarde au clic document.addEventListener('click', e => { const btn = e.target.closest('button, a'); if (!btn) return; const btns = getButtons(); const idx = btns.indexOf(btn); if (idx >= 0) { sessionStorage.setItem(KEY, idx); sessionStorage.setItem(KEY_TEXT, norm(btn.textContent)); sessionStorage.setItem(KEY_SCROLL, window.scrollY); } }, true); // Restaure function restore() { const idx = parseInt(sessionStorage.getItem(KEY)); const txt = sessionStorage.getItem(KEY_TEXT); const scrollY = parseFloat(sessionStorage.getItem(KEY_SCROLL)) || 0; if (isNaN(idx) && !txt) return; const t0 = performance.now(); (function loop(){ const btns = getButtons(); if (btns.length) { const target = btns[idx] || btns.find(b => norm(b.textContent) === txt); if (target) { target.click(); setTimeout(() => window.scrollTo({ top: scrollY, behavior: 'instant' }), 100); return; } } if (performance.now() - t0 < 6000) requestAnimationFrame(loop); })(); } document.addEventListener('DOMContentLoaded', restore); window.addEventListener('pageshow', restore); })(); </script> | /* 1) Lever les limites de conteneur sur la page Works / .page__works .super-content { max-width: none !important; } article#block-works.notion-root.max-width { max-width: none !important; } / 2) Fixer la largeur de la/les vues Notion en pourcentage de l'écran / :root { --portfolio-w: 80vw; } / ajuste 60–90 selon besoin / #block-works .notion-collection_view, #block-works .notion-collection_view > div { width: var(--portfolio-w); max-width: none; margin-inline: auto; / centré / } / Variables / :root{ --portfolio-vw: 80vw; / ajuste: 70–90vw / --portfolio-cap: 1280px; / plafond ≈ conteneur par défaut / } / Desktop & tablettes larges : appliquer la largeur à la gallery / @media (min-width: 901px){ .page__works #block-works .notion-collection-gallery{ width: min(var(--portfolio-vw), var(--portfolio-cap)) !important; max-width: 100% !important; margin-inline: auto !important; / centré / display: block; / évite certains layouts flex / } } / Mobile : rien → comportement par défaut de Super/Notion / / --- Couleur de fond du titre de carte dans la section Works --- / #block-works .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background-color: #fff; / 🎨 choisis ta couleur / padding: 0.5rem 0.75rem; / un peu d’espace interne / border-radius: 0px; / arrondi léger / display: inline-block; / le fond épouse la longueur du texte / transition: background-color 0.2s ease; } / Option : effet hover très léger / #block-works a.notion-collection-card__anchor:hover .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background-color: #ebebeb; } / Variante dark mode (si applicable) */ .dark-mode #block-works .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background-color: #1a1a1a; } .dark-mode #block-works a.notion-collection-card__anchor:hover .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background-color: #222; } | ||
SERIES ONSITE | <script>
(function () {
const PATH = () => location.pathname.replace(/\/+$/,'').toLowerCase();
const ALLOWED = () => /^\/series(\/|$)/.test(PATH());
function cleanupIfNotAllowed(){
if (ALLOWED()) return;
document.querySelectorAll('.swws-series-nav__wrap, .swws-backcat__wrap').forEach(n=>n.remove());
}
const ROOT = () => '/series';
const TABS = [
{ label:"Panels Series", href: () => | /* === SWWS — Series Nav (responsive + hover + mobile rail) =========== */ .swws-series-nav{ --pill-bg:#fff; --pill-fg:#111; --pill-bd:rgba(0,0,0,.18); --active-bg:#feedcf; --active-fg:#111; --active-bd:rgba(0,0,0,.25); --hover-bg:rgba(254,237,207,.6); --hover-bd:rgba(0,0,0,.2); margin:18px auto 22px; padding:10px 12px; } .swws-series-nav__rail{ display:flex; gap:12px; flex-wrap:wrap; justify-content:center; overflow:visible; } @media (max-width:720px){ .swws-series-nav__rail{ flex-wrap:nowrap; justify-content:flex-start; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:6px 4px; scroll-snap-type:x mandatory; scroll-behavior:smooth; mask-image:linear-gradient(to right, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%); -webkit-mask-image:linear-gradient(to right, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%); } .swws-series-nav__rail::-webkit-scrollbar{ display:none; } .swws-tab{ flex:0 0 auto; scroll-snap-align:center; } } .swws-tab{ display:inline-flex; align-items:center; justify-content:center; font:600 18px/1 "Space Grotesk", ui-sans-serif, system-ui; letter-spacing:.02em; color:var(--pill-fg); background:var(--pill-bg); border:1px solid var(--pill-bd); border-radius:0; padding:10px 16px; text-decoration:none; cursor:pointer; transition:background .2s, border-color .2s, transform .12s; } .swws-tab:hover{ background:var(--hover-bg); border-color:var(--hover-bd); transform:translateY(-1px); } .swws-tab[aria-current="page"]{ background:var(--active-bg); border-color:var(--active-bd); color:var(--active-fg); } .swws-backcat__wrap{ display:flex; justify-content:flex-start; margin:12px 0 18px; } @media (max-width:640px){ .swws-backcat__wrap{ justify-content:center; } } .swws-backcat{ display:inline-flex; align-items:center; gap:.55rem; padding:.75rem 1.1rem; border-radius:999px; background:#111; color:#fff; text-decoration:none; font:600 14px/1 "Space Grotesk",ui-sans-serif,system-ui; border:1px solid rgba(255,255,255,.14); box-shadow:0 6px 18px rgba(0,0,0,.25); transition:transform .15s, box-shadow .2s, background .2s; } .swws-backcat:hover{ transform:translateY(-1px); background:#000; box-shadow:0 10px 26px rgba(0,0,0,.32); } .swws-backcat svg{ width:18px; height:18px; } | ||
SERIES ALL | <script>
(function () {
const PATH = () => location.pathname.replace(/\/+$/,'').toLowerCase();
const ALLOWED = () => /^\/series(\/|$)/.test(PATH());
function cleanupIfNotAllowed(){
if (ALLOWED()) return;
document.querySelectorAll('.swws-series-nav__wrap, .swws-backcat__wrap').forEach(n=>n.remove());
}
const ROOT = () => '/series';
const TABS = [
{ label:"Panels Series", href: () => | /* === SWWS — Series Nav (responsive + hover + mobile rail) =========== / .swws-series-nav{ --pill-bg:#fff; --pill-fg:#111; --pill-bd:rgba(0,0,0,.18); --active-bg:#feedcf; --active-fg:#111; --active-bd:rgba(0,0,0,.25); --hover-bg:rgba(254,237,207,.6); --hover-bd:rgba(0,0,0,.2); margin:18px auto 22px; padding:10px 12px; } .swws-series-nav__rail{ display:flex; gap:12px; flex-wrap:wrap; justify-content:center; overflow:visible; } @media (max-width:720px){ .swws-series-nav__rail{ flex-wrap:nowrap; justify-content:flex-start; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:6px 4px; scroll-snap-type:x mandatory; scroll-behavior:smooth; mask-image:linear-gradient(to right, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%); -webkit-mask-image:linear-gradient(to right, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%); } .swws-series-nav__rail::-webkit-scrollbar{ display:none; } .swws-tab{ flex:0 0 auto; scroll-snap-align:center; } } .swws-tab{ display:inline-flex; align-items:center; justify-content:center; font:600 18px/1 "Space Grotesk", ui-sans-serif, system-ui; letter-spacing:.02em; color:var(--pill-fg); background:var(--pill-bg); border:1px solid var(--pill-bd); border-radius:0; padding:10px 16px; text-decoration:none; cursor:pointer; transition:background .2s, border-color .2s, transform .12s; } .swws-tab:hover{ background:var(--hover-bg); border-color:var(--hover-bd); transform:translateY(-1px); } .swws-tab[aria-current="page"]{ background:var(--active-bg); border-color:var(--active-bd); color:var(--active-fg); } .swws-backcat__wrap{ display:flex; justify-content:flex-start; margin:12px 0 18px; } @media (max-width:640px){ .swws-backcat__wrap{ justify-content:center; } } .swws-backcat{ display:inline-flex; align-items:center; gap:.55rem; padding:.75rem 1.1rem; border-radius:999px; background:#111; color:#fff; text-decoration:none; font:600 14px/1 "Space Grotesk",ui-sans-serif,system-ui; border:1px solid rgba(255,255,255,.14); box-shadow:0 6px 18px rgba(0,0,0,.25); transition:transform .15s, box-shadow .2s, background .2s; } .swws-backcat:hover{ transform:translateY(-1px); background:#000; box-shadow:0 10px 26px rgba(0,0,0,.32); } .swws-backcat svg{ width:18px; height:18px; } / --- Masonry plein écran pour la page ALL projects --- / @media (min-width: 1024px) { / Étendre la galerie sur toute la largeur / #block-series-all { max-width: 100vw !important; padding-left: 3vw; padding-right: 3vw; } / Masonry columns : 3 sur desktop / #block-series-all .notion-collection-gallery { display: block !important; / On casse le grid natif de Super / column-count: 3 !important; / Force 3 colonnes / column-gap: 1.2rem !important; } / Chaque carte = brique masonry / #block-series-all .notion-collection-card { display: inline-block !important; width: 100% !important; max-width: 100% !important; flex: none !important; margin-bottom: 1.8rem !important; break-inside: avoid; overflow: hidden; border-radius: 0px; transition: transform 0.25s ease, opacity 0.3s ease; } / Effet au survol / #block-series-all .notion-collection-card:hover { transform: translateY(-4px); opacity: 0.95; } / Images fluides / #block-series-all img.notion-collection-card__cover { width: 100% !important; height: auto !important; display: block; border-radius: 0px; } / Texte sous l’image / #block-series-all .notion-collection-card__property-list { padding: 0.6rem 0.4rem 1rem 0.4rem; } } / Écrans très larges (≥1600px) : 4 colonnes / @media (min-width: 1600px) { #block-series-all .notion-collection-gallery { column-count: 4 !important; } } / Tablette : 2 colonnes masonry / @media (min-width: 768px) and (max-width: 1023px) { #block-series-all { max-width: 100vw !important; padding-left: 4vw; padding-right: 4vw; } #block-series-all .notion-collection-gallery { display: block !important; column-count: 2 !important; column-gap: 1.4rem !important; } #block-series-all .notion-collection-card { display: inline-block !important; width: 100% !important; max-width: 100% !important; flex: none !important; margin-bottom: 1.4rem !important; break-inside: avoid; } } / Mobile : une seule colonne, grille native de Super */ | ||
LANDING 02 | <!-- === SWWS Landing Hero — ASCII Canvas Background (Quality MAX) ===== -->
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Roboto+Mono:wght@400&display=swap" rel="stylesheet">
<style>
.swws-hero, .swws-hero * { box-sizing: border-box; }
.swws-hero {
position: relative;
height: 100dvh; width: 100%;
isolation: isolate; overflow: clip;
display: grid; place-items: center;
background: #000; color: #fff; text-align: center;
font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
}
/* Canvas ASCII en fond /
.swws-ascii { position:absolute; inset:0; width:100%; height:100%; display:block; z-index:1; }
/ Vignettage doux pour lisibilité du texte /
.swws-hero::after{
content:""; position:absolute; inset:0; pointer-events:none; z-index:2;
background: radial-gradient(120% 85% at 50% 12%, transparent 0 58%, rgba(0,0,0,.45) 100%);
}
.swws-hero__content { position:relative; z-index:5; padding:2rem 1rem; max-width:min(900px, 90vw); }
.swws-eyebrow{
display:inline-flex; align-items:center; gap:.6rem; padding:.4rem .7rem; border-radius:999px;
background:rgba(255,255,255,.12); backdrop-filter:blur(8px);
font-weight:600; font-size:18px; letter-spacing:.08em; text-transform:uppercase;
}
.swws-dot{ width:.8rem; aspect-ratio:1; border-radius:50%; background:#FFFF00; box-shadow:0 0 .5rem #FFFF00; }
/ H2 dynamique par lignes (déjà validé) /
.swws-h2{ display:flex; flex-direction:column; align-items:center; overflow:hidden;
font-weight:700; font-size:clamp(32px,6vw,72px); line-height:1.1; letter-spacing:-0.015em; color:#fff; }
.swws-h2 span{ display:block; transform:translateY(120%); opacity:0; animation:swwsLineReveal .9s ease-out forwards; }
@keyframes swwsLineReveal{ to{ transform:translateY(0); opacity:1; } }
.swws-h2 span:nth-child(1){animation-delay:.2s}
.swws-h2 span:nth-child(2){animation-delay:.45s}
.swws-h2 span:nth-child(3){animation-delay:.7s}
.swws-h2 span:nth-child(4){animation-delay:.95s}
.swws-contact{ font-weight:400; font-size:16px; line-height:1.7; color:#fff; opacity:.9; margin-bottom:2rem; }
.swws-contact a{ color:#fff; text-decoration:underline; text-underline-offset:3px; transition:color .2s ease; }
.swws-contact a:hover{ color:#feedcf; }
.swws-cta{
display:inline-flex; align-items:center; gap:.6rem; padding:.9rem 1.4rem; border-radius:0px;
color:#111; background:rgba(254,237,207,0.9); border:1px solid rgba(255,255,0,.35); text-decoration:none;
font-weight:600; font-size:15px; box-shadow:0 10px 30px rgba(0,0,0,.25);
transition:transform .2s ease, box-shadow .2s ease, background .2s ease, color .2s ease;
}
.swws-cta:hover{ transform:translateY(-2px); box-shadow:0 14px 40px rgba(0,0,0,.35); background:rgba(255,255,0,1); color:#111; }
.swws-cta svg{ width:18px; height:18px; }
.swws-hero__bottom-fade{ position:absolute; inset:auto 0 0 0; height 160px; background:linear-gradient(to bottom, transparent, #fff); pointer-events:none; z-index:6; }
@media (prefers-color-scheme: dark){ .swws-hero__bottom-fade{ background:linear-gradient(to bottom, transparent, #0b0d16); } }
@media (prefers-reduced-motion: reduce){
.swws-h2 span{ animation:none !important; opacity:1 !important; transform:none !important; }
}
</style>
<section id="swws-hero" class="swws-hero" aria-label="Sebastien Wierinck WorkShop — Hero">
<canvas id="swws-ascii" class="swws-ascii" aria-hidden="true"></canvas>
<div class="swws-hero__content">
<span class="swws-eyebrow"><span class="swws-dot"></span> Sebastien Wierinck WorkShop</span>
<h2 class="swws-h2">
<span>A design practice</span>
<span>at the intersection of</span>
<span>furniture, public art,</span>
<span>and digital craft.</span>
</h2>
<p class="swws-contact">
Get in touch → <a href="mailto:sw@swws.net">sw@swws.net</a><br>
Always open to collaborations, commissions, and professional opportunities.
</p>
<a class="swws-cta" href="https://swws.net/works">
Explore our Portfolio
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M5 12h12M13 6l6 6-6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
</div>
<div class="swws-hero__bottom-fade"></div>
</section>
<script>
/ === ASCII Canvas — Quality MAX with auto density & perf guards ===== /
(() => {
const canvas = document.getElementById('swws-ascii');
if (!canvas) return;
const ctx = canvas.getContext('2d', { alpha: true, willReadFrequently: true });
// Images (ordre validé)
const IMAGES = [
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/775095d7-97ff-423c-8787-04648236bdb6/005/w=3840,quality=90,fit=scale-down',
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/e00f1546-30d8-444d-a663-cb1d9946d1b6/Buffet-Enfilade-SebastienWierinckSebastienNormand061/w=1920,quality=90,fit=scale-down',
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/dd8fc821-2964-4b81-ba44-aa04cee3f03a/BodyFold-Septeme-SWierinckSebastienNormand013/w=3840,quality=90,fit=scale-down',
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/f6a0da9d-d7c7-41c3-b17a-c9ea5bf66fec/CD104-02/w=1920,quality=90,fit=scale-down',
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/527cd0ef-b6eb-4a9d-bb9d-ac0ffa7d7faa/WORMS-SWWSSbastienNormand008_WEB/w=3840,quality=90,fit=scale-down',
'https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/29cd6995-4e66-4d1b-8201-cd78b7abdfdf/J1-OS015-001c/w=1920,quality=90,fit=scale-down'
];
// Paramètres qualité
const CHARSET = '@%#WS$9876543210?!abc;:+=-,._ '; // sombre → clair (long = finesse)
const COLOR_MODE = 'mono'; // 'mono' ou 'color'
const BASE_CELL_DESKTOP = 5; // plus petit = plus de détails (5 recommandé pour Retina)
const BASE_CELL_MOBILE = 4; // densité plus légère pour mobile
const MAX_CELLS = 180000; // garde-fou perf (colonnes * lignes)
const CONTRAST = 1.1;
const BRIGHTNESS = 1.05;
const SLIDE_MS = 6000;
let imgIndex = 0, currentImg = null, slideTimer = null;
// Offscreen canvas pour downsample
const off = ('OffscreenCanvas' in window) ? new OffscreenCanvas(1,1) : document.createElement('canvas');
const octx = off.getContext('2d', { willReadFrequently: true });
// Chargement d'image
function loadImage(src){
return new Promise((resolve, reject)=>{
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
}
// DPR & resize
function fitCanvasToParent(){
const parent = canvas.parentElement;
const dpr = Math.min(window.devicePixelRatio || 1, 2); // cap à 2
const w = parent.clientWidth;
const h = parent.clientHeight;
canvas.style.width = w + 'px';
canvas.style.height = h + 'px';
canvas.width = Math.floor(w * dpr);
canvas.height = Math.floor(h * dpr);
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
function calcGrid(){
const W = canvas.clientWidth, H = canvas.clientHeight;
const isMobile = Math.min(W, H) < 820; // heuristique téléphone/tablette portrait
// Base cell size selon device
const baseCell = isMobile ? BASE_CELL_MOBILE : BASE_CELL_DESKTOP;
// Ajustement par DPR (plus fin sur Retina)
const dpr = Math.min(window.devicePixelRatio || 1, 2);
const dprBoost = dpr >= 1.5 ? 0.85 : 1.0; // un peu plus dense si Retina
// Densité adaptative selon surface (évite 4K trop lourd)
const area = W * H;
let densityFactor = 1.4;
if (area > 2000000) densityFactor = 1.15; // 2MP
if (area > 3500000) densityFactor = 1.3; // 3.5MP
const CELL = baseCell * dprBoost * densityFactor;
// Estimation lignes/colonnes (ratio lignes ~ 1.9 pour caractères)
let cols = Math.ceil(W / CELL);
let rows = Math.ceil(H / (CELL * 1.0));
// Garde-fou : limite le nb total de “cellules”
const total = cols * rows;
if (total > MAX_CELLS){
const scale = Math.sqrt(total / MAX_CELLS);
cols = Math.floor(cols / scale);
rows = Math.floor(rows / scale);
}
return { cols, rows, cellPx: CELL };
}
function drawASCII(){
if (!currentImg) return;
const W = canvas.clientWidth, H = canvas.clientHeight;
const { cols, rows } = calcGrid();
// 1) Dessin “cover” de l’image source dans l’offscreen à la résolution du grid
const sW = currentImg.width, sH = currentImg.height;
const scale = Math.max(cols / sW, rows / sH);
const dW = sW * scale, dH = sH * scale;
const dx = (cols - dW) * 0.5;
const dy = (rows - dH) * 0.55; // focus légèrement plus bas
if (off.width) { off.width = cols; off.height = rows; }
else { off.width = cols; off.height = rows; } // pour OffscreenCanvas
octx.imageSmoothingEnabled = true;
octx.clearRect(0, 0, cols, rows);
octx.drawImage(currentImg, dx, dy, dW, dH);
const imgData = octx.getImageData(0, 0, cols, rows).data;
// 2) Peindre le fond
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, W, H);
// 3) Rendu caractères
const charW = W / cols;
const charH = H / rows;
// Police optimisée (Roboto Mono = très propre)
ctx.textBaseline = 'top';
ctx.font = | /* === SWWS — Featured gallery (B&W default, color on hover) ============ / / Cible le nouveau bloc / #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card__cover { / N&B propre, un peu d’intensité / filter: grayscale(1) contrast(1.08) brightness(0.96); transition: filter .45s ease, transform .35s ease; will-change: filter, transform; } / Couleur + léger zoom au hover/focus (desktop & clavier) / @media (hover:hover) { #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card.gallery:hover .notion-collection-card__cover, #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card.gallery:focus-within .notion-collection-card__cover { filter: grayscale(0) contrast(1.02) brightness(1.0); transform: scale(1.03); } } / Mobile/tactile : pas de zoom (évite les sauts), couleur au tap (active) / @media (hover:none) { #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card.gallery:active .notion-collection-card__cover { filter: grayscale(0) contrast(1.02) brightness(1.0); } } / Option: ajout d'un grain très léger pour un rendu éditorial (facultatif) / #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card__cover::after { content: ""; position: absolute; inset: 0; pointer-events: none; background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px); background-size: 2px 2px; / grain fin / mix-blend-mode: overlay; opacity: .25; transition: opacity .35s ease; } @media (hover:hover) { #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card.gallery:hover .notion-collection-card__cover::after { opacity: .12; / un peu moins de grain en couleur / } } / Accessibilité: si l’utilisateur préfère moins d’animations / @media (prefers-reduced-motion: reduce) { #block-29a95fdcc23e80c9abecc3777b9f2655 .notion-collection-card__cover { transition: none; } } / === SWWS — Titres des cartes Notion : fond blanc + hover jaune ============ / .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background: #fff; / fond blanc / color: #000; / texte noir / padding: 0px 012px; display: inline-block; border-radius: 0px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; } / === SWWS — YOYO Horizontal Gallery (aspect ratio edition) === / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection__header-wrapper { margin-bottom: 12px; } / Rail horizontal / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery { display: grid !important; grid-auto-flow: column; grid-auto-columns: minmax(180px, 36vw); gap: 18px; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; padding: 8px 24px 24px; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; scrollbar-width: none; position: relative; } #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery::-webkit-scrollbar { display: none; } / Cartes / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery { scroll-snap-align: center; border-radius: 12px; overflow: hidden; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease; } #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery:hover { transform: translateY(-2px); border-color: rgba(255,255,255,0.18); box-shadow: 0 10px 30px rgba(0,0,0,.25); } / Couverture image — proportion fixe / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card__cover { width: 100%; aspect-ratio: 4 / 5; / 👈 proportion stable (4:5 = vertical élégant) / object-fit: cover !important; object-position: center 45% !important; display: block; } / Contenu sous l’image / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card__content { padding: 12px 12px 14px; color: #5B5B5B; font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif; font-size: 18px; line-height: 1.45; background: transparent; } / Effet “edges fade” pour indiquer le scroll / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery { -webkit-mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%); mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%); } / ---- Mobile adjustments ---- / @media (max-width: 720px) { #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery { grid-auto-columns: 30vw; / carte presque plein écran / gap: 16px; padding: 8px 12px 24px; } #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card__cover { aspect-ratio: 5 / 4; / plus proche du carré, mieux sur téléphone / } } / YOYOLIGHT — ne cacher le header vide qu'en version téléphone / @media (max-width: 768px) { #block-29b95fdcc23e8076ae45cee0bceb4255 > .notion-collection__header-wrapper { display: none !important; margin: 0 !important; padding: 0 !important; } / petit espace fluide entre le titre H2 et la galerie / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery { margin-top: 8px !important; } } / Fix mobile : supprimer l’espace laissé par le header-wrapper intermédiaire / @media (max-width: 768px) { / Masque le header vide + retire son espace / #block-29b95fdcc23e801a95bfcfe99896e893 > .notion-collection__header-wrapper { display: none !important; margin: 0 !important; padding: 0 !important; height: 0 !important; } / Si Notion insère un paragraphe vide, on le neutralise aussi / #block-29b95fdcc23e801a95bfcfe99896e893 .notion-text:empty, #block-29b95fdcc23e801a95bfcfe99896e893 .notion-semantic-string:empty { display: none !important; } / Ajoute un mini-espacement au-dessus du rail pour respirer (optionnel) / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-gallery { margin-top: 8px !important; / ajuste à 0 si tu veux collé / } } / Overlay uses --hover-img set by JS / #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery { position: relative; overflow: hidden; } #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery::after { content: ""; position: absolute; inset: 0; background-image: var(--hover-img); background-size: cover; background-position: center 45%; opacity: 0; transition: opacity .35s ease; pointer-events: none; } / Desktop hover / @media (hover:hover) { #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery.swws-lamp-ready:hover::after { opacity: 1; } } / Mobile tap */ @media (hover:none) { #block-29b95fdcc23e8076ae45cee0bceb4255 .notion-collection-card.gallery.swws-lamp-ready:active::after { opacity: 1; } } |