ds-tis 1.0.0-beta.10

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 (79) hide show
  1. package/LICENSE +49 -0
  2. package/README.md +125 -0
  3. package/css/base/forced-colors.css +62 -0
  4. package/css/base/icons.css +73 -0
  5. package/css/base/index.css +4 -0
  6. package/css/base/reset.css +80 -0
  7. package/css/base/typography.css +211 -0
  8. package/css/components/accordion.css +153 -0
  9. package/css/components/alert.css +161 -0
  10. package/css/components/avatar.css +76 -0
  11. package/css/components/badge.css +83 -0
  12. package/css/components/breadcrumb.css +58 -0
  13. package/css/components/button.css +364 -0
  14. package/css/components/card.css +159 -0
  15. package/css/components/checkbox.css +296 -0
  16. package/css/components/combobox.css +330 -0
  17. package/css/components/divider.css +20 -0
  18. package/css/components/form-field.css +137 -0
  19. package/css/components/index.css +28 -0
  20. package/css/components/input.css +356 -0
  21. package/css/components/link.css +67 -0
  22. package/css/components/menu.css +246 -0
  23. package/css/components/modal.css +236 -0
  24. package/css/components/pagination.css +132 -0
  25. package/css/components/radio.css +280 -0
  26. package/css/components/select.css +399 -0
  27. package/css/components/skeleton.css +52 -0
  28. package/css/components/spinner.css +59 -0
  29. package/css/components/tabs.css +79 -0
  30. package/css/components/textarea.css +218 -0
  31. package/css/components/toggle.css +202 -0
  32. package/css/components/tooltip.css +116 -0
  33. package/css/design-system.css +13 -0
  34. package/css/tokens/generated/component.css +720 -0
  35. package/css/tokens/generated/foundation.css +282 -0
  36. package/css/tokens/generated/index.css +5 -0
  37. package/css/tokens/generated/theme-dark.css +243 -0
  38. package/css/tokens/generated/theme-light.css +244 -0
  39. package/css/tokens/index.css +6 -0
  40. package/css/utilities/elevation.css +24 -0
  41. package/css/utilities/index.css +2 -0
  42. package/css/utilities/layout.css +132 -0
  43. package/docs/agent-consumer-usage.en.md +322 -0
  44. package/docs/agent-consumer-usage.md +294 -0
  45. package/docs/api/adrs.json +186 -0
  46. package/docs/api/components.json +2071 -0
  47. package/docs/api/consumer-context.json +66 -0
  48. package/docs/api/foundations.json +94 -0
  49. package/docs/api/tokens.json +6839 -0
  50. package/docs/llms-full.txt +23699 -0
  51. package/docs/llms.txt +109 -0
  52. package/docs/templates/contact.html +364 -0
  53. package/docs/templates/dashboard.html +318 -0
  54. package/docs/templates/index.html +232 -0
  55. package/docs/templates/login.html +286 -0
  56. package/docs/templates/settings.html +365 -0
  57. package/docs/templates/signup.html +350 -0
  58. package/js/accordion.js +192 -0
  59. package/js/combobox.js +263 -0
  60. package/js/menu.js +301 -0
  61. package/js/modal.js +256 -0
  62. package/js/package.json +3 -0
  63. package/js/tabs.js +200 -0
  64. package/js/theme/apply.js +75 -0
  65. package/js/theme/brand-contrast-audit.js +133 -0
  66. package/js/theme/color.js +149 -0
  67. package/js/theme/config-schema.js +40 -0
  68. package/js/theme/contrast.js +76 -0
  69. package/js/theme/export.js +118 -0
  70. package/js/theme/index.js +21 -0
  71. package/js/theme/overlay.js +29 -0
  72. package/js/theme/package.json +3 -0
  73. package/js/theme/palette.js +103 -0
  74. package/js/theme/radius.js +76 -0
  75. package/js/theme/semantic-mapper.js +138 -0
  76. package/js/theme/typography.js +33 -0
  77. package/js/theme/url-state.js +52 -0
  78. package/js/tooltip.js +227 -0
  79. package/package.json +139 -0
@@ -0,0 +1,137 @@
1
+ /* ============================================================
2
+ COMPONENT: Form Field — wrapper composite pra Input/Select/Textarea/etc
3
+
4
+ ⚠ CSS-ONLY (ADR-017): Form Field NÃO existe no Figma e NÃO deve ser
5
+ authorado lá. Componentes Figma de form (Input Text, Select, Textarea,
6
+ Checkbox, Radio, Toggle) já carregam Label + Required + Helper Text +
7
+ Description inline em cada variant. Form Field só existe no CSS porque
8
+ HTML não tem elemento "form control" composto — precisamos compor
9
+ <label> + control + helper + error com IDs e ARIA. Auditorias Figma↔Repo
10
+ devem ignorar este componente como "faltando no Figma".
11
+
12
+ Junta os 5 elementos que precisam estar visualmente alinhados E
13
+ acessivelmente conectados:
14
+
15
+ 1. Label .ds-field__label (com `for=` apontando pra controle)
16
+ 2. Required indicator .ds-field__required (asterisco, decorativo)
17
+ 3. Controle Input/Select/Textarea/Checkbox group
18
+ 4. Helper text .ds-field__helper (com aria-describedby no controle)
19
+ 5. Error message .ds-field__error (ícone + texto, aparece em estado --error)
20
+
21
+ HTML structure:
22
+ <div class="ds-field">
23
+ <div class="ds-field__label-row">
24
+ <label class="ds-field__label" for="field-id">Nome</label>
25
+ <span class="ds-field__required" aria-hidden="true">*</span>
26
+ </div>
27
+ <div class="ds-input">
28
+ <input class="ds-input__field" id="field-id"
29
+ aria-required="true"
30
+ aria-describedby="field-id-helper">
31
+ </div>
32
+ <span class="ds-field__helper" id="field-id-helper">Texto auxiliar</span>
33
+ <span class="ds-field__error" id="field-id-error" role="alert">Mensagem de erro</span>
34
+ </div>
35
+
36
+ Accessibility (WCAG 2.2):
37
+ - Label tem `for=` apontando pro `id` do controle (1.3.1, 3.3.2)
38
+ - Required → `aria-required="true"` no controle + asterisco visual com aria-hidden
39
+ - Helper text → `aria-describedby` no controle apontando pro `id` do helper
40
+ - Error → set `aria-invalid="true"` no controle + `aria-describedby` aponta pro error
41
+ - Show Label=false → use `aria-label` direto no controle E `.ds-field--no-label`
42
+ ============================================================ */
43
+
44
+ /* Wrapper: stacks label row, control, helper, error verticalmente */
45
+ .ds-field {
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: var(--ds-form-field-gap-default);
49
+ width: 100%;
50
+ }
51
+
52
+ /* Label row: label text + optional required asterisk (horizontal, gap 2px) */
53
+ .ds-field__label-row {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: var(--ds-form-field-label-row-gap-default);
57
+ }
58
+
59
+ /* Label text (body/sm: 14px bold / 20px) */
60
+ .ds-field__label {
61
+ font-size: var(--ds-form-field-label-font-size-default);
62
+ font-weight: var(--ds-body-font-weight-bold);
63
+ line-height: var(--ds-form-field-label-line-height-default);
64
+ color: var(--ds-form-field-label-color-default);
65
+ }
66
+
67
+ /* Required asterisk — error text color, decorative (aria-hidden no markup) */
68
+ .ds-field__required {
69
+ font-size: var(--ds-form-field-required-font-size-default);
70
+ font-weight: var(--ds-body-font-weight-bold);
71
+ line-height: var(--ds-form-field-required-line-height-default);
72
+ color: var(--ds-form-field-required-color-default);
73
+ user-select: none;
74
+ }
75
+
76
+ /* Helper text (12px regular / 18px) */
77
+ .ds-field__helper {
78
+ font-size: var(--ds-body-font-size-xs);
79
+ font-weight: var(--ds-body-font-weight-regular);
80
+ line-height: var(--ds-body-line-height-xs);
81
+ color: var(--ds-form-field-helper-color-default);
82
+ }
83
+
84
+ /* Error message (default hidden; mostrado em .ds-field--error) */
85
+ .ds-field__error {
86
+ display: none;
87
+ align-items: flex-start;
88
+ gap: var(--ds-form-field-error-gap-default);
89
+ font-size: var(--ds-form-field-error-font-size-default);
90
+ font-weight: var(--ds-form-field-error-font-weight-default);
91
+ line-height: var(--ds-form-field-error-line-height-default);
92
+ padding-top: var(--ds-form-field-error-padding-top-default);
93
+ color: var(--ds-form-field-error-color-default);
94
+ }
95
+
96
+ .ds-field__error::before {
97
+ --_ds-field-error-icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='8' x2='12' y2='12'/%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'/%3E%3C/svg%3E");
98
+
99
+ content: "";
100
+ display: inline-flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ box-sizing: content-box;
104
+ flex: 0 0 calc(
105
+ var(--ds-form-field-error-icon-size-default) +
106
+ var(--ds-form-field-error-icon-frame-padding-x-default) +
107
+ var(--ds-form-field-error-icon-frame-padding-x-default)
108
+ );
109
+ width: var(--ds-form-field-error-icon-size-default);
110
+ height: var(--ds-form-field-error-icon-size-default);
111
+ padding-left: var(--ds-form-field-error-icon-frame-padding-x-default);
112
+ padding-right: var(--ds-form-field-error-icon-frame-padding-x-default);
113
+ color: var(--ds-form-field-error-icon-color-default);
114
+ background-color: currentColor;
115
+ -webkit-mask: var(--_ds-field-error-icon-mask) center / var(--ds-form-field-error-icon-size-default) var(--ds-form-field-error-icon-size-default) no-repeat;
116
+ mask: var(--_ds-field-error-icon-mask) center / var(--ds-form-field-error-icon-size-default) var(--ds-form-field-error-icon-size-default) no-repeat;
117
+ user-select: none;
118
+ }
119
+
120
+ /* ---------------------------------------------------------
121
+ Modifiers
122
+ --------------------------------------------------------- */
123
+
124
+ /* Hide label row (use aria-label no controle pra a11y) */
125
+ .ds-field--no-label .ds-field__label-row {
126
+ display: none;
127
+ }
128
+
129
+ /* Hide helper text */
130
+ .ds-field--no-helper .ds-field__helper {
131
+ display: none;
132
+ }
133
+
134
+ /* Error state — mostra error message; label permanece neutra. */
135
+ .ds-field--error .ds-field__error {
136
+ display: inline-flex;
137
+ }
@@ -0,0 +1,28 @@
1
+ /* ==========================================================================
2
+ Components
3
+ ========================================================================== */
4
+
5
+ @import 'button.css';
6
+ @import 'form-field.css';
7
+ @import 'input.css';
8
+ @import 'textarea.css';
9
+ @import 'select.css';
10
+ @import 'combobox.css';
11
+ @import 'checkbox.css';
12
+ @import 'radio.css';
13
+ @import 'toggle.css';
14
+ @import 'badge.css';
15
+ @import 'alert.css';
16
+ @import 'accordion.css';
17
+ @import 'card.css';
18
+ @import 'modal.css';
19
+ @import 'tooltip.css';
20
+ @import 'menu.css';
21
+ @import 'tabs.css';
22
+ @import 'breadcrumb.css';
23
+ @import 'pagination.css';
24
+ @import 'avatar.css';
25
+ @import 'divider.css';
26
+ @import 'spinner.css';
27
+ @import 'skeleton.css';
28
+ @import 'link.css';
@@ -0,0 +1,356 @@
1
+ /* ==========================================================================
2
+ Input – .ds-input — aligned with Figma specs
3
+ Sizes: sm=32px, md=40px, lg=48px
4
+ ========================================================================== */
5
+
6
+ /* Wrapper
7
+ ========================================================================== */
8
+
9
+ .ds-input {
10
+ --input-padding-x: var(--ds-input-padding-x-md);
11
+ --input-padding-y: var(--ds-field-padding-y-md);
12
+ --input-gap: var(--ds-input-gap-md);
13
+ --input-icon-frame-size: var(--ds-input-icon-size-md);
14
+ --input-border-width: var(--ds-field-border-width);
15
+
16
+ display: flex;
17
+ align-items: center;
18
+ gap: var(--ds-input-gap-md);
19
+ border: var(--ds-field-border-width) solid var(--ds-field-border-color-default);
20
+ border-radius: var(--ds-field-radius);
21
+ background: var(--ds-field-bg-default);
22
+ color: var(--ds-field-value-color-default);
23
+ font-family: var(--ds-input-text-font-family-default);
24
+ font-weight: var(--ds-input-text-font-weight-default);
25
+ letter-spacing: var(--ds-input-text-letter-spacing-default);
26
+ transition: border-color var(--ds-motion-duration-fast) var(--ds-motion-ease-default),
27
+ box-shadow var(--ds-motion-duration-fast) var(--ds-motion-ease-default);
28
+ }
29
+
30
+ /* Sizes
31
+ ========================================================================== */
32
+
33
+ .ds-input,
34
+ .ds-input--md {
35
+ height: var(--ds-input-height-md);
36
+ padding: var(--ds-field-padding-y-md) var(--ds-input-padding-x-md);
37
+ font-size: var(--ds-input-text-font-size-md);
38
+ line-height: var(--ds-input-text-line-height-md);
39
+ }
40
+
41
+ .ds-input--sm {
42
+ --input-padding-x: var(--ds-input-padding-x-sm);
43
+ --input-padding-y: var(--ds-field-padding-y-sm);
44
+ --input-gap: var(--ds-input-gap-sm);
45
+ --input-icon-frame-size: var(--ds-input-icon-size-sm);
46
+
47
+ height: var(--ds-input-height-sm);
48
+ gap: var(--ds-input-gap-sm);
49
+ padding: var(--ds-field-padding-y-sm) var(--ds-input-padding-x-sm);
50
+ font-size: var(--ds-input-text-font-size-sm);
51
+ line-height: var(--ds-input-text-line-height-sm);
52
+ }
53
+
54
+ .ds-input--lg {
55
+ --input-padding-x: var(--ds-input-padding-x-lg);
56
+ --input-padding-y: var(--ds-field-padding-y-lg);
57
+ --input-gap: var(--ds-input-gap-lg);
58
+ --input-icon-frame-size: var(--ds-input-icon-size-lg);
59
+
60
+ height: var(--ds-input-height-lg);
61
+ gap: var(--ds-input-gap-lg);
62
+ padding: var(--ds-field-padding-y-lg) var(--ds-input-padding-x-lg);
63
+ font-size: var(--ds-input-text-font-size-lg);
64
+ line-height: var(--ds-input-text-line-height-lg);
65
+ }
66
+
67
+ /* Field
68
+ ========================================================================== */
69
+
70
+ .ds-input__field {
71
+ --input-field-leading-size: 0px;
72
+ --input-field-leading-gap: 0px;
73
+ --input-field-trailing-size: 0px;
74
+ --input-field-trailing-gap: 0px;
75
+
76
+ flex: 1;
77
+ align-self: stretch;
78
+ border: none;
79
+ background: transparent;
80
+ outline: none;
81
+ color: var(--ds-field-value-color-default);
82
+ font-size: inherit;
83
+ font-family: inherit;
84
+ font-weight: inherit;
85
+ letter-spacing: inherit;
86
+ line-height: inherit;
87
+ min-width: 0;
88
+ margin-top: calc(-1 * (var(--input-padding-y) + var(--input-border-width)));
89
+ margin-bottom: calc(-1 * (var(--input-padding-y) + var(--input-border-width)));
90
+ margin-left: calc(
91
+ -1 * (
92
+ var(--input-padding-x) +
93
+ var(--input-border-width) +
94
+ var(--input-field-leading-size) +
95
+ var(--input-field-leading-gap)
96
+ )
97
+ );
98
+ margin-right: calc(-1 * (var(--input-padding-x) + var(--input-border-width)));
99
+ padding-left: calc(
100
+ var(--input-padding-x) +
101
+ var(--input-border-width) +
102
+ var(--input-field-leading-size) +
103
+ var(--input-field-leading-gap) +
104
+ var(--ds-input-text-frame-padding-x-default)
105
+ );
106
+ padding-right: calc(
107
+ var(--input-padding-x) +
108
+ var(--input-border-width) +
109
+ var(--input-field-trailing-size) +
110
+ var(--input-field-trailing-gap) +
111
+ var(--ds-input-text-frame-padding-x-default)
112
+ );
113
+ }
114
+
115
+ .ds-input__icon + .ds-input__field {
116
+ --input-field-leading-size: calc(
117
+ var(--input-icon-frame-size) +
118
+ var(--ds-input-icon-frame-padding-x-default) +
119
+ var(--ds-input-icon-frame-padding-x-default)
120
+ );
121
+ --input-field-leading-gap: var(--input-gap);
122
+ }
123
+
124
+ .ds-input__field:has(+ .ds-input__icon) {
125
+ --input-field-trailing-size: calc(
126
+ var(--input-icon-frame-size) +
127
+ var(--ds-input-icon-frame-padding-x-default) +
128
+ var(--ds-input-icon-frame-padding-x-default)
129
+ );
130
+ --input-field-trailing-gap: var(--input-gap);
131
+ margin-right: calc(
132
+ -1 * (
133
+ var(--input-padding-x) +
134
+ var(--input-border-width) +
135
+ var(--input-field-trailing-size) +
136
+ var(--input-field-trailing-gap)
137
+ )
138
+ );
139
+ }
140
+
141
+ .ds-input__field::placeholder {
142
+ color: var(--ds-field-placeholder-color-default);
143
+ }
144
+
145
+ /* Icon
146
+ ========================================================================== */
147
+
148
+ /* Icon container: wrapper externo com respiro horizontal; ícone interno escala por tamanho. */
149
+ .ds-input__icon {
150
+ flex-shrink: 0;
151
+ color: var(--ds-input-icon-color-default);
152
+ fill: none;
153
+ stroke: currentColor;
154
+ stroke-width: var(--ds-input-icon-stroke-width-md);
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ box-sizing: content-box;
159
+ width: var(--ds-input-icon-size-md);
160
+ height: var(--ds-input-icon-size-md);
161
+ padding-left: var(--ds-input-icon-frame-padding-x-default);
162
+ padding-right: var(--ds-input-icon-frame-padding-x-default);
163
+ font-size: var(--ds-input-icon-size-md);
164
+ line-height: 1;
165
+ pointer-events: none;
166
+ }
167
+
168
+ .ds-input--sm .ds-input__icon {
169
+ width: var(--ds-input-icon-size-sm);
170
+ height: var(--ds-input-icon-size-sm);
171
+ font-size: var(--ds-input-icon-size-sm);
172
+ stroke-width: var(--ds-input-icon-stroke-width-sm);
173
+ }
174
+
175
+ .ds-input--lg .ds-input__icon {
176
+ width: var(--ds-input-icon-size-lg);
177
+ height: var(--ds-input-icon-size-lg);
178
+ font-size: var(--ds-input-icon-size-lg);
179
+ stroke-width: var(--ds-input-icon-stroke-width-lg);
180
+ }
181
+
182
+ /* States
183
+ ========================================================================== */
184
+
185
+ /* Hover */
186
+ .ds-input:hover:not(.ds-input--disabled):not(:focus-within) {
187
+ border-color: var(--ds-field-border-color-hover);
188
+ }
189
+
190
+ /* Focused */
191
+ .ds-input:focus-within {
192
+ background: var(--ds-field-bg-default);
193
+ border-color: var(--ds-field-border-color-focus);
194
+ border-radius: var(--ds-field-radius);
195
+ outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color-default);
196
+ outline-offset: var(--ds-focus-ring-width);
197
+ }
198
+
199
+ /* Error */
200
+ .ds-input--error,
201
+ .ds-field--error .ds-input {
202
+ background: var(--ds-field-bg-default);
203
+ border-color: var(--ds-field-border-color-error);
204
+ }
205
+
206
+ .ds-input--error:hover:not(.ds-input--disabled):not(:focus-within),
207
+ .ds-field--error .ds-input:hover:not(.ds-input--disabled):not(:focus-within) {
208
+ background: var(--ds-field-bg-default);
209
+ border-color: var(--ds-field-border-color-error-hover);
210
+ }
211
+
212
+ .ds-input--error:focus-within,
213
+ .ds-field--error .ds-input:focus-within {
214
+ border-color: var(--ds-field-border-color-error);
215
+ outline-color: var(--ds-focus-ring-color-error);
216
+ }
217
+
218
+ /* Filled */
219
+ .ds-input--filled {
220
+ background: var(--ds-field-bg-default);
221
+ border-color: var(--ds-field-border-color-filled);
222
+ }
223
+
224
+ .ds-input--filled.ds-input--error,
225
+ .ds-field--error .ds-input--filled {
226
+ background: var(--ds-field-bg-default);
227
+ border-color: var(--ds-field-border-color-error);
228
+ }
229
+
230
+ .ds-input--filled.ds-input--error:hover:not(.ds-input--disabled):not(:focus-within),
231
+ .ds-field--error .ds-input--filled:hover:not(.ds-input--disabled):not(:focus-within) {
232
+ background: var(--ds-field-bg-default);
233
+ border-color: var(--ds-field-border-color-error-hover);
234
+ }
235
+
236
+ /* Disabled */
237
+ .ds-input--disabled,
238
+ .ds-input:has(.ds-input__field:disabled) {
239
+ background: var(--ds-field-bg-disabled);
240
+ border-color: var(--ds-field-border-color-disabled);
241
+ color: var(--ds-field-value-color-disabled);
242
+ pointer-events: none;
243
+ }
244
+
245
+ .ds-input--disabled .ds-input__field,
246
+ .ds-input__field:disabled {
247
+ color: var(--ds-field-value-color-disabled);
248
+ }
249
+
250
+ .ds-input--disabled .ds-input__field::placeholder,
251
+ .ds-input__field:disabled::placeholder {
252
+ color: var(--ds-field-placeholder-color-disabled);
253
+ }
254
+
255
+ .ds-input--disabled .ds-input__icon,
256
+ .ds-input:has(.ds-input__field:disabled) .ds-input__icon {
257
+ color: var(--ds-input-icon-color-disabled);
258
+ }
259
+
260
+ /* Readonly */
261
+ .ds-input--readonly,
262
+ .ds-input:has(.ds-input__field:read-only) {
263
+ background: var(--ds-field-bg-readonly);
264
+ border-color: var(--ds-field-border-color-readonly);
265
+ }
266
+
267
+ .ds-input--readonly .ds-input__field,
268
+ .ds-input__field:read-only {
269
+ color: var(--ds-field-value-color-readonly);
270
+ }
271
+
272
+ .ds-input--readonly:focus-within,
273
+ .ds-input:has(.ds-input__field:read-only):focus-within {
274
+ background: var(--ds-field-bg-readonly);
275
+ border-color: var(--ds-field-border-color-readonly);
276
+ outline-color: var(--ds-focus-ring-color-readonly);
277
+ }
278
+
279
+ /* Composed field anatomy
280
+ ========================================================================== */
281
+
282
+ .ds-field:has(.ds-input) {
283
+ gap: var(--ds-form-field-stack-gap-default);
284
+ }
285
+
286
+ .ds-field:has(.ds-input) .ds-field__label-row {
287
+ gap: var(--ds-form-field-label-row-gap-default);
288
+ }
289
+
290
+ .ds-field:has(.ds-input) .ds-field__label {
291
+ color: var(--ds-form-field-label-color-default);
292
+ font-family: var(--ds-form-field-label-font-family-default);
293
+ font-size: var(--ds-form-field-label-font-size-default);
294
+ font-weight: var(--ds-body-font-weight-bold);
295
+ letter-spacing: var(--ds-body-letter-spacing-normal);
296
+ line-height: var(--ds-form-field-label-line-height-default);
297
+ }
298
+
299
+ .ds-field:has(.ds-input--sm) .ds-field__label {
300
+ font-size: var(--ds-form-field-label-font-size-default);
301
+ line-height: var(--ds-form-field-label-line-height-default);
302
+ }
303
+
304
+ .ds-field:has(.ds-input--lg) .ds-field__label {
305
+ font-size: var(--ds-form-field-label-font-size-default);
306
+ line-height: var(--ds-form-field-label-line-height-default);
307
+ }
308
+
309
+ .ds-field:has(.ds-input) .ds-field__required {
310
+ color: var(--ds-form-field-required-color-default);
311
+ font-family: var(--ds-form-field-required-font-family-default);
312
+ font-size: var(--ds-form-field-required-font-size-default);
313
+ font-weight: var(--ds-body-font-weight-bold);
314
+ letter-spacing: var(--ds-body-letter-spacing-normal);
315
+ line-height: var(--ds-form-field-required-line-height-default);
316
+ }
317
+
318
+ .ds-field:has(.ds-input) .ds-field__helper {
319
+ color: var(--ds-form-field-helper-color-default);
320
+ font-family: var(--ds-form-field-label-font-family-default);
321
+ font-size: var(--ds-body-font-size-xs);
322
+ font-weight: var(--ds-body-font-weight-regular);
323
+ letter-spacing: var(--ds-body-letter-spacing-normal);
324
+ line-height: var(--ds-body-line-height-xs);
325
+ }
326
+
327
+ .ds-field--error:has(.ds-input) .ds-field__label {
328
+ color: var(--ds-form-field-label-color-default);
329
+ }
330
+
331
+ .ds-field:has(.ds-input--disabled) .ds-field__label,
332
+ .ds-field:has(.ds-input__field:disabled) .ds-field__label {
333
+ color: var(--ds-form-field-label-color-disabled);
334
+ }
335
+
336
+ .ds-field:has(.ds-input--disabled) .ds-field__helper,
337
+ .ds-field:has(.ds-input__field:disabled) .ds-field__helper {
338
+ color: var(--ds-form-field-helper-color-disabled);
339
+ }
340
+
341
+ .ds-field:has(.ds-input--readonly) .ds-field__label,
342
+ .ds-field:has(.ds-input__field:read-only) .ds-field__label {
343
+ color: var(--ds-form-field-label-color-readonly);
344
+ }
345
+
346
+ /* ---------------------------------------------------------
347
+ Error message styling lives em form-field.css.
348
+ Compor Input dentro de .ds-field pra usar o pattern composto.
349
+ --------------------------------------------------------- */
350
+
351
+ /* ---------------------------------------------------------
352
+ Reduced motion
353
+ --------------------------------------------------------- */
354
+ @media (prefers-reduced-motion: reduce) {
355
+ .ds-input { transition: none; }
356
+ }
@@ -0,0 +1,67 @@
1
+ /* ============================================================
2
+ COMPONENT: Link — text style pra hyperlinks inline em prosa
3
+ Bold + underline. Tamanhos espelham body/* (xs/sm/md/lg).
4
+ Estados WCAG/W3C: default, :hover, :active, :focus-visible.
5
+ :visited intencionalmente omitido (decisão do owner).
6
+
7
+ Consome Semantic `link/content/*` e `body/*` direto por design:
8
+ no Figma Link é Text Style + Semantic Variables, sem collection
9
+ Component. Não inventar `component.link.*` só no JSON — isso
10
+ cria DRIFT_FROM_SOURCE. Migrar para ADR-019 quando o Figma
11
+ materializar contrato anatômico próprio.
12
+ ============================================================ */
13
+
14
+ .ds-link {
15
+ font-weight: var(--ds-body-font-weight-bold);
16
+ text-decoration: underline;
17
+ color: var(--ds-link-content-default);
18
+ cursor: pointer;
19
+ transition: color var(--ds-motion-duration-fast) var(--ds-motion-ease-default);
20
+ }
21
+
22
+ .ds-link:hover {
23
+ color: var(--ds-link-content-hover);
24
+ }
25
+
26
+ .ds-link:active {
27
+ color: var(--ds-link-content-active);
28
+ }
29
+
30
+ /* :visited intencionalmente omitido — decisão do owner */
31
+
32
+ .ds-link:focus-visible {
33
+ outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color-default);
34
+ outline-offset: var(--ds-focus-ring-width);
35
+ border-radius: var(--ds-radius-sm);
36
+ }
37
+
38
+ /* ---------------------------------------------------------
39
+ Sizes — herdam dimensões de body/*
40
+ --------------------------------------------------------- */
41
+
42
+ .ds-link--xs {
43
+ font-size: var(--ds-body-font-size-xs); /* 12px */
44
+ line-height: var(--ds-body-line-height-xs); /* 18px */
45
+ }
46
+
47
+ .ds-link--sm {
48
+ font-size: var(--ds-body-font-size-sm); /* 14px */
49
+ line-height: var(--ds-body-line-height-sm); /* 20px */
50
+ }
51
+
52
+ .ds-link--md {
53
+ font-size: var(--ds-body-font-size-md); /* 16px */
54
+ line-height: var(--ds-body-line-height-md); /* 24px */
55
+ }
56
+
57
+ .ds-link--lg {
58
+ font-size: var(--ds-body-font-size-lg); /* 18px */
59
+ line-height: var(--ds-body-line-height-xl); /* 32px (Figma body/lg uses lh xl) */
60
+ }
61
+
62
+ /* ---------------------------------------------------------
63
+ Reduced motion
64
+ --------------------------------------------------------- */
65
+ @media (prefers-reduced-motion: reduce) {
66
+ .ds-link { transition: none; }
67
+ }