diff --git a/src/components/cc-zone-card/cc-zone-card.js b/src/components/cc-zone-card/cc-zone-card.js
new file mode 100644
index 000000000..8c4ac1e66
--- /dev/null
+++ b/src/components/cc-zone-card/cc-zone-card.js
@@ -0,0 +1,184 @@
+import { css, html, LitElement } from 'lit';
+import { iconRemixCheckboxCircleFill as selectedIcon } from '../../assets/cc-remix.icons.js';
+import { i18n } from '../../translations/translation.js';
+import '../cc-icon/cc-icon.js';
+import '../cc-img/cc-img.js';
+
+/**
+ * @typedef {import('./cc-zone-card.types.js').ZoneImage} ZoneImage
+ */
+
+/**
+ * A component displaying a card with relative zone information (name, code...)
+ *
+ * @cssdisplay flex
+ */
+export class CcZoneCard extends LitElement {
+ static get properties() {
+ return {
+ code: { type: String },
+ country: { type: String },
+ countryCode: { type: String, attribute: 'country-code' },
+ disabled: { type: Boolean, reflect: true },
+ flagUrl: { type: String, attribute: 'flag-url' },
+ images: { type: Array },
+ name: { type: String },
+ selected: { type: Boolean, reflect: true },
+ };
+ }
+
+ constructor() {
+ super();
+
+ /** @type {string} The zone code */
+ this.code = null;
+
+ /** @type {string} The country name */
+ this.country = null;
+
+ /** @type {string} The ISO 3166-1 alpha-2 country code (e.g: FR) */
+ this.countryCode = null;
+
+ /** @type {boolean} Whether the card should be disabled */
+ this.disabled = false;
+
+ /** @type {string} The url of the flag image */
+ this.flagUrl = null;
+
+ /** @type {ZoneImage[]} A list of images that will displayed in the footer */
+ this.images = [];
+
+ /** @type {string} The name of the zone */
+ this.name = null;
+
+ /** @type {boolean} Whether the card should be selected */
+ this.selected = false;
+ }
+
+ render() {
+ return html`
+
+
${this.code}
+
${this.name}
+
+
+
+ ${this.flagUrl
+ ? html`
+
+ `
+ : ''}
+ ${this.images.map((image) => html``)}
+
+ `;
+ }
+
+ static get styles() {
+ return [
+ // language=CSS
+ css`
+ :host {
+ border: 2px solid var(--cc-color-border-neutral);
+ border-radius: var(--cc-border-radius-default);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ position: relative;
+ }
+
+ .title {
+ flex: 1 1 auto;
+ padding: 1em 1em 0.75em;
+ }
+
+ :host(:hover:not([disabled])) {
+ border-color: var(--cc-color-border-neutral-hovered);
+ }
+
+ :host(:not([selected], [disabled])) {
+ cursor: pointer;
+ }
+
+ :host([selected]) {
+ border-color: var(--cc-color-bg-primary);
+ }
+
+ :host([selected]) .title .zone-code {
+ color: var(--cc-color-text-primary-strong);
+ }
+
+ :host([selected]) .title .zone-name {
+ color: var(--cc-color-text-primary-strongest);
+ }
+
+ :host([selected]) .icon-selected {
+ display: block;
+ }
+
+ :host([selected]) .thumbnails {
+ background-color: var(--cc-color-bg-primary-weak);
+ }
+
+ :host([disabled]) {
+ border-color: var(--cc-color-border-neutral-disabled);
+ opacity: var(--cc-opacity-when-disabled);
+ }
+
+ :host([disabled]) .zone-code {
+ color: #fff;
+ }
+
+ :host([disabled]) .thumbnails cc-icon,
+ :host([disabled]) .thumbnails cc-img {
+ filter: grayscale(1);
+ }
+
+ .zone-code {
+ color: var(--cc-color-text-weak);
+ font-size: 0.875em;
+ line-height: 1.125;
+ padding-inline-start: 0.125em;
+ }
+
+ .zone-name {
+ font-size: 1.5em;
+ line-height: 1.125;
+ }
+
+ .icon-selected {
+ --cc-icon-color: var(--cc-color-bg-primary);
+
+ display: none;
+ position: absolute;
+ right: 0.5em;
+ top: 0.5em;
+ }
+
+ .thumbnails {
+ align-items: center;
+ background-color: var(--cc-color-bg-neutral);
+ display: inline-flex;
+ flex: 0 0 auto;
+ gap: 0.5em;
+ padding: 0.75em 1.125em;
+ }
+
+ .thumbnails > cc-img {
+ --cc-img-fit: contain;
+
+ height: 1.5em;
+ width: 1.5em;
+ }
+ `,
+ ];
+ }
+}
+
+window.customElements.define('cc-zone-card', CcZoneCard);
diff --git a/src/components/cc-zone-card/cc-zone-card.stories.js b/src/components/cc-zone-card/cc-zone-card.stories.js
new file mode 100644
index 000000000..fb28d72eb
--- /dev/null
+++ b/src/components/cc-zone-card/cc-zone-card.stories.js
@@ -0,0 +1,102 @@
+import { getFlagUrl } from '../../lib/remote-assets.js';
+import { makeStory } from '../../stories/lib/make-story.js';
+import './cc-zone-card.js';
+
+export default {
+ tags: ['autodocs'],
+ title: 'đź› Creation Tunnel/',
+ component: 'cc-zone-card',
+};
+
+const cleverIcon = new URL('../../stories/assets/clevercloud.svg', import.meta.url);
+
+const conf = {
+ component: 'cc-zone-card',
+};
+
+/**
+ * @typedef {import('./cc-zone-card.js').CcZoneCard} CcZoneCard
+ */
+
+/** @type {Partial} */
+const DEFAULT_ITEM = {
+ code: 'par',
+ name: 'Paris',
+ selected: false,
+ images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+};
+
+/** @type {Partial} */
+const LONG_CODE = {
+ code: 'very-very-very-very-very-very-very-long-code',
+ name: 'Zone',
+ selected: false,
+ images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+};
+
+/** @type {Partial} */
+const LONG_NAME = {
+ code: 'code',
+ name: 'very-very-very-very-very-very-very-long-name',
+ selected: false,
+ images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+};
+
+/** @type {Partial} */
+const LONG_CODE_AND_NAME = {
+ code: 'very-very-very-very-very-very-very-long-code',
+ name: 'very-very-very-very-very-very-very-long-name',
+ selected: false,
+ images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+};
+
+export const defaultStory = makeStory(conf, {
+ items: [DEFAULT_ITEM],
+});
+
+export const disabled = makeStory(conf, {
+ items: [{ ...DEFAULT_ITEM, disabled: true }],
+});
+
+export const selected = makeStory(conf, {
+ items: [{ ...DEFAULT_ITEM, selected: true }],
+});
+
+export const longCode = makeStory(conf, {
+ items: [
+ { ...LONG_CODE, style: 'width: 10em' },
+ { ...LONG_CODE, style: 'width: 20em' },
+ { ...LONG_CODE, style: 'width: 30em' },
+ LONG_CODE,
+ ],
+});
+
+export const longName = makeStory(conf, {
+ items: [
+ { ...LONG_NAME, style: 'width: 10em' },
+ { ...LONG_NAME, style: 'width: 20em' },
+ { ...LONG_NAME, style: 'width: 30em' },
+ LONG_NAME,
+ ],
+});
+
+export const longCodeAndLongName = makeStory(conf, {
+ items: [
+ { ...LONG_CODE_AND_NAME, style: 'width: 10em' },
+ { ...LONG_CODE_AND_NAME, style: 'width: 20em' },
+ { ...LONG_CODE_AND_NAME, style: 'width: 30em' },
+ LONG_CODE_AND_NAME,
+ ],
+});
diff --git a/src/components/cc-zone-card/cc-zone-card.test.js b/src/components/cc-zone-card/cc-zone-card.test.js
new file mode 100644
index 000000000..6999a7014
--- /dev/null
+++ b/src/components/cc-zone-card/cc-zone-card.test.js
@@ -0,0 +1,11 @@
+/* eslint-env node, mocha */
+
+import { testAccessibility } from '../../../test/helpers/accessibility.js';
+import { getStories } from '../../../test/helpers/get-stories.js';
+import * as storiesModule from './cc-zone-card.stories.js';
+
+const storiesToTest = getStories(storiesModule);
+
+describe(`Component: ${storiesModule.default.component}`, function () {
+ testAccessibility(storiesToTest);
+});
diff --git a/src/components/cc-zone-card/cc-zone-card.types.d.ts b/src/components/cc-zone-card/cc-zone-card.types.d.ts
new file mode 100644
index 000000000..a0cc62ccf
--- /dev/null
+++ b/src/components/cc-zone-card/cc-zone-card.types.d.ts
@@ -0,0 +1,4 @@
+export interface ZoneImage {
+ url: string | URL;
+ alt: string;
+}
diff --git a/src/components/cc-zone-picker/cc-zone-picker.js b/src/components/cc-zone-picker/cc-zone-picker.js
new file mode 100644
index 000000000..f71472695
--- /dev/null
+++ b/src/components/cc-zone-picker/cc-zone-picker.js
@@ -0,0 +1,184 @@
+import { css, html } from 'lit';
+import { CcFormControlElement } from '../../lib/form/cc-form-control-element.abstract.js';
+import { accessibilityStyles } from '../../styles/accessibility.js';
+import { i18n } from '../../translations/translation.js';
+import '../cc-zone-card/cc-zone-card.js';
+
+import { ifDefined } from 'lit/directives/if-defined.js';
+import { iconRemixEarthLine as zoneIcon } from '../../assets/cc-remix.icons.js';
+import { dispatchCustomEvent } from '../../lib/events.js';
+
+/**
+ * @typedef {import('./cc-zone-picker.types.js').ZoneItem} ZoneItem
+ * @typedef {import('./cc-zone-picker.types.js').ZoneSection} ZoneSection
+ * @typedef {import('./cc-zone-picker.types.js').SingleZoneSection} SingleZoneSection
+ * @typedef {import('./cc-zone-picker.types.js').ZonesSections} ZonesSections
+ * @typedef {import('../../lib/events.types.js').EventWithTarget} HTMLInputElementEvent
+ */
+
+/**
+ * A component that allows you to select a zone from a list of zones sections.
+ *
+ * @cssdisplay block
+ *
+ * @fires {CustomEvent} cc-zone-picker:input - Fires the zone code when a zone has been selected.
+ */
+export class CcZonePicker extends CcFormControlElement {
+ static get properties() {
+ return {
+ ...super.properties,
+ value: { type: String },
+ zonesSections: { type: Array, attribute: 'zones-sections' },
+ };
+ }
+
+ constructor() {
+ super();
+
+ /** @type {ZonesSections} array of zones sections */
+ this.zonesSections = [];
+
+ /** @type {string} current selected zone code */
+ this.value = null;
+ }
+
+ /**
+ * @param {HTMLInputElementEvent} e
+ */
+ _onZoneSelect(e) {
+ this.value = e.target.value;
+ dispatchCustomEvent(this, 'cc-zone-picker:input', e.target.value);
+ }
+
+ render() {
+ return html`
+
+ `;
+ }
+
+ /**
+ * @param {ZoneSection|SingleZoneSection} zoneSection
+ * @param {number} index
+ */
+ _renderZoneSection(zoneSection, index) {
+ const hasZoneSectionHeaderTitle = zoneSection != null && 'title' in zoneSection;
+ const zoneSectionHeaderId = hasZoneSectionHeaderTitle ? `section-header-${index}` : null;
+ return html`
+ ${hasZoneSectionHeaderTitle
+ ? html` `
+ : ''}
+
+ ${zoneSection.zones.map((zone) => this._renderZoneCard(zone, zone.code === this.value, zoneSectionHeaderId))}
+
+ `;
+ }
+
+ /**
+ * @param {ZoneItem} zone
+ * @param {boolean} isZoneSelected
+ * @param {string} zoneSectionHeaderId
+ */
+ _renderZoneCard(zone, isZoneSelected, zoneSectionHeaderId) {
+ return html`
+
+
+ `;
+ }
+
+ static get styles() {
+ return [
+ accessibilityStyles,
+ // language=CSS
+ css`
+ :host {
+ display: block;
+ /* We have to use px value because we change font-size value and we need the same margin for every other elements */
+ --fixed-margin: 34px;
+ }
+
+ legend {
+ display: flex;
+ gap: 0.25em;
+ }
+
+ .form-controls {
+ display: grid;
+ gap: 1em;
+ grid-template-columns: repeat(auto-fill, minmax(12.5em, 1fr));
+ margin-block-start: 0.5em;
+ margin-inline-start: var(--fixed-margin);
+ }
+
+ .zone-legend-icon {
+ --cc-icon-color: var(--cc-color-text-primary);
+
+ align-self: center;
+ }
+
+ .zone-legend-text {
+ color: var(--cc-color-text-primary-strongest);
+ font-family: var(--cc-ff-form-legend), inherit;
+ font-size: 1.625em;
+ font-weight: 500;
+ }
+
+ .zone-section-title {
+ color: var(--cc-color-text-primary-strongest);
+ font-family: var(--cc-ff-form-legend), inherit;
+ font-size: 1.15em;
+ margin-block-start: 1em;
+ margin-inline-start: var(--fixed-margin);
+ }
+
+ .form-controls + .zone-section-title {
+ margin-block-start: 2em;
+ }
+
+ fieldset {
+ border: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ cc-zone-card {
+ height: 100%;
+ }
+
+ input[type='radio']:focus-visible + label cc-zone-card {
+ border-radius: var(--cc-border-radius-default, 0.25em);
+ outline: var(--cc-focus-outline, #000 solid 2px);
+ outline-offset: var(--cc-focus-outline-offset, 2px);
+ }
+ `,
+ ];
+ }
+}
+
+window.customElements.define('cc-zone-picker', CcZonePicker);
diff --git a/src/components/cc-zone-picker/cc-zone-picker.stories.js b/src/components/cc-zone-picker/cc-zone-picker.stories.js
new file mode 100644
index 000000000..b703d9fec
--- /dev/null
+++ b/src/components/cc-zone-picker/cc-zone-picker.stories.js
@@ -0,0 +1,259 @@
+import { getFlagUrl } from '../../lib/remote-assets.js';
+import { makeStory } from '../../stories/lib/make-story.js';
+import './cc-zone-picker.js';
+
+const cleverIcon = new URL('../../stories/assets/clevercloud.svg', import.meta.url);
+const cloudTempleIcon = new URL('../../stories/assets/cloudtemple.svg', import.meta.url);
+const oracleIcon = new URL('../../stories/assets/oracle.svg', import.meta.url);
+const ovhIcon = new URL('../../stories/assets/ovh.svg', import.meta.url);
+const scalewayIcon = new URL('../../stories/assets/scaleway.svg', import.meta.url);
+
+export default {
+ tags: ['autodocs'],
+ title: 'đź› Creation Tunnel/',
+ component: 'cc-zone-picker',
+};
+
+const conf = {
+ component: 'cc-zone-picker',
+ // language=CSS
+ css: ``,
+};
+
+/**
+ * @typedef {import('./cc-zone-picker.js').CcZonePicker} CcZonePicker
+ * @typedef {import('./cc-zone-picker.types.js').ZoneItem} ZoneItem
+ * @typedef {import('./cc-zone-picker.types.js').ZoneSection} ZoneSection
+ */
+
+/** @type {ZoneItem[]} */
+const PUBLIC_ZONES = [
+ {
+ code: 'scw',
+ name: 'Paris',
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ images: [{ url: scalewayIcon, alt: 'infra' }],
+ disabled: false,
+ },
+ {
+ code: 'sgp',
+ name: 'Singapore',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('SG'),
+ countryCode: 'SG',
+ country: 'Singapore',
+ },
+ {
+ code: 'par',
+ name: 'Paris',
+ images: [{ url: cleverIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ },
+ {
+ code: 'grahds',
+ name: 'Gravelines',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ },
+ {
+ code: 'mtl',
+ name: 'Montreal',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('CA'),
+ countryCode: 'CA',
+ country: 'Canada',
+ },
+ {
+ code: 'syd',
+ name: 'Sydney',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('AU'),
+ countryCode: 'AU',
+ country: 'Australia',
+ },
+ {
+ code: 'rbx',
+ name: 'Roubaix',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ },
+ {
+ code: 'wsw',
+ name: 'Warsaw',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('PL'),
+ countryCode: 'PL',
+ country: 'Poland',
+ },
+ {
+ code: 'rbxhds',
+ name: 'Roubaix',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ },
+ {
+ code: 'fr-north-hds',
+ name: 'North',
+ images: [{ url: ovhIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ countryCode: 'FR',
+ country: 'France',
+ },
+];
+
+/** @type {ZoneItem[]} */
+const PRIVATE_ZONES = [
+ {
+ code: 'foo-foobars',
+ name: 'Private MySQL Cluster',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'Foo',
+ name: 'City Member Lab',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'foo5',
+ name: 'testing environment',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'foobarz',
+ name: 'Foobarz',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'foozbar',
+ name: 'Chips Dale Sound City',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'foobazbabarzone',
+ name: 'Sleep Edge Abroad Bird Random',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'champion',
+ name: 'Private MongoDB Cluster',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'ichipsndales-postgresql-internal',
+ name: 'Private PostgreSQL Cluster',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'mainstream',
+ name: 'Sleep Edge Abroad Bird Matrix',
+ images: [],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+];
+
+export const defaultStory = makeStory(conf, {
+ /** @type {Array>} */
+ items: [
+ {
+ zonesSections: [
+ {
+ zones: PUBLIC_ZONES,
+ },
+ ],
+ value: 'par',
+ },
+ ],
+});
+
+export const publicAndPrivateZones = makeStory(conf, {
+ /** @type {Array>} */
+ items: [
+ {
+ zonesSections: [
+ {
+ title: 'Private zones',
+ zones: PRIVATE_ZONES,
+ },
+ {
+ title: 'Public zones',
+ zones: PUBLIC_ZONES,
+ },
+ ],
+ },
+ ],
+});
+
+export const multipleSections = makeStory(conf, {
+ /** @type {Array>} */
+ items: [
+ {
+ zonesSections: [
+ {
+ title: 'Private zones',
+ zones: PRIVATE_ZONES,
+ },
+ {
+ title: 'Public zones',
+ zones: PUBLIC_ZONES,
+ },
+ {
+ title: 'Other section',
+ zones: [
+ {
+ code: 'other-zone',
+ name: 'Other Zone',
+ images: [{ url: oracleIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ {
+ code: 'other-zone-two',
+ name: 'Other Zone 2',
+ images: [{ url: cloudTempleIcon, alt: 'infra' }],
+ flagUrl: getFlagUrl('FR'),
+ country: 'France',
+ countryCode: 'FR',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+});
diff --git a/src/components/cc-zone-picker/cc-zone-picker.test.js b/src/components/cc-zone-picker/cc-zone-picker.test.js
new file mode 100644
index 000000000..b32fbe616
--- /dev/null
+++ b/src/components/cc-zone-picker/cc-zone-picker.test.js
@@ -0,0 +1,11 @@
+/* eslint-env node, mocha */
+
+import { testAccessibility } from '../../../test/helpers/accessibility.js';
+import { getStories } from '../../../test/helpers/get-stories.js';
+import * as storiesModule from './cc-zone-picker.stories.js';
+
+const storiesToTest = getStories(storiesModule);
+
+describe(`Component: ${storiesModule.default.component}`, function () {
+ testAccessibility(storiesToTest);
+});
diff --git a/src/components/cc-zone-picker/cc-zone-picker.types.d.ts b/src/components/cc-zone-picker/cc-zone-picker.types.d.ts
new file mode 100644
index 000000000..83b2e81a0
--- /dev/null
+++ b/src/components/cc-zone-picker/cc-zone-picker.types.d.ts
@@ -0,0 +1,23 @@
+import { ZoneImage } from '../cc-zone-card/cc-zone-card.types.js';
+
+export interface ZoneItem {
+ code: string;
+ country: string;
+ countryCode: string;
+ name: string;
+ flagUrl: string;
+ images: Array;
+ disabled?: boolean;
+ selected?: boolean;
+}
+
+export type ZonesSections = Array | [SingleZoneSection];
+
+export interface ZoneSection {
+ title: string;
+ zones: Array;
+}
+
+export interface SingleZoneSection {
+ zones: Array;
+}
diff --git a/src/stories/assets/clevercloud.svg b/src/stories/assets/clevercloud.svg
new file mode 100644
index 000000000..8c6a8c0f6
--- /dev/null
+++ b/src/stories/assets/clevercloud.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/src/stories/assets/cloudtemple.svg b/src/stories/assets/cloudtemple.svg
new file mode 100644
index 000000000..f273b1d4d
--- /dev/null
+++ b/src/stories/assets/cloudtemple.svg
@@ -0,0 +1,23 @@
+
diff --git a/src/stories/assets/oracle.svg b/src/stories/assets/oracle.svg
new file mode 100644
index 000000000..1e41072ff
--- /dev/null
+++ b/src/stories/assets/oracle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/stories/assets/ovh.svg b/src/stories/assets/ovh.svg
new file mode 100644
index 000000000..053aa36f0
--- /dev/null
+++ b/src/stories/assets/ovh.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/stories/assets/scaleway.svg b/src/stories/assets/scaleway.svg
new file mode 100644
index 000000000..2227f1be9
--- /dev/null
+++ b/src/stories/assets/scaleway.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/styles/default-theme.css b/src/styles/default-theme.css
index 70339ede6..021de5b16 100644
--- a/src/styles/default-theme.css
+++ b/src/styles/default-theme.css
@@ -1,4 +1,5 @@
:root {
+ --cc-ff-form-legend: 'Source Sans 3', sans-serif;
--cc-ff-monospace: 'SourceCodePro', 'monaco', monospace;
/* All custom properties are sorted alphabetically within each region. */
diff --git a/src/translations/translations.en.js b/src/translations/translations.en.js
index 0f33403e1..9c0bf5695 100644
--- a/src/translations/translations.en.js
+++ b/src/translations/translations.en.js
@@ -1284,8 +1284,15 @@ export const translations = {
'cc-zone.country': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
+ //#region cc-zone-card
+ 'cc-zone-card.alt.country-name': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
+ getCountryName(lang, code, name),
+ //#endregion
//#region cc-zone-input
'cc-zone-input.error': `Something went wrong while loading zones.`,
'cc-zone-input.private-map-warning': `Private zones don't appear on the map.`,
//#endregion
+ //#region cc-zone-picker
+ 'cc-zone-picker.legend': `Select your zone`,
+ //#endregion
};
diff --git a/src/translations/translations.fr.js b/src/translations/translations.fr.js
index 446fc0110..f52c51a01 100644
--- a/src/translations/translations.fr.js
+++ b/src/translations/translations.fr.js
@@ -1308,8 +1308,15 @@ export const translations = {
'cc-zone.country': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
+ //#region cc-zone-card
+ 'cc-zone-card.alt.country-name': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
+ getCountryName(lang, code, name),
+ //#endregion
//#region cc-zone-input
'cc-zone-input.error': `Une erreur est survenue pendant le chargement des zones.`,
'cc-zone-input.private-map-warning': `Les zones privées n'apparaissent pas sur la carte.`,
//#endregion
+ //#region cc-zone-picker
+ 'cc-zone-picker.legend': `SĂ©lectionnez votre zone`,
+ //#endregion
};