@edc-motor/ui 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +45 -0
  3. package/package.json +47 -0
  4. package/scss/_base.scss +33 -0
  5. package/scss/_forms.scss +33 -0
  6. package/scss/_shared-components.scss +1 -0
  7. package/scss/_theme.scss +74 -0
  8. package/scss/_tokens.scss +114 -0
  9. package/scss/components/_base-button.scss +113 -0
  10. package/scss/components/_blocks.scss +211 -0
  11. package/scss/components/_breadcrumbs.scss +31 -0
  12. package/scss/components/_checkbox.scss +42 -0
  13. package/scss/components/_chip.scss +23 -0
  14. package/scss/components/_confirm.scss +3 -0
  15. package/scss/components/_edit-modal.scss +11 -0
  16. package/scss/components/_font-upload.scss +91 -0
  17. package/scss/components/_form-field.scss +85 -0
  18. package/scss/components/_icon-button.scss +23 -0
  19. package/scss/components/_image-upload.scss +85 -0
  20. package/scss/components/_index.scss +24 -0
  21. package/scss/components/_locale-selector.scss +89 -0
  22. package/scss/components/_modal.scss +68 -0
  23. package/scss/components/_motor-badge.scss +21 -0
  24. package/scss/components/_numeric-input.scss +53 -0
  25. package/scss/components/_page-background.scss +22 -0
  26. package/scss/components/_palette-color-picker.scss +69 -0
  27. package/scss/components/_rich-text.scss +144 -0
  28. package/scss/components/_search-select.scss +138 -0
  29. package/scss/components/_tabs.scss +120 -0
  30. package/scss/components/_theme-selector.scss +34 -0
  31. package/scss/components/_toast-container.scss +16 -0
  32. package/scss/components/_toast.scss +25 -0
  33. package/scss/components/_translatable-input.scss +73 -0
  34. package/src/blocks/BlockCta.vue +32 -0
  35. package/src/blocks/BlockFaq.vue +25 -0
  36. package/src/blocks/BlockHeader.vue +13 -0
  37. package/src/blocks/BlockIndex.vue +20 -0
  38. package/src/blocks/BlockQuote.vue +16 -0
  39. package/src/blocks/BlockShell.vue +30 -0
  40. package/src/blocks/BlockText.vue +20 -0
  41. package/src/blocks/BlockTextCard.vue +23 -0
  42. package/src/blocks/PageBackground.vue +15 -0
  43. package/src/blocks/index.ts +25 -0
  44. package/src/components/AppBreadcrumbs.vue +44 -0
  45. package/src/components/BaseButton.vue +24 -0
  46. package/src/components/BaseCheckbox.vue +37 -0
  47. package/src/components/BaseInput.vue +53 -0
  48. package/src/components/BaseModal.vue +98 -0
  49. package/src/components/BaseSelect.vue +53 -0
  50. package/src/components/BaseTabs.vue +30 -0
  51. package/src/components/BaseTextarea.vue +45 -0
  52. package/src/components/BaseToast.vue +31 -0
  53. package/src/components/ConfirmDialog.vue +35 -0
  54. package/src/components/EditModal.vue +57 -0
  55. package/src/components/FontUpload.vue +123 -0
  56. package/src/components/IconButton.vue +24 -0
  57. package/src/components/ImageUpload.vue +142 -0
  58. package/src/components/LocaleSelector.vue +59 -0
  59. package/src/components/MotorBadge.vue +17 -0
  60. package/src/components/NumericInput.vue +115 -0
  61. package/src/components/PaletteColorPicker.vue +94 -0
  62. package/src/components/RichTextInput.vue +273 -0
  63. package/src/components/SearchSelect.vue +172 -0
  64. package/src/components/ThemeSelector.vue +28 -0
  65. package/src/components/ToastContainer.vue +23 -0
  66. package/src/components/TranslatableImage.vue +120 -0
  67. package/src/components/TranslatableInput.vue +135 -0
  68. package/src/composables/useConfirm.ts +49 -0
  69. package/src/composables/useHead.ts +54 -0
  70. package/src/composables/useTheme.ts +50 -0
  71. package/src/composables/useToast.ts +26 -0
  72. package/src/index.ts +39 -0
  73. package/src/lib/createApi.ts +42 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @edc-motor/ui
2
+
3
+ Componentes públicos de **EdC Motor** (Espadas de Ceniza Motor): la capa Vue 3
4
+ de la web pública de un juego de mesa construido sobre
5
+ [`edc-motor/core`](https://packagist.org/packages/edc-motor/core) — componentes
6
+ base (botones, formularios, modales, chips, migas…), tokens SCSS con temas
7
+ claro/oscuro, i18n, editor de texto rico (TipTap) y los composables del motor
8
+ (API, head/SEO, tema).
9
+
10
+ ## Instalación
11
+
12
+ ```bash
13
+ npm install @edc-motor/ui
14
+ ```
15
+
16
+ Es un **paquete fuente** (`main: src/index.ts`): lo compila la app consumidora
17
+ con Vite. El consumidor necesita:
18
+
19
+ ```bash
20
+ npm install -D vite @vitejs/plugin-vue sass-embedded typescript vue-tsc
21
+ ```
22
+
23
+ y en su `vite.config.ts`, los tokens SCSS del paquete en `loadPaths`:
24
+
25
+ ```ts
26
+ css: {
27
+ preprocessorOptions: {
28
+ scss: {
29
+ additionalData: '@use "tokens" as *;\n',
30
+ loadPaths: ['node_modules/@edc-motor/ui/scss'],
31
+ },
32
+ },
33
+ },
34
+ ```
35
+
36
+ ## Versionado
37
+
38
+ Versión *de tren* con `edc-motor/core` y `@edc-motor/admin-kit`: los tres
39
+ paquetes comparten número y se etiquetan juntos en el monorepo
40
+ [`bildurre/boardgame_motor`](https://github.com/bildurre/boardgame_motor),
41
+ donde viven el código, las guías, los issues y los pull requests.
42
+
43
+ ## Licencia
44
+
45
+ [GPL-3.0-only](LICENSE).
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@edc-motor/ui",
3
+ "version": "0.2.0",
4
+ "description": "EdC Motor — componentes públicos Vue 3 + tokens SCSS para webs de juegos de mesa (paquete fuente: lo compila el consumidor con Vite)",
5
+ "license": "GPL-3.0-only",
6
+ "type": "module",
7
+ "main": "src/index.ts",
8
+ "types": "src/index.ts",
9
+ "exports": {
10
+ ".": "./src/index.ts",
11
+ "./scss/*": "./scss/*"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "scss",
16
+ "LICENSE",
17
+ "README.md"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/bildurre/boardgame_motor.git",
22
+ "directory": "packages/ui"
23
+ },
24
+ "homepage": "https://github.com/bildurre/boardgame_motor/tree/main/packages/ui#readme",
25
+ "bugs": "https://github.com/bildurre/boardgame_motor/issues",
26
+ "keywords": [
27
+ "vue",
28
+ "boardgame",
29
+ "scss",
30
+ "edc-motor"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "dependencies": {
36
+ "axios": "^1.7.0",
37
+ "@tiptap/vue-3": "^2.11.0",
38
+ "@tiptap/starter-kit": "^2.11.0",
39
+ "@tiptap/extension-image": "^2.11.0",
40
+ "@tiptap/pm": "^2.11.0"
41
+ },
42
+ "peerDependencies": {
43
+ "vue": "^3.5.0",
44
+ "@lucide/vue": "^1.0.0",
45
+ "vue-router": "^5.0.0"
46
+ }
47
+ }
@@ -0,0 +1,33 @@
1
+ @use "tokens" as *;
2
+ // =========================================================
3
+ // Reset + base
4
+ // =========================================================
5
+
6
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
7
+
8
+ html {
9
+ font-size: 100%;
10
+ overflow-x: hidden;
11
+ -webkit-font-smoothing: antialiased;
12
+ -moz-osx-font-smoothing: grayscale;
13
+ }
14
+
15
+ body {
16
+ font-family: $k-font-sans;
17
+ font-size: $fs-14;
18
+ line-height: $k-lh-body;
19
+ color: $text-1;
20
+ background-color: $bg;
21
+ overflow-x: hidden;
22
+ max-width: 100vw;
23
+ min-height: 100vh;
24
+ }
25
+
26
+ #app { min-height: 100vh; max-width: 100%; }
27
+
28
+ h1, h2, h3, h4 { font-weight: $k-fw-semibold; line-height: $k-lh-tight; }
29
+ h1 { font-size: $fs-28; }
30
+ h2 { font-size: $fs-24; }
31
+ h3 { font-size: $fs-20; }
32
+
33
+ a { color: $accent-500; text-decoration: none; &:hover { color: $accent-600; } }
@@ -0,0 +1,33 @@
1
+ @use "tokens" as *;
2
+ // =========================================================
3
+ // Inputs y formularios genéricos
4
+ // =========================================================
5
+
6
+ .form { display: flex; flex-direction: column; gap: $space-4; }
7
+ .form-actions { margin-top: $space-2; display: flex; gap: $space-3; }
8
+
9
+ .field { display: flex; flex-direction: column; gap: $space-1; }
10
+ .field__label, .field label { font-size: $fs-13; color: $text-2; }
11
+
12
+ input[type="text"],
13
+ input[type="email"],
14
+ input[type="password"],
15
+ input[type="search"],
16
+ input[type="number"],
17
+ select,
18
+ textarea {
19
+ font: inherit;
20
+ width: 100%;
21
+ padding: 10px 12px;
22
+ background: $surface;
23
+ border: 1px solid $border;
24
+ border-radius: $radius-md;
25
+ color: $text-1;
26
+ &:hover { border-color: $border-strong; }
27
+ &:focus { outline: none; border-color: $accent-500; }
28
+ }
29
+ textarea { resize: vertical; }
30
+ input[type="color"] { width: 44px; height: 36px; padding: 2px; cursor: pointer; }
31
+
32
+ .error { color: $danger; margin: 0; }
33
+ .ok { color: $success; margin: 0; }
@@ -0,0 +1 @@
1
+ @use "components";
@@ -0,0 +1,74 @@
1
+ // =========================================================
2
+ // CSS Custom Properties (theming light/dark) — acento morado
3
+ // El <html> arranca en data-theme="dark" (identidad EdC).
4
+ // =========================================================
5
+
6
+ :root {
7
+ color-scheme: light;
8
+
9
+ --accent-100: #ece9fb;
10
+ --accent-200: #cdc7f7;
11
+ --accent-300: #a99ff2;
12
+ --accent-400: #8577ec;
13
+ --accent-500: #6c5ce7;
14
+ --accent-600: #5b4bd6;
15
+ --accent-700: #4c3cc4;
16
+
17
+ --info: #6c8cff;
18
+ --success: #4ade80;
19
+ --warning: #fbbf24;
20
+ --danger: #ff6b6b;
21
+
22
+ --bg: #fafafa;
23
+ --surface: #ffffff;
24
+ --surface-2: #f2f3f4;
25
+ --surface-3: #eaecf0;
26
+ --text-1: #101216;
27
+ --text-2: #636a77;
28
+ --text-3: #7b8290;
29
+ --border: #e2e3e7;
30
+ --border-strong: #cfd2d9;
31
+
32
+ --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.06);
33
+ --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.08);
34
+ --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.12);
35
+
36
+ --toast-success-bg: #ecfdf5;
37
+ --toast-warning-bg: #fffbeb;
38
+ --toast-danger-bg: #fef2f2;
39
+ --toast-info-bg: #eff6ff;
40
+
41
+ // CRM público (patrón CDL): el fondo de color de un bloque es un TINTE
42
+ // semitransparente del color elegido, y la imagen de fondo de la página
43
+ // va atenuada — en claro admiten más presencia que en oscuro.
44
+ --block-tint: 20%;
45
+ --page-bg-opacity: 0.2;
46
+ }
47
+
48
+ [data-theme="dark"] {
49
+ color-scheme: dark;
50
+
51
+ --accent-100: #1e1b2e;
52
+
53
+ --bg: #0f1115;
54
+ --surface: #1a1d24;
55
+ --surface-2: #20242d;
56
+ --surface-3: #2b2f3a;
57
+ --text-1: #e6e8ee;
58
+ --text-2: #9aa0ad;
59
+ --text-3: #7b8290;
60
+ --border: #2b2f3a;
61
+ --border-strong: #3a4150;
62
+
63
+ --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.30);
64
+ --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.35);
65
+ --shadow-lg: 0 18px 48px rgba(0, 0, 0, 0.45);
66
+
67
+ --toast-success-bg: #0d2818;
68
+ --toast-warning-bg: #2a2008;
69
+ --toast-danger-bg: #2a0e0e;
70
+ --toast-info-bg: #0e1a2e;
71
+
72
+ --block-tint: 12%;
73
+ --page-bg-opacity: 0.1;
74
+ }
@@ -0,0 +1,114 @@
1
+ // =========================================================
2
+ // EdC Tokens — adaptados de kontuan (acento morado)
3
+ // =========================================================
4
+
5
+ // Acento (CSS vars, ver _theme.scss) — un juego puede sobreescribirlas
6
+ $accent-100: var(--accent-100);
7
+ $accent-200: var(--accent-200);
8
+ $accent-300: var(--accent-300);
9
+ $accent-400: var(--accent-400);
10
+ $accent-500: var(--accent-500);
11
+ $accent-600: var(--accent-600);
12
+ $accent-700: var(--accent-700);
13
+
14
+ // Semánticos
15
+ $info: #6c8cff;
16
+ $success: #4ade80;
17
+ $warning: #fbbf24;
18
+ $danger: #ff6b6b;
19
+
20
+ // Neutros (CSS vars, themed)
21
+ $bg: var(--bg);
22
+ $surface: var(--surface);
23
+ $surface-2: var(--surface-2);
24
+ $surface-3: var(--surface-3);
25
+ $text-1: var(--text-1);
26
+ $text-2: var(--text-2);
27
+ $text-3: var(--text-3);
28
+ $border: var(--border);
29
+ $border-strong: var(--border-strong);
30
+
31
+ // Tipografía
32
+ $k-font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
33
+ $k-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
34
+ $k-fw-regular: 400;
35
+ $k-fw-medium: 500;
36
+ $k-fw-semibold: 600;
37
+ $k-fw-bold: 700;
38
+ $k-lh-tight: 1.15;
39
+ $k-lh-ui: 1.35;
40
+ $k-lh-body: 1.55;
41
+ $fs-11: 11px; $fs-12: 12px; $fs-13: 13px; $fs-14: 14px; $fs-16: 16px; $fs-18: 18px; $fs-20: 20px; $fs-24: 24px; $fs-28: 28px;
42
+
43
+ // Espaciado (px, como kontuan)
44
+ $space-0: 0;
45
+ $space-1: 4px;
46
+ $space-2: 8px;
47
+ $space-3: 12px;
48
+ $space-4: 16px;
49
+ $space-5: 20px;
50
+ $space-6: 24px;
51
+ $space-7: 28px;
52
+ $space-8: 32px;
53
+
54
+ // Radios
55
+ $radius-sm: 6px;
56
+ $radius-md: 10px;
57
+ $radius-lg: 14px;
58
+ $radius-xl: 18px;
59
+ $radius-pill: 999px;
60
+
61
+ // Estados UI (hover, etc.)
62
+ $ui-hover-bg: $surface-2;
63
+ $ui-hover-bg-strong: $surface-3;
64
+
65
+ // Tracking (letter-spacing)
66
+ $k-track-wide: 0.02em;
67
+
68
+ // Layout (igual que kontuan)
69
+ $layout-sidebar-width: 280px;
70
+ $layout-content-max: 1400px;
71
+ $layout-page-padding: 24px;
72
+
73
+ // Iconos (Lucide)
74
+ $icon-stroke: 1.75;
75
+
76
+ // Breakpoints (mobile-first, min-width)
77
+ $bp-xs: 360px;
78
+ $bp-sm: 480px;
79
+ $bp-md: 768px;
80
+ $bp-lg: 1024px;
81
+ $bp-xl: 1280px;
82
+
83
+ // ---------------------------------------------------------
84
+ // Alias de compatibilidad (nombres antiguos -> tokens kontuan)
85
+ // para no reescribir cada propiedad de los componentes ya hechos.
86
+ // ---------------------------------------------------------
87
+ $color-bg: $bg;
88
+ $color-surface: $surface;
89
+ $color-border: $border;
90
+ $color-text: $text-1;
91
+ $color-text-muted: $text-2;
92
+ $color-accent: $accent-500;
93
+ $color-accent-dark: $accent-600;
94
+ $font-sans: $k-font-sans;
95
+
96
+ // Sombras (CSS vars)
97
+ $shadow-sm: var(--shadow-sm);
98
+ $shadow-md: var(--shadow-md);
99
+ $shadow-lg: var(--shadow-lg);
100
+
101
+ // Formularios (elementos estilo kontuan)
102
+ $focus-ring: 0 0 0 3px color-mix(in srgb, #{$accent-500} 25%, transparent);
103
+ $disabled-opacity: 0.45;
104
+ $input-height: 40px;
105
+ $input-padding-x: 12px;
106
+ $input-padding-y: 10px;
107
+ $input-radius: $radius-md;
108
+ $input-bg: $surface-2;
109
+ $input-text: $text-1;
110
+ $input-placeholder: $text-3;
111
+ $input-border: $border;
112
+ $input-border-hover: $border-strong;
113
+ $input-border-focus: $accent-500;
114
+ $input-focus-ring: $focus-ring;
@@ -0,0 +1,113 @@
1
+ @use "tokens" as *;
2
+
3
+ .edc-button {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: $space-2;
8
+ padding: $space-2 $space-4;
9
+ border: 1px solid transparent;
10
+ border-radius: $radius-md;
11
+ font: inherit;
12
+ font-weight: 600;
13
+ cursor: pointer;
14
+ transition: background-color 0.15s ease, border-color 0.15s ease;
15
+
16
+ &:disabled {
17
+ opacity: 0.55;
18
+ cursor: not-allowed;
19
+ pointer-events: none;
20
+ }
21
+
22
+ &__icon {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ flex-shrink: 0;
26
+ }
27
+
28
+ &__text {
29
+ display: inline-flex;
30
+ align-items: center;
31
+ gap: $space-2;
32
+ line-height: 1.2;
33
+ }
34
+
35
+ // Con slot de icono (patrón kontuan): fila por defecto en todas partes;
36
+ // SOLO cuando el contenedor `content` (el área de contenido) es estrecho,
37
+ // el texto pasa a mini-etiqueta bajo el icono.
38
+ &--has-icon:not(.edc-button--text):not(.edc-button--text-danger) {
39
+ @container content (max-width: #{$bp-sm - 1px}) {
40
+ flex-direction: column;
41
+ gap: 2px;
42
+ padding: $space-1 $space-2;
43
+
44
+ .edc-button__text {
45
+ font-size: 10px;
46
+ line-height: 1;
47
+ }
48
+ }
49
+ }
50
+
51
+ &--primary {
52
+ background: $color-accent;
53
+ color: #fff;
54
+
55
+ // Hover bien visible: accent-600 apenas se distingue del 500.
56
+ &:hover:not(:disabled) {
57
+ background: color-mix(in srgb, $color-accent 72%, black);
58
+ }
59
+ }
60
+
61
+ &--secondary {
62
+ background: transparent;
63
+ border-color: $color-border;
64
+ color: $color-text;
65
+
66
+ &:hover:not(:disabled) {
67
+ background: color-mix(in srgb, $color-accent 14%, transparent);
68
+ border-color: $color-accent;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Botón tipo TEXTO (kontuan): sin fondo, sin borde ni padding; solo color.
74
+ .edc-button--text {
75
+ background: transparent;
76
+ border-color: transparent;
77
+ padding: 0;
78
+ color: $accent-500;
79
+
80
+ &:hover:not(:disabled) { color: $accent-700; background: transparent; }
81
+ }
82
+ .edc-button--text-danger {
83
+ background: transparent;
84
+ border-color: transparent;
85
+ padding: 0;
86
+ color: $danger;
87
+
88
+ &:hover:not(:disabled) {
89
+ color: color-mix(in srgb, $danger 80%, black);
90
+ background: transparent;
91
+ }
92
+ }
93
+
94
+ .edc-button--danger {
95
+ background: $danger;
96
+ color: #fff;
97
+ &:hover:not(:disabled) { background: color-mix(in srgb, $danger 72%, black); }
98
+ }
99
+ .edc-button--success {
100
+ background: $success;
101
+ color: #06281a;
102
+ &:hover:not(:disabled) { background: color-mix(in srgb, $success 72%, black); }
103
+ }
104
+ .edc-button--info {
105
+ background: $info;
106
+ color: #fff;
107
+ &:hover:not(:disabled) { background: color-mix(in srgb, $info 72%, black); }
108
+ }
109
+ .edc-button--warning {
110
+ background: $warning;
111
+ color: #2b2005;
112
+ &:hover:not(:disabled) { background: color-mix(in srgb, $warning 72%, black); }
113
+ }
@@ -0,0 +1,211 @@
1
+ @use "tokens" as *;
2
+
3
+ // Bloques públicos del CRM (doc 03): estilos base, cada juego los ajusta.
4
+ .block {
5
+ // Aire vertical entre bloques (CDL usa 4rem; aquí algo más contenido).
6
+ padding-block: $space-8 + $space-6; // 56px
7
+ background: var(--block-bg, transparent);
8
+
9
+ &__inner {
10
+ max-width: 960px; // 'wide' (por defecto)
11
+ margin: 0 auto;
12
+ padding: 0 $space-4;
13
+ display: grid;
14
+ gap: $space-5; // separación entre los elementos del bloque
15
+ }
16
+
17
+ // Anchura del contenido (campo común `width`): coherente entre bloques.
18
+ &--w-narrow .block__inner { max-width: 680px; }
19
+ &--w-full .block__inner { max-width: none; padding-inline: $space-6; }
20
+
21
+ &__title { margin: 0; }
22
+ &__subtitle { margin: 0; color: $text-2; font-size: $fs-18; }
23
+ &__text { color: $text-1; }
24
+
25
+ &__label {
26
+ display: inline-block;
27
+ justify-self: start;
28
+ font-size: $fs-12;
29
+ font-weight: $k-fw-semibold;
30
+ text-transform: uppercase;
31
+ letter-spacing: 0.05em;
32
+ color: $accent-500;
33
+ border: 1px solid color-mix(in srgb, $accent-500 45%, transparent);
34
+ border-radius: $radius-pill;
35
+ padding: 2px $space-3;
36
+ }
37
+
38
+ &__card {
39
+ // Semitransparente: la imagen de fondo de la página se ve a través
40
+ // (patrón CDL, rgba(surface, .5)); el blur mantiene el texto legible.
41
+ background: color-mix(in srgb, $surface 65%, transparent);
42
+ backdrop-filter: blur(8px);
43
+ border: 1px solid $border;
44
+ border-radius: $radius-lg;
45
+ box-shadow: $shadow-sm;
46
+ padding: $space-8;
47
+ display: grid;
48
+ gap: $space-4;
49
+
50
+ .edc-button { justify-self: start; text-decoration: none; }
51
+ }
52
+
53
+ &--header .block__title { font-size: $fs-28; }
54
+
55
+ &__media-layout { display: grid; gap: $space-4; }
56
+ &__image {
57
+ max-width: 100%;
58
+ border-radius: $radius-md;
59
+ justify-self: center;
60
+ }
61
+
62
+ &--image-left .block__media-layout,
63
+ &--image-right .block__media-layout {
64
+ @container content (min-width: #{$bp-sm}) {
65
+ grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
66
+ align-items: start;
67
+ }
68
+ }
69
+ &--image-right .block__media-layout .block__image { order: 2; }
70
+ &--image-bottom .block__media-layout .block__image { order: 2; }
71
+
72
+ // Imagen flotada: el texto la rodea y sigue por debajo (cleartext, como
73
+ // CDL). En estrecho la imagen va arriba a lo ancho, sin flotar.
74
+ &--image-clear-left .block__media-layout,
75
+ &--image-clear-right .block__media-layout {
76
+ display: block;
77
+
78
+ // Clearfix: el bloque no se corta si la imagen es más alta que el texto.
79
+ &::after { content: ""; display: table; clear: both; }
80
+
81
+ .block__image { margin-bottom: $space-3; }
82
+ }
83
+ &--image-clear-left .block__media-layout .block__image {
84
+ @container content (min-width: #{$bp-sm}) {
85
+ float: left;
86
+ max-width: 50%;
87
+ margin-right: $space-4;
88
+ }
89
+ }
90
+ &--image-clear-right .block__media-layout .block__image {
91
+ @container content (min-width: #{$bp-sm}) {
92
+ float: right;
93
+ max-width: 50%;
94
+ margin-left: $space-4;
95
+ }
96
+ }
97
+
98
+ // Banner de la cabecera (a lo ancho del bloque).
99
+ &__banner {
100
+ width: 100%;
101
+ border-radius: $radius-md;
102
+ }
103
+
104
+ // Retrato del autor de la cita.
105
+ &__avatar {
106
+ width: 64px;
107
+ height: 64px;
108
+ border-radius: 50%;
109
+ object-fit: cover;
110
+ margin-bottom: $space-2;
111
+ }
112
+
113
+ // Cuerpo del CTA (texto + botón) dentro de su media-layout.
114
+ &__cta-body {
115
+ display: grid;
116
+ gap: $space-3;
117
+ justify-items: start;
118
+ }
119
+
120
+ &--quote .block__quote {
121
+ margin: 0;
122
+ border-left: 3px solid $accent-500;
123
+ padding-left: $space-4;
124
+ // Fuente "especial" de la configuración de la web (doc 10); las fuentes
125
+ // decorativas piden un cuerpo mayor.
126
+ font-family: var(--font-special, inherit);
127
+ font-size: $fs-24;
128
+ font-style: italic;
129
+ }
130
+ &__author {
131
+ margin-top: $space-2;
132
+ color: $text-3;
133
+ // El autor no hereda la fuente especial de la cita.
134
+ font-family: var(--font-body, inherit);
135
+ font-style: normal;
136
+ font-size: $fs-14;
137
+ }
138
+ }
139
+
140
+ .block__index {
141
+ margin: 0;
142
+ padding-left: 1.2em;
143
+ display: grid;
144
+ gap: $space-1;
145
+
146
+ a { color: $accent-500; text-decoration: none; }
147
+ a:hover { text-decoration: underline; }
148
+ }
149
+
150
+ // FAQ (doc 03): acordeón nativo details/summary del bloque `faq`.
151
+ .block__faq-item {
152
+ border: 1px solid $border;
153
+ border-radius: $radius-md;
154
+ background: color-mix(in srgb, $surface 65%, transparent);
155
+
156
+ & + & { margin-top: $space-2; }
157
+
158
+ &[open] .block__faq-question { color: $accent-500; }
159
+ }
160
+
161
+ .block__faq-question {
162
+ padding: $space-3 $space-4;
163
+ font-weight: 600;
164
+ cursor: pointer;
165
+
166
+ &:hover { color: $accent-500; }
167
+ }
168
+
169
+ .block__faq-answer {
170
+ padding: 0 $space-4 $space-3;
171
+ color: $text-2;
172
+ }
173
+
174
+
175
+ // Botón de los bloques (CTA, doc 03): dos tipos con hover CRUZADO.
176
+ // Normal: fondo de acento + texto del color del texto; al pasar, fondo del
177
+ // color de fondo + texto de acento. Inverso: exactamente al revés.
178
+ .block-button {
179
+ display: inline-flex;
180
+ align-items: center;
181
+ gap: $space-2;
182
+ padding: $space-2 $space-5;
183
+ border: 1px solid $accent-500;
184
+ border-radius: $radius-md;
185
+ font-weight: 600;
186
+ text-decoration: none;
187
+ cursor: pointer;
188
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
189
+
190
+ // El "fondo" de los estados cruzados es la SUPERFICIE ($surface, el
191
+ // segundo tono), no el fondo de página puro: menos negro / menos blanco.
192
+ &--primary {
193
+ background: $accent-500;
194
+ color: $text-1;
195
+
196
+ &:hover {
197
+ background: $surface;
198
+ color: $accent-500;
199
+ }
200
+ }
201
+
202
+ &--secondary {
203
+ background: $surface;
204
+ color: $accent-500;
205
+
206
+ &:hover {
207
+ background: $accent-500;
208
+ color: $text-1;
209
+ }
210
+ }
211
+ }
@@ -0,0 +1,31 @@
1
+ @use "tokens" as *;
2
+
3
+ .breadcrumbs {
4
+ display: flex;
5
+ align-items: center;
6
+ flex-wrap: wrap;
7
+ column-gap: 2px;
8
+ font-size: $fs-12;
9
+ color: $text-3;
10
+ margin-bottom: $space-8; // aire doble entre la miga y el contenido
11
+ }
12
+
13
+ .breadcrumb-link {
14
+ color: $text-3;
15
+ text-decoration: none;
16
+ transition: color 0.15s ease;
17
+
18
+ &:hover {
19
+ color: $text-1;
20
+ }
21
+ }
22
+
23
+ .breadcrumb-current {
24
+ color: $text-1;
25
+ font-weight: $k-fw-medium;
26
+ }
27
+
28
+ .breadcrumb-separator {
29
+ color: $text-3;
30
+ flex-shrink: 0;
31
+ }