feat: migre le site vers SvelteKit (Svelte 5, statique, zéro tiers)

- Rebuild complet SvelteKit 2 + Svelte 5 runes + TypeScript, adapter-static
- Images self-hébergées optimisées au build (vite-imagetools), fonts Archivo/Inter
  en woff2 local — BunnyCDN et Google Fonts supprimés (corrige les 403 d'images)
- Tokens charte OKI, thème sombre par défaut / clair opt-in, zéro emoji (set SVG)
- Motion : KineticText (stagger syncopé gwoka), ScrollProgressBar, View Transitions
- Village SVG isométrique pour les services hébergés + fallback accessible
- PWA (manifest + SW hors-ligne), 404 en KA, CSP nettoyée (.htaccess + _headers)
- Lighthouse mobile : 91/100/100/100 — JS initial 67 Ko gzip
This commit is contained in:
sucupira
2026-07-21 08:00:16 -04:00
parent d0fc7207f2
commit d0d80a105e
175 changed files with 15603 additions and 5911 deletions
+55
View File
@@ -0,0 +1,55 @@
<script lang="ts">
import { page } from '$app/state';
const status = $derived(page.status);
const is404 = $derived(status === 404);
</script>
<svelte:head>
<title>{status}{is404 ? 'Paj la rivé périyòd…' : 'Erreur'} · ORGANISATION KA INTERNATIONALE</title>
<meta name="robots" content="noindex" />
</svelte:head>
<section class="error-page container">
<svg class="icon error-icon" aria-hidden="true"><use href="/icons.svg#ka" /></svg>
<h1>{status}</h1>
{#if is404}
<p class="ka" lang="gcf">« Paj la rivé périyòd… »</p>
<p class="fr">La page que vous cherchez n'existe pas ou a été déplacée. La route continue ailleurs.</p>
{:else}
<p class="fr">{page.error?.message ?? 'Une erreur est survenue.'}</p>
{/if}
<a class="btn" href="/">Retour à l'accueil</a>
</section>
<style>
.error-page {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: var(--space-3);
padding: var(--space-5) var(--space-4);
}
.error-icon {
width: 6rem;
height: 6rem;
color: var(--or-oki);
}
h1 {
font-weight: 900;
font-size: clamp(4rem, 15vw, 8rem);
}
.ka {
font-size: 1.25rem;
color: var(--or-oki);
}
.fr {
max-width: 52ch;
color: var(--muted);
}
</style>
+57
View File
@@ -0,0 +1,57 @@
<script lang="ts">
import '$lib/styles/oki-tokens.css';
import '$lib/styles/base.css';
import { afterNavigate, onNavigate } from '$app/navigation';
import { page } from '$app/state';
import Footer from '$lib/components/Footer.svelte';
import Nav from '$lib/components/Nav.svelte';
import ScrollProgressBar from '$lib/components/motion/ScrollProgressBar.svelte';
import { getBundle, localeFromPath } from '$lib/i18n';
import { prefersReducedMotion } from '$lib/motion/tokens';
let { children } = $props();
const locale = $derived(localeFromPath(page.url.pathname));
const t = $derived(getBundle(locale));
// PageTransition légère : View Transitions API, durée lue depuis les tokens.
// Navigateurs sans support : navigation instantanée (fallback sobre).
onNavigate((navigation) => {
if (prefersReducedMotion()) return;
if (!document.startViewTransition) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
// Focus déplacé sur le contenu après chaque transition de route (playbook §6)
afterNavigate(({ type, to }) => {
if (type === 'enter') return;
if (to?.url.hash) return;
document.getElementById('contenu')?.focus({ preventScroll: true });
});
</script>
<a href="#contenu" class="skip-link">{locale === 'en' ? 'Skip to content' : 'Aller au contenu'}</a>
<ScrollProgressBar />
<Nav {t} {locale} />
<main id="contenu" tabindex="-1">
{@render children()}
</main>
<Footer {t} {locale} />
<style>
main {
outline: none;
}
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: var(--dur-mesure);
animation-timing-function: var(--ease-ka);
}
</style>
+2
View File
@@ -0,0 +1,2 @@
export const prerender = true;
export const trailingSlash = 'always';
+33
View File
@@ -0,0 +1,33 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import Clients from '$lib/components/sections/Clients.svelte';
import Contact from '$lib/components/sections/Contact.svelte';
import Djangokam from '$lib/components/sections/Djangokam.svelte';
import Engagement from '$lib/components/sections/Engagement.svelte';
import Faq from '$lib/components/sections/Faq.svelte';
import Fediverse from '$lib/components/sections/Fediverse.svelte';
import Hero from '$lib/components/sections/Hero.svelte';
import Hosting from '$lib/components/sections/Hosting.svelte';
import Mission from '$lib/components/sections/Mission.svelte';
import Partners from '$lib/components/sections/Partners.svelte';
import Projects from '$lib/components/sections/Projects.svelte';
import Publics from '$lib/components/sections/Publics.svelte';
import { getBundle } from '$lib/i18n';
const t = getBundle('fr');
</script>
<Seo path="/" locale="fr" />
<Hero {t} locale="fr" />
<Publics {t} locale="fr" />
<Projects {t} locale="fr" />
<Partners {t} locale="fr" />
<Djangokam {t} locale="fr" />
<Mission {t} locale="fr" />
<Hosting {t} locale="fr" />
<Clients {t} locale="fr" />
<Fediverse {t} locale="fr" />
<Faq {t} locale="fr" />
<Engagement {t} locale="fr" />
<Contact {t} locale="fr" />
+435
View File
@@ -0,0 +1,435 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import donations from '$lib/data/donations.json';
import { getBundle } from '$lib/i18n';
const t = getBundle('fr');
// Lien Stripe « montant libre » repris à l'identique du legacy
// (legacy/src/assets/js/main.js — handleCustomDonation).
const CUSTOM_DONATION_URL = 'https://don.o-k-i.net/b/6oE2aO94P88X9u8eV4';
let customOneTime = $state('');
let customMonthly = $state('');
function handleCustomDonation(amount: string) {
const value = Number(amount);
if (!amount || !Number.isFinite(value) || value < 1) {
alert('Veuillez entrer un montant valide');
return;
}
window.location.href = CUSTOM_DONATION_URL;
}
</script>
<Seo
title="Dons"
description="Soutenez ORGANISATION KA INTERNATIONALE par un don ponctuel ou mensuel via Stripe, Liberapay ou Ko-fi."
path="/dons/"
locale="fr"
/>
<section class="dons-hero">
<h1>{t.support.section_title} <span class="accent">{t.support.section_title_accent}</span></h1>
<p class="lede">{t.support.lede}</p>
<p class="lede-secondary">{t.support.lede_secondary}</p>
</section>
<section class="support">
<div class="support-inner">
<div class="donation-panels">
<div class="support-panel support-panel--primary">
<h2>
<svg class="icon" aria-hidden="true"><use href="/icons.svg#lakanmou" /></svg>
{t.support.one_time_title}
</h2>
<div class="donation-grid">
{#each donations.oneTime as d (d.url)}
<a href={d.url} class="donation-amount" target="_blank" rel="noopener noreferrer">
{d.amount}{t.support.one_time_suffix}
</a>
{/each}
</div>
<div class="custom-donation">
<label class="donation-form-label" for="customAmountOneTime">
{t.support.custom_amount_label}
</label>
<div class="custom-donation-form">
<input
type="number"
id="customAmountOneTime"
bind:value={customOneTime}
placeholder={t.support.custom_amount_placeholder}
min="1"
class="custom-amount-input"
/>
<span class="currency-symbol">{t.support.one_time_suffix}</span>
<button
type="button"
class="custom-donation-btn custom-donation-btn-primary"
onclick={() => handleCustomDonation(customOneTime)}
>
{t.support.custom_amount_btn}
</button>
</div>
</div>
</div>
<div class="support-panel support-panel--secondary">
<h2>{t.support.monthly_title}</h2>
<div class="donation-grid">
{#each donations.monthly as d (d.url)}
<a
href={d.url}
class="donation-amount monthly"
target="_blank"
rel="noopener noreferrer"
>
{d.amount}{t.support.monthly_suffix}
</a>
{/each}
</div>
<div class="custom-donation">
<label class="donation-form-label" for="customAmountMonthly">
{t.support.custom_monthly_label}
</label>
<div class="custom-donation-form">
<input
type="number"
id="customAmountMonthly"
bind:value={customMonthly}
placeholder={t.support.custom_amount_placeholder}
min="1"
class="custom-amount-input custom-amount-input-monthly"
/>
<span class="currency-symbol">{t.support.monthly_suffix}</span>
<button
type="button"
class="custom-donation-btn custom-donation-btn-secondary"
onclick={() => handleCustomDonation(customMonthly)}
>
{t.support.custom_monthly_btn}
</button>
</div>
</div>
</div>
</div>
<div class="alt-donation-section">
<h2 class="alt-donation-title">{t.support.alt_title}</h2>
<div class="alt-donation-grid">
<a
href={donations.liberapay}
target="_blank"
rel="noopener noreferrer"
class="alt-donation-card alt-donation-card--liberapay"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#jaden" /></svg
>
<h3>{t.support.liberapay_title}</h3>
<p>{t.support.liberapay_text}</p>
</a>
<a
href={donations.kofi}
target="_blank"
rel="noopener noreferrer"
class="alt-donation-card alt-donation-card--kofi"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#lakanmou" /></svg
>
<h3>{t.support.kofi_title}</h3>
<p>{t.support.kofi_text}</p>
</a>
</div>
</div>
<div class="security-note">
<!-- Contenu éditorial du bundle i18n (lien Stripe), repris du legacy -->
<p>{@html t.support.security_stripe}</p>
<p>{t.support.security_alt}</p>
</div>
</div>
</section>
<style>
.dons-hero {
padding: 9rem var(--space-4) 3rem;
text-align: center;
border-bottom: 1px solid var(--line);
}
.dons-hero h1 {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: var(--space-2);
}
.accent {
color: var(--or-oki);
}
.lede {
max-width: 700px;
margin: 0 auto var(--space-2);
font-size: 1.2rem;
}
.lede-secondary {
max-width: 700px;
margin: 0 auto;
font-size: 1.05rem;
color: var(--muted);
}
.support {
padding: var(--space-5) var(--space-4);
background: var(--noir-profond);
text-align: center;
}
.support-inner {
max-width: 900px;
margin: 0 auto;
}
.support-panel {
background: var(--card-bg);
border: var(--border-card);
border-radius: var(--radius-md);
padding: var(--space-4);
margin-bottom: var(--space-4);
}
.support-panel h2 {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: var(--space-3);
font-size: 1.3rem;
}
.support-panel--primary {
border-top: 4px solid var(--or-oki);
}
.support-panel--primary h2 {
color: var(--or-oki);
}
.support-panel--secondary {
border-top: 4px solid var(--vert-oki);
}
.support-panel--secondary h2 {
color: var(--vert-oki);
}
.donation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.donation-amount {
display: flex;
align-items: center;
justify-content: center;
padding: 1.1rem;
background: color-mix(in srgb, var(--or-oki) 8%, transparent);
border: 2px solid var(--or-oki);
color: var(--blanc-creme);
border-radius: var(--radius-sm);
font-weight: 700;
font-size: 1.05rem;
transition:
background var(--dur-tanbou) var(--ease-ka),
color var(--dur-tanbou) var(--ease-ka),
transform var(--dur-tanbou) var(--ease-ka);
}
.donation-amount:hover {
background: var(--or-oki);
color: var(--noir-oki);
transform: translateY(-2px);
}
.donation-amount.monthly {
background: color-mix(in srgb, var(--vert-oki) 8%, transparent);
border-color: var(--vert-oki);
}
.donation-amount.monthly:hover {
background: var(--vert-oki);
color: var(--noir-oki);
}
.donation-form-label {
display: block;
margin-bottom: var(--space-2);
}
.custom-donation-form {
display: flex;
gap: 0.5rem;
justify-content: center;
align-items: center;
max-width: 350px;
margin: 0 auto;
padding: 0 var(--space-2);
}
.custom-amount-input {
padding: 0.8rem;
border: 2px solid var(--or-oki);
background: color-mix(in srgb, var(--blanc-creme) 5%, transparent);
color: var(--blanc-creme);
border-radius: var(--radius-sm);
flex: 1;
min-width: 0;
font-size: 1rem;
font-family: var(--font-body);
appearance: textfield;
-moz-appearance: textfield;
}
.custom-amount-input::-webkit-inner-spin-button,
.custom-amount-input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.custom-amount-input:focus {
outline: none;
background: color-mix(in srgb, var(--blanc-creme) 8%, transparent);
}
.custom-amount-input-monthly {
border-color: var(--vert-oki);
}
.currency-symbol {
white-space: nowrap;
flex-shrink: 0;
}
.custom-donation-btn {
padding: 0.8rem 1.2rem;
border: none;
border-radius: var(--radius-sm);
font-weight: 700;
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
font-family: var(--font-body);
font-size: 1rem;
transition: transform var(--dur-tanbou) var(--ease-ka);
}
.custom-donation-btn:hover {
transform: translateY(-2px);
}
.custom-donation-btn-primary {
background: var(--or-oki);
color: var(--noir-oki);
}
.custom-donation-btn-secondary {
background: var(--vert-oki);
color: var(--noir-oki);
}
.alt-donation-section {
margin-top: var(--space-4);
}
.alt-donation-title {
color: var(--or-oki);
margin-bottom: var(--space-4);
font-size: 1.3rem;
}
.alt-donation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--space-3);
max-width: 700px;
margin: 0 auto;
}
.alt-donation-card {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-1);
padding: var(--space-4);
background: var(--card-bg);
border: var(--border-card);
border-top: 3px solid var(--card-accent, var(--or-oki));
border-radius: var(--radius-md);
color: var(--blanc-creme);
transition: transform var(--dur-tanbou) var(--ease-ka);
}
.alt-donation-card:hover {
transform: translateY(-4px);
color: var(--blanc-creme);
}
.alt-donation-card--liberapay {
--card-accent: var(--vert-oki);
}
.alt-donation-card--kofi {
--card-accent: var(--or-oki);
}
.alt-donation-icon {
width: 2rem;
height: 2rem;
color: var(--card-accent, var(--or-oki));
}
.alt-donation-card h3 {
color: var(--card-accent, var(--or-oki));
font-size: 1.2rem;
}
.alt-donation-card p {
text-align: center;
font-size: 0.95rem;
}
.security-note {
margin-top: var(--space-4);
padding: var(--space-3);
background: var(--card-bg);
border-radius: var(--radius-md);
}
.security-note p {
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--muted);
}
@media (max-width: 480px) {
.custom-donation-form {
flex-direction: column;
}
.custom-amount-input,
.custom-donation-btn {
width: 100%;
}
}
</style>
+33
View File
@@ -0,0 +1,33 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import Clients from '$lib/components/sections/Clients.svelte';
import Contact from '$lib/components/sections/Contact.svelte';
import Djangokam from '$lib/components/sections/Djangokam.svelte';
import Engagement from '$lib/components/sections/Engagement.svelte';
import Faq from '$lib/components/sections/Faq.svelte';
import Fediverse from '$lib/components/sections/Fediverse.svelte';
import Hero from '$lib/components/sections/Hero.svelte';
import Hosting from '$lib/components/sections/Hosting.svelte';
import Mission from '$lib/components/sections/Mission.svelte';
import Partners from '$lib/components/sections/Partners.svelte';
import Projects from '$lib/components/sections/Projects.svelte';
import Publics from '$lib/components/sections/Publics.svelte';
import { getBundle } from '$lib/i18n';
const t = getBundle('en');
</script>
<Seo path="/en/" locale="en" />
<Hero {t} locale="en" />
<Publics {t} locale="en" />
<Projects {t} locale="en" />
<Partners {t} locale="en" />
<Djangokam {t} locale="en" />
<Mission {t} locale="en" />
<Hosting {t} locale="en" />
<Clients {t} locale="en" />
<Fediverse {t} locale="en" />
<Faq {t} locale="en" />
<Engagement {t} locale="en" />
<Contact {t} locale="en" />
+435
View File
@@ -0,0 +1,435 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import donations from '$lib/data/donations.json';
import { getBundle } from '$lib/i18n';
const t = getBundle('en');
// Stripe "custom amount" link, carried over verbatim from the legacy site
// (legacy/src/assets/js/main.js — handleCustomDonation).
const CUSTOM_DONATION_URL = 'https://don.o-k-i.net/b/6oE2aO94P88X9u8eV4';
let customOneTime = $state('');
let customMonthly = $state('');
function handleCustomDonation(amount: string) {
const value = Number(amount);
if (!amount || !Number.isFinite(value) || value < 1) {
alert('Please enter a valid amount');
return;
}
window.location.href = CUSTOM_DONATION_URL;
}
</script>
<Seo
title="Donate"
description="Support ORGANISATION KA INTERNATIONALE with a one-time or monthly donation through Stripe, Liberapay or Ko-fi."
path="/en/donate/"
locale="en"
/>
<section class="dons-hero">
<h1>{t.support.section_title} <span class="accent">{t.support.section_title_accent}</span></h1>
<p class="lede">{t.support.lede}</p>
<p class="lede-secondary">{t.support.lede_secondary}</p>
</section>
<section class="support">
<div class="support-inner">
<div class="donation-panels">
<div class="support-panel support-panel--primary">
<h2>
<svg class="icon" aria-hidden="true"><use href="/icons.svg#lakanmou" /></svg>
{t.support.one_time_title}
</h2>
<div class="donation-grid">
{#each donations.oneTime as d (d.url)}
<a href={d.url} class="donation-amount" target="_blank" rel="noopener noreferrer">
{d.amount}{t.support.one_time_suffix}
</a>
{/each}
</div>
<div class="custom-donation">
<label class="donation-form-label" for="customAmountOneTime">
{t.support.custom_amount_label}
</label>
<div class="custom-donation-form">
<input
type="number"
id="customAmountOneTime"
bind:value={customOneTime}
placeholder={t.support.custom_amount_placeholder}
min="1"
class="custom-amount-input"
/>
<span class="currency-symbol">{t.support.one_time_suffix}</span>
<button
type="button"
class="custom-donation-btn custom-donation-btn-primary"
onclick={() => handleCustomDonation(customOneTime)}
>
{t.support.custom_amount_btn}
</button>
</div>
</div>
</div>
<div class="support-panel support-panel--secondary">
<h2>{t.support.monthly_title}</h2>
<div class="donation-grid">
{#each donations.monthly as d (d.url)}
<a
href={d.url}
class="donation-amount monthly"
target="_blank"
rel="noopener noreferrer"
>
{d.amount}{t.support.monthly_suffix}
</a>
{/each}
</div>
<div class="custom-donation">
<label class="donation-form-label" for="customAmountMonthly">
{t.support.custom_monthly_label}
</label>
<div class="custom-donation-form">
<input
type="number"
id="customAmountMonthly"
bind:value={customMonthly}
placeholder={t.support.custom_amount_placeholder}
min="1"
class="custom-amount-input custom-amount-input-monthly"
/>
<span class="currency-symbol">{t.support.monthly_suffix}</span>
<button
type="button"
class="custom-donation-btn custom-donation-btn-secondary"
onclick={() => handleCustomDonation(customMonthly)}
>
{t.support.custom_monthly_btn}
</button>
</div>
</div>
</div>
</div>
<div class="alt-donation-section">
<h2 class="alt-donation-title">{t.support.alt_title}</h2>
<div class="alt-donation-grid">
<a
href={donations.liberapay}
target="_blank"
rel="noopener noreferrer"
class="alt-donation-card alt-donation-card--liberapay"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#jaden" /></svg
>
<h3>{t.support.liberapay_title}</h3>
<p>{t.support.liberapay_text}</p>
</a>
<a
href={donations.kofi}
target="_blank"
rel="noopener noreferrer"
class="alt-donation-card alt-donation-card--kofi"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#lakanmou" /></svg
>
<h3>{t.support.kofi_title}</h3>
<p>{t.support.kofi_text}</p>
</a>
</div>
</div>
<div class="security-note">
<!-- Editorial content from the i18n bundle (Stripe link), from the legacy site -->
<p>{@html t.support.security_stripe}</p>
<p>{t.support.security_alt}</p>
</div>
</div>
</section>
<style>
.dons-hero {
padding: 9rem var(--space-4) 3rem;
text-align: center;
border-bottom: 1px solid var(--line);
}
.dons-hero h1 {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: var(--space-2);
}
.accent {
color: var(--or-oki);
}
.lede {
max-width: 700px;
margin: 0 auto var(--space-2);
font-size: 1.2rem;
}
.lede-secondary {
max-width: 700px;
margin: 0 auto;
font-size: 1.05rem;
color: var(--muted);
}
.support {
padding: var(--space-5) var(--space-4);
background: var(--noir-profond);
text-align: center;
}
.support-inner {
max-width: 900px;
margin: 0 auto;
}
.support-panel {
background: var(--card-bg);
border: var(--border-card);
border-radius: var(--radius-md);
padding: var(--space-4);
margin-bottom: var(--space-4);
}
.support-panel h2 {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: var(--space-3);
font-size: 1.3rem;
}
.support-panel--primary {
border-top: 4px solid var(--or-oki);
}
.support-panel--primary h2 {
color: var(--or-oki);
}
.support-panel--secondary {
border-top: 4px solid var(--vert-oki);
}
.support-panel--secondary h2 {
color: var(--vert-oki);
}
.donation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.donation-amount {
display: flex;
align-items: center;
justify-content: center;
padding: 1.1rem;
background: color-mix(in srgb, var(--or-oki) 8%, transparent);
border: 2px solid var(--or-oki);
color: var(--blanc-creme);
border-radius: var(--radius-sm);
font-weight: 700;
font-size: 1.05rem;
transition:
background var(--dur-tanbou) var(--ease-ka),
color var(--dur-tanbou) var(--ease-ka),
transform var(--dur-tanbou) var(--ease-ka);
}
.donation-amount:hover {
background: var(--or-oki);
color: var(--noir-oki);
transform: translateY(-2px);
}
.donation-amount.monthly {
background: color-mix(in srgb, var(--vert-oki) 8%, transparent);
border-color: var(--vert-oki);
}
.donation-amount.monthly:hover {
background: var(--vert-oki);
color: var(--noir-oki);
}
.donation-form-label {
display: block;
margin-bottom: var(--space-2);
}
.custom-donation-form {
display: flex;
gap: 0.5rem;
justify-content: center;
align-items: center;
max-width: 350px;
margin: 0 auto;
padding: 0 var(--space-2);
}
.custom-amount-input {
padding: 0.8rem;
border: 2px solid var(--or-oki);
background: color-mix(in srgb, var(--blanc-creme) 5%, transparent);
color: var(--blanc-creme);
border-radius: var(--radius-sm);
flex: 1;
min-width: 0;
font-size: 1rem;
font-family: var(--font-body);
appearance: textfield;
-moz-appearance: textfield;
}
.custom-amount-input::-webkit-inner-spin-button,
.custom-amount-input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.custom-amount-input:focus {
outline: none;
background: color-mix(in srgb, var(--blanc-creme) 8%, transparent);
}
.custom-amount-input-monthly {
border-color: var(--vert-oki);
}
.currency-symbol {
white-space: nowrap;
flex-shrink: 0;
}
.custom-donation-btn {
padding: 0.8rem 1.2rem;
border: none;
border-radius: var(--radius-sm);
font-weight: 700;
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
font-family: var(--font-body);
font-size: 1rem;
transition: transform var(--dur-tanbou) var(--ease-ka);
}
.custom-donation-btn:hover {
transform: translateY(-2px);
}
.custom-donation-btn-primary {
background: var(--or-oki);
color: var(--noir-oki);
}
.custom-donation-btn-secondary {
background: var(--vert-oki);
color: var(--noir-oki);
}
.alt-donation-section {
margin-top: var(--space-4);
}
.alt-donation-title {
color: var(--or-oki);
margin-bottom: var(--space-4);
font-size: 1.3rem;
}
.alt-donation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--space-3);
max-width: 700px;
margin: 0 auto;
}
.alt-donation-card {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-1);
padding: var(--space-4);
background: var(--card-bg);
border: var(--border-card);
border-top: 3px solid var(--card-accent, var(--or-oki));
border-radius: var(--radius-md);
color: var(--blanc-creme);
transition: transform var(--dur-tanbou) var(--ease-ka);
}
.alt-donation-card:hover {
transform: translateY(-4px);
color: var(--blanc-creme);
}
.alt-donation-card--liberapay {
--card-accent: var(--vert-oki);
}
.alt-donation-card--kofi {
--card-accent: var(--or-oki);
}
.alt-donation-icon {
width: 2rem;
height: 2rem;
color: var(--card-accent, var(--or-oki));
}
.alt-donation-card h3 {
color: var(--card-accent, var(--or-oki));
font-size: 1.2rem;
}
.alt-donation-card p {
text-align: center;
font-size: 0.95rem;
}
.security-note {
margin-top: var(--space-4);
padding: var(--space-3);
background: var(--card-bg);
border-radius: var(--radius-md);
}
.security-note p {
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--muted);
}
@media (max-width: 480px) {
.custom-donation-form {
flex-direction: column;
}
.custom-amount-input,
.custom-donation-btn {
width: 100%;
}
}
</style>
+302
View File
@@ -0,0 +1,302 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import { getBundle } from '$lib/i18n';
const t = getBundle('en');
</script>
<Seo
title="Legal Notice"
description="Legal notice and legal information of ORGANISATION KA INTERNATIONALE (OKI) - Hosting, GDPR, AGPL-V3 license"
path="/en/legal-notice/"
locale="en"
/>
<section class="legal">
<div class="legal-inner">
<h1><span class="accent">Legal Notice</span></h1>
<!-- Website Presentation -->
<section class="legal-block legal-block--or">
<h2>1. Website Presentation</h2>
<p>
In accordance with applicable law, we hereby provide users of the website
<strong>o-k-i.net</strong> with the identity of the various parties involved in its
creation and management:
</p>
<ul class="legal-list">
<li>
<strong>Owner:</strong><br />
ORGANISATION KA INTERNATIONALE<br />
36 Rue Lethière, 97100 Basse-Terre
</li>
<li>
<strong>Publishing Manager:</strong><br />
ORGANISATION KA INTERNATIONALE<br />
Contact: <a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</li>
<li>
<strong>Webmaster:</strong><br />
Cédric FAMIBELLE-PRONZOLA<br />
Contact: <a href="mailto:contact@cedric-pronzola.dev">contact@cedric-pronzola.dev</a>
</li>
<li>
<strong>Hosting Provider:</strong><br />
o2switch<br />
222-224 Boulevard Gustave Flaubert, 63000 Clermont-Ferrand, France
</li>
<li>
<strong>Data Protection Officer:</strong><br />
ORGANISATION KA INTERNATIONALE<br />
Contact: <a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</li>
</ul>
</section>
<!-- Terms of Use -->
<section class="legal-block legal-block--vert">
<h2>2. Terms of Use of the Website and Services</h2>
<p>
The website is protected by intellectual property laws. Use of the website constitutes
full acceptance of the terms of use described below. These terms of use may be modified
or supplemented at any time.
</p>
<p>
Users of the website may not reuse or exploit the elements of the website without prior
authorization.
</p>
</section>
<!-- Description of Services -->
<section class="legal-block legal-block--rouge">
<h2>3. Description of Services Provided</h2>
<p>
The website <strong>o-k-i.net</strong> is intended to provide information about all
activities of ORGANISATION KA INTERNATIONALE.
</p>
<p>
ORGANISATION KA INTERNATIONALE strives to provide information that is as accurate as
possible. However, it cannot be held responsible for omissions, inaccuracies and
deficiencies in updates, whether due to its own actions or those of third-party partners
providing this information.
</p>
</section>
<!-- Technical Limitations -->
<section class="legal-block legal-block--or">
<h2>4. Technical Limitations</h2>
<p>
The website uses JavaScript technology. The site is hosted within the European Union in
compliance with GDPR.
</p>
<p>
ORGANISATION KA INTERNATIONALE cannot be held responsible for material damage related to
the use of the website. Furthermore, the website user agrees to access the site using
recent equipment, free from viruses, and with a current, up-to-date browser.
</p>
</section>
<!-- Intellectual Property and Licenses -->
<section class="legal-block legal-block--vert">
<h2>5. Intellectual Property and Licenses</h2>
<p>
The source code of the website <strong>o-k-i.net</strong> is distributed under the
<strong>GNU Affero General Public License v3.0 (AGPL-V3)</strong>, a free license that
guarantees the following freedoms:
</p>
<ul class="legal-disc">
<li>Freedom to use the software for any purpose</li>
<li>Freedom to study how the program works and adapt it</li>
<li>Freedom to redistribute copies</li>
<li>Freedom to improve the program and publish improvements</li>
</ul>
<p>
This license ensures that any modification to the source code must be published under the
same AGPL-V3 license. If you use this code to provide an online service, you must also
make the modified source code available to users of that service.
</p>
<p>
The full text of the license is available at:
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener noreferrer">
https://www.gnu.org/licenses/agpl-3.0.html
</a>
</p>
<p>
Original textual and visual content of the website (excluding source code) remains the
property of ORGANISATION KA INTERNATIONALE. Its use is subject to the conditions of the
AGPL-V3 license for technical elements, and requires authorization for other uses.
</p>
</section>
<!-- Limitations of Liability -->
<section class="legal-block legal-block--rouge">
<h2>6. Limitations of Liability</h2>
<p>
ORGANISATION KA INTERNATIONALE cannot be held responsible for direct or indirect damage
caused to the user's equipment, when accessing the website o-k-i.net, and resulting either
from the use of equipment not meeting the specifications indicated in section 4, or from
the occurrence of a bug or incompatibility.
</p>
<p>
ORGANISATION KA INTERNATIONALE cannot also be held responsible for indirect damage (such
as loss of market or loss of opportunity) resulting from the use of the website
o-k-i.net.
</p>
</section>
<!-- Personal Data Management -->
<section class="legal-block legal-block--or">
<h2>7. Personal Data Management</h2>
<p>
Personal data is protected in particular by European Regulation 2016/679 of April 27,
2016 relating to the protection of natural persons with regard to the processing of
personal data (GDPR).
</p>
<p>Personal data collected on the website o-k-i.net is processed for the following purposes:</p>
<ul class="legal-disc">
<li>Navigation on the website</li>
<li>Prevention of computer fraud</li>
<li>Improvement and optimization of navigation</li>
<li>Audience measurement and statistics</li>
</ul>
<p>
In application of these provisions, you have the right to access, rectify, delete and
transfer your personal data. You can exercise these rights by contacting:
<a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</p>
</section>
<!-- Incident Notification -->
<section class="legal-block legal-block--vert">
<h2>8. Incident Notification</h2>
<p>
Regardless of the efforts made, no method of transmission over the Internet and no method
of electronic storage is completely secure. We therefore cannot guarantee absolute
security.
</p>
<p>
If we became aware of a security breach, we would notify affected users so they can take
appropriate measures. Our incident notification procedures take into account our legal
obligations, whether at the national or European level. We undertake to fully inform our
customers of all security-related issues and to provide all necessary information to help
them meet their own regulatory reporting obligations.
</p>
<p>
Security measures in place include: firewalls, encryption, pseudonymization and physical
security measures.
</p>
</section>
<!-- Cookies and Web Beacons -->
<section class="legal-block legal-block--rouge">
<h2>9. Cookies and Web Beacons</h2>
<p>
The website may use cookies to enhance the user experience. Users can disable cookies in
their browser settings.
</p>
<p>
Some pages may contain web beacons (invisible pixels) to measure website traffic and
performance.
</p>
</section>
<!-- Applicable Law and Jurisdiction -->
<section class="legal-block legal-block--or">
<h2>10. Applicable Law and Jurisdiction</h2>
<p>
Any dispute related to the use of the website o-k-i.net is governed by French law. Except
where the law does not permit, exclusive jurisdiction is granted to the competent courts
of Guadeloupe.
</p>
</section>
<!-- Back to Home -->
<div class="legal-back">
<a href="/en/" class="btn btn-solid">{t.ui.back_home}</a>
</div>
</div>
</section>
<style>
.legal {
padding: 8rem var(--space-4) var(--space-5);
background: linear-gradient(135deg, var(--noir-profond) 0%, var(--gris-sombre) 100%);
}
.legal-inner {
max-width: 900px;
margin: 0 auto;
}
.legal h1 {
font-size: clamp(2rem, 5vw, 2.5rem);
margin-bottom: var(--space-4);
text-align: center;
}
.accent {
color: var(--or-oki);
}
.legal-block {
background: color-mix(in srgb, var(--block-accent) 10%, transparent);
border-left: 4px solid var(--block-accent);
padding: var(--space-4);
margin-bottom: var(--space-4);
border-radius: var(--radius-md);
}
.legal-block--or {
--block-accent: var(--or-oki);
}
.legal-block--vert {
--block-accent: var(--vert-oki);
}
.legal-block--rouge {
--block-accent: var(--rouge-oki);
}
.legal-block h2 {
color: var(--block-accent);
margin-bottom: var(--space-3);
font-size: clamp(1.3rem, 3vw, 1.8rem);
}
.legal-block p {
line-height: 1.6;
}
.legal-block p + p {
margin-top: var(--space-2);
}
.legal-list {
list-style: none;
margin: var(--space-3) 0;
}
.legal-list li {
margin-bottom: var(--space-2);
}
.legal-list strong {
color: var(--block-accent);
}
.legal-disc {
list-style: disc;
padding-left: var(--space-4);
margin: var(--space-2) 0;
}
.legal-disc li {
margin-bottom: 0.5rem;
}
.legal-back {
text-align: center;
margin-top: var(--space-4);
}
</style>
+252
View File
@@ -0,0 +1,252 @@
<script lang="ts">
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
import Seo from '$lib/components/Seo.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import { getBundle } from '$lib/i18n';
import sheToldMe from '$lib/assets/images/djangokam-she-told-me.webp?format=avif;webp&w=400;800&as=picture';
import iWantYouGirl from '$lib/assets/images/djangokam-i-want-you-girl.webp?format=avif;webp&w=400;800&as=picture';
import ishMwenKute from '$lib/assets/images/djangokam-ish-mwen-kute.jpg?format=avif;webp;jpg&w=400;800&as=picture';
const t = getBundle('en');
// Order aligned with t.press.visuals (i18n/en/press.json).
const pictures = [sheToldMe, iWantYouGirl, ishMwenKute];
</script>
<Seo
title="Press"
description="Press resources for DJANGOKAM, the first Caribbean AI artist produced by ORGANISATION KA INTERNATIONALE (OKI) — HD visuals and listening links."
path="/en/press/"
locale="en"
/>
<section class="press-hero">
<svg class="icon hero-icon" aria-hidden="true"><use href="/icons.svg#lambi" /></svg>
<h1>{t.press.title} <span class="accent">{t.press.title_accent}</span></h1>
<p class="press-lede">{t.press.lede}</p>
</section>
<section class="press-facts">
<div class="press-container">
<KineticText text={t.press.facts_title} as="h2" class="press-section-title" />
<div class="press-facts-list">
{#each t.press.facts as fact (fact.label)}
<div class="press-fact">
<span class="press-fact-label">{fact.label}</span>
<span>{fact.value}</span>
</div>
{/each}
</div>
</div>
</section>
<section class="press-visuals">
<div class="press-container">
<KineticText text={t.press.visuals_title} as="h2" class="press-section-title" />
<p class="press-visuals-intro">{t.press.visuals_intro}</p>
<div class="press-visual-grid">
{#each t.press.visuals as visual, i (visual.pdf)}
<div class="press-visual">
<a href={pictures[i].img.src} target="_blank" rel="noopener noreferrer">
<ResponsiveImage picture={pictures[i]} alt={visual.caption} loading="lazy" />
<span class="press-visual-caption">{visual.caption}</span>
</a>
<a href="/assets/press/{visual.pdf}" class="press-visual-pdf-link">
{t.press.visual_pdf_label}
</a>
</div>
{/each}
</div>
<div class="press-visuals-pdf">
<a href="/assets/press/{t.press.visuals_pdf_file}" class="btn btn-solid">
{t.press.visuals_pdf_label}
</a>
</div>
</div>
</section>
<section class="press-links">
<div class="press-container">
<KineticText text={t.press.links_title} as="h2" class="press-section-title" />
<div class="press-links-list">
{#each t.press.links as link (link.url)}
<a href={link.url} target="_blank" rel="noopener noreferrer">{link.text}</a>
{/each}
</div>
</div>
</section>
<section class="press-contact">
<div class="press-container">
<KineticText text={t.press.contact_title} as="h2" class="press-section-title" />
<p class="press-contact-text">{t.press.contact_text}</p>
<a href="mailto:{t.press.contact_email}" class="btn btn-solid">{t.press.contact_email}</a>
</div>
</section>
<style>
.press-hero {
padding: 9rem var(--space-4) 3rem;
text-align: center;
border-bottom: 1px solid var(--line);
}
.hero-icon {
width: 2.5rem;
height: 2.5rem;
margin: 0 auto var(--space-2);
color: var(--or-oki);
}
.press-hero h1 {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: var(--space-2);
}
.accent {
color: var(--or-oki);
}
.press-lede {
max-width: 700px;
margin: 0 auto;
font-size: 1.1rem;
line-height: 1.6;
color: var(--muted);
}
.press-container {
max-width: var(--container);
margin: 0 auto;
padding: 0 var(--space-4);
}
.press-facts,
.press-visuals,
.press-contact {
padding: var(--space-5) 0;
background: var(--noir-profond);
}
.press-links {
padding: var(--space-5) 0;
}
.press-contact {
padding-bottom: calc(var(--space-5) + var(--space-4));
text-align: center;
}
:global(.press-section-title) {
text-align: center;
font-size: clamp(1.75rem, 4vw, 2rem);
margin-bottom: var(--space-4);
}
.press-facts-list {
max-width: 800px;
margin: 0 auto;
display: grid;
gap: var(--space-2);
}
.press-fact {
display: grid;
grid-template-columns: 160px 1fr;
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--line);
}
.press-fact-label {
color: var(--or-oki);
font-weight: 700;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.press-visuals-intro {
text-align: center;
max-width: 700px;
margin: 0 auto var(--space-4);
color: var(--muted);
}
.press-visual-grid {
max-width: 1000px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: var(--space-3);
}
.press-visual a {
display: block;
color: inherit;
}
.press-visual :global(img) {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border-radius: var(--radius-md);
border: 1px solid var(--line);
}
.press-visual-caption {
display: block;
margin-top: 0.5rem;
font-size: 0.85rem;
color: var(--muted);
}
.press-visual-pdf-link {
display: inline-block;
margin-top: 0.5rem;
font-size: 0.8rem;
color: var(--or-oki);
border-bottom: 1px solid currentColor;
}
.press-visuals-pdf {
text-align: center;
margin-top: var(--space-4);
}
.press-links-list {
max-width: 600px;
margin: 0 auto;
display: grid;
gap: var(--space-1);
}
.press-links-list a {
display: block;
color: var(--blanc-creme);
padding: 0.9rem 1.25rem;
background: var(--card-bg);
border: var(--border-card);
border-left: 4px solid var(--vert-oki);
border-radius: var(--radius-md);
transition: border-color var(--dur-tanbou) var(--ease-ka);
}
.press-links-list a:hover {
border-color: var(--vert-oki);
}
.press-contact-text {
max-width: 600px;
margin: 0 auto var(--space-3);
color: var(--muted);
}
@media (max-width: 600px) {
.press-fact {
grid-template-columns: 1fr;
gap: 0.25rem;
}
}
</style>
+311
View File
@@ -0,0 +1,311 @@
<script lang="ts">
import Seo from '$lib/components/Seo.svelte';
import { getBundle } from '$lib/i18n';
const t = getBundle('fr');
</script>
<Seo
title="Mentions Légales"
description="Mentions légales et informations juridiques de l'ORGANISATION KA INTERNATIONALE (OKI) - Hébergement, RGPD, licence AGPL-V3"
path="/mentions-legales/"
locale="fr"
/>
<section class="legal">
<div class="legal-inner">
<h1><span class="accent">Mentions Légales</span></h1>
<!-- Présentation du site -->
<section class="legal-block legal-block--or">
<h2>1. Présentation du site</h2>
<p>
En vertu de l'article 6 de la loi n° 2004-575 du 21 juin 2004 pour la confiance dans
l'économie numérique, il est précisé aux utilisateurs du site internet
<strong>o-k-i.net</strong> l'identité des différents intervenants dans le cadre de sa
réalisation et de son suivi :
</p>
<ul class="legal-list">
<li>
<strong>Propriétaire :</strong><br />
ORGANISATION KA INTERNATIONALE<br />
36 Rue Lethière, 97100 Basse-Terre
</li>
<li>
<strong>Responsable publication :</strong><br />
ORGANISATION KA INTERNATIONALE<br />
Contact : <a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</li>
<li>
<strong>Webmaster :</strong><br />
Cédric FAMIBELLE-PRONZOLA<br />
Contact : <a href="mailto:contact@cedric-pronzola.dev">contact@cedric-pronzola.dev</a>
</li>
<li>
<strong>Hébergeur :</strong><br />
o2switch<br />
222-224 Boulevard Gustave Flaubert, 63000 Clermont-Ferrand
</li>
<li>
<strong>Délégué à la protection des données :</strong><br />
ORGANISATION KA INTERNATIONALE<br />
Contact : <a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</li>
</ul>
</section>
<!-- Conditions générales d'utilisation -->
<section class="legal-block legal-block--vert">
<h2>2. Conditions générales d'utilisation du site et des services proposés</h2>
<p>
Le site est protégé par les dispositions relatives à la propriété intellectuelle.
L'utilisation du site implique l'acceptation pleine et entière des conditions générales
d'utilisation ci-après décrites. Ces conditions d'utilisation sont susceptibles d'être
modifiées ou complétées à tout moment.
</p>
<p>
Les utilisateurs du site ne peuvent pas réutiliser ou exploiter les éléments du site sans
autorisation préalable.
</p>
</section>
<!-- Description des services -->
<section class="legal-block legal-block--rouge">
<h2>3. Description des services fournis</h2>
<p>
Le site <strong>o-k-i.net</strong> a pour objet de fournir une information concernant
l'ensemble des activités de l'ORGANISATION KA INTERNATIONALE.
</p>
<p>
ORGANISATION KA INTERNATIONALE s'efforce de fournir des informations aussi précises que
possible. Toutefois, il ne pourra être tenu responsable des oublis, des inexactitudes et
des carences dans la mise à jour, qu'elles soient de son fait ou du fait des tiers
partenaires qui lui fournissent ces informations.
</p>
</section>
<!-- Limitations techniques -->
<section class="legal-block legal-block--or">
<h2>4. Limitations techniques</h2>
<p>
Le site utilise la technologie JavaScript. Le site est hébergé dans l'Union Européenne
conformément au RGPD.
</p>
<p>
ORGANISATION KA INTERNATIONALE ne pourra être tenue responsable de dommages matériels liés
à l'utilisation du site. De plus, l'utilisateur du site s'engage à accéder au site en
utilisant un matériel récent, ne contenant pas de virus et avec un navigateur de dernière
génération mis à jour.
</p>
</section>
<!-- Propriété intellectuelle et licences -->
<section class="legal-block legal-block--vert">
<h2>5. Propriété intellectuelle et licences</h2>
<p>
Le code source du site <strong>o-k-i.net</strong> est distribué sous licence
<strong>GNU Affero General Public License v3.0 (AGPL-V3)</strong>, une licence libre qui
garantit les libertés suivantes :
</p>
<ul class="legal-disc">
<li>La liberté d'utiliser le logiciel à toute fin</li>
<li>La liberté d'étudier le fonctionnement du programme et de l'adapter</li>
<li>La liberté de redistribuer des copies</li>
<li>La liberté d'améliorer le programme et de publier ces améliorations</li>
</ul>
<p>
Cette licence garantit que toute modification du code source doit être publiée sous la
même licence AGPL-V3. Si vous utilisez ce code pour fournir un service en ligne, vous
devez également rendre le code source modifié disponible aux utilisateurs de ce service.
</p>
<p>
Le texte complet de la licence est disponible sur :
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener noreferrer">
https://www.gnu.org/licenses/agpl-3.0.html
</a>
</p>
<p>
Les contenus textuels et visuels originaux du site (hors code source) restent la propriété
de ORGANISATION KA INTERNATIONALE. Leur utilisation est soumise aux conditions de la
licence AGPL-V3 pour les éléments techniques, et requiert une autorisation pour les autres
usages.
</p>
</section>
<!-- Limitations de responsabilité -->
<section class="legal-block legal-block--rouge">
<h2>6. Limitations de responsabilité</h2>
<p>
ORGANISATION KA INTERNATIONALE ne pourra être tenue responsable des dommages directs et
indirects causés au matériel de l'utilisateur, lors de l'accès au site o-k-i.net, et
résultant soit de l'utilisation d'un matériel ne répondant pas aux spécifications
indiquées au point 4, soit de l'apparition d'un bug ou d'une incompatibilité.
</p>
<p>
ORGANISATION KA INTERNATIONALE ne pourra également être tenue responsable des dommages
indirects (tels par exemple qu'une perte de marché ou perte d'une chance) consécutifs à
l'utilisation du site o-k-i.net.
</p>
</section>
<!-- Gestion des données personnelles -->
<section class="legal-block legal-block--or">
<h2>7. Gestion des données personnelles</h2>
<p>
En France, les données personnelles sont notamment protégées par le Règlement européen
2016/679 du 27 avril 2016 relatif à la protection des personnes physiques à l'égard du
traitement des données à caractère personnel (RGPD).
</p>
<p>
Les données à caractère personnel recueillies sur le site o-k-i.net sont traitées pour les
finalités suivantes :
</p>
<ul class="legal-disc">
<li>Navigation sur le site</li>
<li>Prévention de la fraude informatique</li>
<li>Amélioration et optimisation de la navigation</li>
<li>Mesure d'audience et statistiques</li>
</ul>
<p>
En application de ces dispositions, vous disposez d'un droit d'accès, de rectification,
d'effacement et de portabilité de vos données personnelles. Vous pouvez exercer ces droits
en contactant : <a href="mailto:kontak@o-k-i.net">kontak@o-k-i.net</a>
</p>
</section>
<!-- Notification d'incident -->
<section class="legal-block legal-block--vert">
<h2>8. Notification d'incident</h2>
<p>
Quels que soient les efforts fournis, aucune méthode de transmission sur Internet et
aucune méthode de stockage électronique n'est complètement sûre. Nous ne pouvons en
conséquence pas garantir une sécurité absolue.
</p>
<p>
Si nous prenions connaissance d'une brèche de la sécurité, nous avertirions les
utilisateurs concernés afin qu'ils puissent prendre les mesures appropriées. Nos
procédures de notification d'incident tiennent compte de nos obligations légales, qu'elles
se situent au niveau national ou européen. Nous nous engageons à informer pleinement nos
clients de toutes les questions relevant de la sécurité de leur compte et à leur fournir
toutes les informations nécessaires pour les aider à respecter leurs propres obligations
réglementaires en matière de reporting.
</p>
<p>
Les systèmes de sécurité mis en place comprennent : pare-feu, chiffrement,
pseudonymisation et mesures de sécurité physiques.
</p>
</section>
<!-- Cookies -->
<section class="legal-block legal-block--rouge">
<h2>9. Cookies et balises web</h2>
<p>
Le site peut utiliser des cookies pour améliorer l'expérience utilisateur. L'utilisateur
peut désactiver les cookies dans les paramètres de son navigateur.
</p>
<p>
Certaines pages peuvent contenir des balises web (pixels invisibles) permettant notamment
de mesurer l'audience et la performance du site.
</p>
</section>
<!-- Droit applicable et juridiction -->
<section class="legal-block legal-block--or">
<h2>10. Droit applicable et juridiction compétente</h2>
<p>
Tout litige en relation avec l'utilisation du site o-k-i.net est soumis au droit français.
En dehors des cas où la loi ne le permet pas, il est fait attribution exclusive de
juridiction aux tribunaux compétents de Guadeloupe.
</p>
</section>
<!-- Retour à l'accueil -->
<div class="legal-back">
<a href="/" class="btn btn-solid">{t.ui.back_home}</a>
</div>
</div>
</section>
<style>
.legal {
padding: 8rem var(--space-4) var(--space-5);
background: linear-gradient(135deg, var(--noir-profond) 0%, var(--gris-sombre) 100%);
}
.legal-inner {
max-width: 900px;
margin: 0 auto;
}
.legal h1 {
font-size: clamp(2rem, 5vw, 2.5rem);
margin-bottom: var(--space-4);
text-align: center;
}
.accent {
color: var(--or-oki);
}
.legal-block {
background: color-mix(in srgb, var(--block-accent) 10%, transparent);
border-left: 4px solid var(--block-accent);
padding: var(--space-4);
margin-bottom: var(--space-4);
border-radius: var(--radius-md);
}
.legal-block--or {
--block-accent: var(--or-oki);
}
.legal-block--vert {
--block-accent: var(--vert-oki);
}
.legal-block--rouge {
--block-accent: var(--rouge-oki);
}
.legal-block h2 {
color: var(--block-accent);
margin-bottom: var(--space-3);
font-size: clamp(1.3rem, 3vw, 1.8rem);
}
.legal-block p {
line-height: 1.6;
}
.legal-block p + p {
margin-top: var(--space-2);
}
.legal-list {
list-style: none;
margin: var(--space-3) 0;
}
.legal-list li {
margin-bottom: var(--space-2);
}
.legal-list strong {
color: var(--block-accent);
}
.legal-disc {
list-style: disc;
padding-left: var(--space-4);
margin: var(--space-2) 0;
}
.legal-disc li {
margin-bottom: 0.5rem;
}
.legal-back {
text-align: center;
margin-top: var(--space-4);
}
</style>
+48
View File
@@ -0,0 +1,48 @@
<svelte:head>
<title>Hors ligne · ORGANISATION KA INTERNATIONALE</title>
<meta name="robots" content="noindex" />
</svelte:head>
<section class="offline-page container">
<svg class="icon offline-icon" aria-hidden="true"><use href="/icons.svg#lanme" /></svg>
<h1>Hors ligne</h1>
<p class="ka" lang="gcf">« Konèksyon an koupé. »</p>
<p class="fr">
Cette page n'est pas disponible hors connexion. Vous pourrez la consulter dès que la connexion sera
rétablie.
</p>
<p class="fr" lang="en">This page is not available offline. It will be back as soon as your connection is restored.</p>
<a class="btn" href="/">Retour à l'accueil</a>
</section>
<style>
.offline-page {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: var(--space-3);
padding: var(--space-5) var(--space-4);
}
.offline-icon {
width: 6rem;
height: 6rem;
color: var(--or-oki);
}
h1 {
font-weight: 900;
font-size: clamp(2.5rem, 8vw, 4.5rem);
}
.ka {
font-size: 1.25rem;
color: var(--or-oki);
}
.fr {
max-width: 52ch;
color: var(--muted);
}
</style>
+252
View File
@@ -0,0 +1,252 @@
<script lang="ts">
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
import Seo from '$lib/components/Seo.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import { getBundle } from '$lib/i18n';
import sheToldMe from '$lib/assets/images/djangokam-she-told-me.webp?format=avif;webp&w=400;800&as=picture';
import iWantYouGirl from '$lib/assets/images/djangokam-i-want-you-girl.webp?format=avif;webp&w=400;800&as=picture';
import ishMwenKute from '$lib/assets/images/djangokam-ish-mwen-kute.jpg?format=avif;webp;jpg&w=400;800&as=picture';
const t = getBundle('fr');
// Ordre aligné sur t.press.visuals (i18n/fr/press.json).
const pictures = [sheToldMe, iWantYouGirl, ishMwenKute];
</script>
<Seo
title="Presse"
description="Ressources presse pour DJANGOKAM, premier artiste IA caribéen produit par ORGANISATION KA INTERNATIONALE (OKI) — visuels HD et liens d'écoute."
path="/presse/"
locale="fr"
/>
<section class="press-hero">
<svg class="icon hero-icon" aria-hidden="true"><use href="/icons.svg#lambi" /></svg>
<h1>{t.press.title} <span class="accent">{t.press.title_accent}</span></h1>
<p class="press-lede">{t.press.lede}</p>
</section>
<section class="press-facts">
<div class="press-container">
<KineticText text={t.press.facts_title} as="h2" class="press-section-title" />
<div class="press-facts-list">
{#each t.press.facts as fact (fact.label)}
<div class="press-fact">
<span class="press-fact-label">{fact.label}</span>
<span>{fact.value}</span>
</div>
{/each}
</div>
</div>
</section>
<section class="press-visuals">
<div class="press-container">
<KineticText text={t.press.visuals_title} as="h2" class="press-section-title" />
<p class="press-visuals-intro">{t.press.visuals_intro}</p>
<div class="press-visual-grid">
{#each t.press.visuals as visual, i (visual.pdf)}
<div class="press-visual">
<a href={pictures[i].img.src} target="_blank" rel="noopener noreferrer">
<ResponsiveImage picture={pictures[i]} alt={visual.caption} loading="lazy" />
<span class="press-visual-caption">{visual.caption}</span>
</a>
<a href="/assets/press/{visual.pdf}" class="press-visual-pdf-link">
{t.press.visual_pdf_label}
</a>
</div>
{/each}
</div>
<div class="press-visuals-pdf">
<a href="/assets/press/{t.press.visuals_pdf_file}" class="btn btn-solid">
{t.press.visuals_pdf_label}
</a>
</div>
</div>
</section>
<section class="press-links">
<div class="press-container">
<KineticText text={t.press.links_title} as="h2" class="press-section-title" />
<div class="press-links-list">
{#each t.press.links as link (link.url)}
<a href={link.url} target="_blank" rel="noopener noreferrer">{link.text}</a>
{/each}
</div>
</div>
</section>
<section class="press-contact">
<div class="press-container">
<KineticText text={t.press.contact_title} as="h2" class="press-section-title" />
<p class="press-contact-text">{t.press.contact_text}</p>
<a href="mailto:{t.press.contact_email}" class="btn btn-solid">{t.press.contact_email}</a>
</div>
</section>
<style>
.press-hero {
padding: 9rem var(--space-4) 3rem;
text-align: center;
border-bottom: 1px solid var(--line);
}
.hero-icon {
width: 2.5rem;
height: 2.5rem;
margin: 0 auto var(--space-2);
color: var(--or-oki);
}
.press-hero h1 {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: var(--space-2);
}
.accent {
color: var(--or-oki);
}
.press-lede {
max-width: 700px;
margin: 0 auto;
font-size: 1.1rem;
line-height: 1.6;
color: var(--muted);
}
.press-container {
max-width: var(--container);
margin: 0 auto;
padding: 0 var(--space-4);
}
.press-facts,
.press-visuals,
.press-contact {
padding: var(--space-5) 0;
background: var(--noir-profond);
}
.press-links {
padding: var(--space-5) 0;
}
.press-contact {
padding-bottom: calc(var(--space-5) + var(--space-4));
text-align: center;
}
:global(.press-section-title) {
text-align: center;
font-size: clamp(1.75rem, 4vw, 2rem);
margin-bottom: var(--space-4);
}
.press-facts-list {
max-width: 800px;
margin: 0 auto;
display: grid;
gap: var(--space-2);
}
.press-fact {
display: grid;
grid-template-columns: 160px 1fr;
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--line);
}
.press-fact-label {
color: var(--or-oki);
font-weight: 700;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.press-visuals-intro {
text-align: center;
max-width: 700px;
margin: 0 auto var(--space-4);
color: var(--muted);
}
.press-visual-grid {
max-width: 1000px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: var(--space-3);
}
.press-visual a {
display: block;
color: inherit;
}
.press-visual :global(img) {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border-radius: var(--radius-md);
border: 1px solid var(--line);
}
.press-visual-caption {
display: block;
margin-top: 0.5rem;
font-size: 0.85rem;
color: var(--muted);
}
.press-visual-pdf-link {
display: inline-block;
margin-top: 0.5rem;
font-size: 0.8rem;
color: var(--or-oki);
border-bottom: 1px solid currentColor;
}
.press-visuals-pdf {
text-align: center;
margin-top: var(--space-4);
}
.press-links-list {
max-width: 600px;
margin: 0 auto;
display: grid;
gap: var(--space-1);
}
.press-links-list a {
display: block;
color: var(--blanc-creme);
padding: 0.9rem 1.25rem;
background: var(--card-bg);
border: var(--border-card);
border-left: 4px solid var(--vert-oki);
border-radius: var(--radius-md);
transition: border-color var(--dur-tanbou) var(--ease-ka);
}
.press-links-list a:hover {
border-color: var(--vert-oki);
}
.press-contact-text {
max-width: 600px;
margin: 0 auto var(--space-3);
color: var(--muted);
}
@media (max-width: 600px) {
.press-fact {
grid-template-columns: 1fr;
gap: 0.25rem;
}
}
</style>