@govnepal/css 0.1.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.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/civic-calm.css +1127 -0
- package/dist/fonts/noto-sans-devanagari-400.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-500.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-600.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-devanagari-400.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-devanagari-500.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-devanagari-600.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-latin-400.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-latin-500.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-latin-600.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-400.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-500.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-600.woff2 +0 -0
- package/dist/fonts/noto-sans-mono-latin-400.woff2 +0 -0
- package/dist/fonts/noto-serif-devanagari-devanagari-400.woff2 +0 -0
- package/dist/fonts/noto-serif-devanagari-devanagari-600.woff2 +0 -0
- package/dist/fonts/noto-serif-devanagari-latin-400.woff2 +0 -0
- package/dist/fonts/noto-serif-devanagari-latin-600.woff2 +0 -0
- package/dist/fonts/noto-serif-latin-400.woff2 +0 -0
- package/dist/fonts/noto-serif-latin-600.woff2 +0 -0
- package/dist/fonts.css +181 -0
- package/package.json +47 -0
|
@@ -0,0 +1,1127 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Civic Calm — @govnepal/css
|
|
3
|
+
* The framework-agnostic visual layer. Semantic HTML plus .gov-* classes; no JavaScript.
|
|
4
|
+
* Built against design-guidelines 0.2.0-dev (7af0babf).
|
|
5
|
+
*
|
|
6
|
+
* This stylesheet holds ALL of Civic Calm's visual decisions. @govnepal/ui adds only behavior
|
|
7
|
+
* (ARIA, keyboard, focus management) on top of these classes — so a plain-HTML site or a CMS
|
|
8
|
+
* gets the same interface without a JS framework, and a future Vue or Web Component port
|
|
9
|
+
* re-implements behavior only, never a design decision.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* GENERATED from data/grid.yaml and data/breakpoints.yaml — do not edit. */
|
|
13
|
+
:root {
|
|
14
|
+
--gov-grid-columns: 12;
|
|
15
|
+
--gov-grid-gutter: 24px;
|
|
16
|
+
--gov-grid-max-width: 1200px;
|
|
17
|
+
--gov-grid-margin: 16px;
|
|
18
|
+
}
|
|
19
|
+
@media (min-width: 768px) {
|
|
20
|
+
:root { --gov-grid-margin: 24px; }
|
|
21
|
+
}
|
|
22
|
+
@media (min-width: 1024px) {
|
|
23
|
+
:root { --gov-grid-margin: 32px; }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Reset — the minimum needed to make the token layer predictable. Not a normalize.css: every
|
|
27
|
+
* rule here exists because a browser default would otherwise contradict a guideline. */
|
|
28
|
+
|
|
29
|
+
*,
|
|
30
|
+
*::before,
|
|
31
|
+
*::after {
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Browser default margins are the main reason teams reach for hardcoded spacing. Remove them so
|
|
36
|
+
* vertical rhythm comes from `stack` and nowhere else (components/stack.md). */
|
|
37
|
+
body,
|
|
38
|
+
h1, h2, h3, h4, h5, h6,
|
|
39
|
+
p, figure, blockquote,
|
|
40
|
+
dl, dd, ol, ul {
|
|
41
|
+
margin: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
ol, ul {
|
|
45
|
+
padding: 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Media never overflows its container — §4.1 requires zoom and responsive layout without
|
|
49
|
+
* clipping or overlap. */
|
|
50
|
+
img, picture, video, canvas, svg {
|
|
51
|
+
display: block;
|
|
52
|
+
max-inline-size: 100%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Form controls do not inherit typography by default; §5.3's 16px minimum applies to them too. */
|
|
56
|
+
input, button, textarea, select {
|
|
57
|
+
font: inherit;
|
|
58
|
+
color: inherit;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* A long citizenship number or Devanagari compound must wrap rather than force a horizontal
|
|
62
|
+
* scrollbar on a 360px phone. */
|
|
63
|
+
p, h1, h2, h3, h4, h5, h6, li, td, th {
|
|
64
|
+
overflow-wrap: break-word;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Element defaults: semantic HTML should already look like Civic Calm before a single class is
|
|
68
|
+
* applied. That is what lets a CMS or a plain-HTML ministry site comply (§10.2's four-step
|
|
69
|
+
* quick start) without adopting a component library. */
|
|
70
|
+
|
|
71
|
+
html {
|
|
72
|
+
/* Never disable zoom, and never lock text scaling (§4.1). */
|
|
73
|
+
-webkit-text-size-adjust: 100%;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
body {
|
|
77
|
+
background: var(--gov-color-background-default);
|
|
78
|
+
color: var(--gov-color-text-primary);
|
|
79
|
+
font-family: var(--gov-font-family-ui);
|
|
80
|
+
font-size: var(--gov-type-body-font-size);
|
|
81
|
+
font-weight: var(--gov-font-weight-regular);
|
|
82
|
+
line-height: var(--gov-type-body-line-height);
|
|
83
|
+
/* Weights below 400 are prohibited (§5.3), so synthetic bolding must never be relied on —
|
|
84
|
+
* and Devanagari must never be faux-bolded or faux-italicised at all. */
|
|
85
|
+
font-synthesis: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Devanagari renders denser than Latin at the same pixel size and needs the taller line (§5.3).
|
|
89
|
+
* This keys off `lang`, so a Nepali passage inside an English page gets the right leading
|
|
90
|
+
* without a class — the theme provider sets `lang` on <html>, but a `<p lang="ne">` works too. */
|
|
91
|
+
:lang(ne) {
|
|
92
|
+
font-size: var(--gov-type-body-ne-font-size);
|
|
93
|
+
line-height: var(--gov-type-body-ne-line-height);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Never letter-space Devanagari: it breaks matra and conjunct joining (§5.3). The type scale
|
|
97
|
+
* defines no tracking tokens at all — the absence is the policy — so this is a backstop against
|
|
98
|
+
* a product stylesheet reintroducing it. */
|
|
99
|
+
:lang(ne) {
|
|
100
|
+
letter-spacing: normal;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
h1, h2, h3 {
|
|
104
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
105
|
+
color: var(--gov-color-text-primary);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
h1 {
|
|
109
|
+
font-size: var(--gov-type-h1-font-size);
|
|
110
|
+
line-height: var(--gov-type-h1-line-height);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
h2 {
|
|
114
|
+
font-size: var(--gov-type-h2-font-size);
|
|
115
|
+
line-height: var(--gov-type-h2-line-height);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
h3 {
|
|
119
|
+
font-size: var(--gov-type-h3-font-size);
|
|
120
|
+
line-height: var(--gov-type-h3-line-height);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
small,
|
|
124
|
+
.gov-text-small {
|
|
125
|
+
font-size: var(--gov-type-small-font-size);
|
|
126
|
+
line-height: var(--gov-type-small-line-height);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.gov-text-secondary {
|
|
130
|
+
color: var(--gov-color-text-secondary);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Reference and application numbers render monospaced so a citizen can transcribe them onto a
|
|
134
|
+
* form or read them down a phone without confusing similar glyphs (typography.json). */
|
|
135
|
+
code, kbd, samp, pre,
|
|
136
|
+
.gov-reference {
|
|
137
|
+
font-family: var(--gov-font-family-mono);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* §5.3: Display and H1 step down on mobile. The type scale carries no responsive variants as
|
|
141
|
+
* tokens, so the two responsive sizes the guideline names in prose are implemented here.
|
|
142
|
+
* TODO(guidelines): these belong in a token overlay, so the checker can verify them. */
|
|
143
|
+
@media (max-width: 767px) {
|
|
144
|
+
h1 {
|
|
145
|
+
font-size: 28px;
|
|
146
|
+
line-height: 36px;
|
|
147
|
+
}
|
|
148
|
+
.gov-display {
|
|
149
|
+
font-size: 32px;
|
|
150
|
+
line-height: 40px;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.gov-display {
|
|
155
|
+
font-size: var(--gov-type-display-font-size);
|
|
156
|
+
line-height: var(--gov-type-display-line-height);
|
|
157
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Skip link — the first focusable element on every page (§7.2, §4.1). Visually hidden until
|
|
161
|
+
* focused; never display:none, which would remove it from the tab order and defeat the point. */
|
|
162
|
+
.gov-skip-link {
|
|
163
|
+
position: absolute;
|
|
164
|
+
inset-inline-start: var(--gov-space-4);
|
|
165
|
+
inset-block-start: var(--gov-space-4);
|
|
166
|
+
z-index: var(--gov-z-sticky);
|
|
167
|
+
padding: var(--gov-space-3) var(--gov-space-4);
|
|
168
|
+
background: var(--gov-color-background-surface);
|
|
169
|
+
color: var(--gov-color-link-default);
|
|
170
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
171
|
+
border-radius: var(--gov-radius-sm);
|
|
172
|
+
transform: translateY(-200%);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.gov-skip-link:focus {
|
|
176
|
+
transform: translateY(0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Screen-reader-only text. Used for the error-summary count, chart table equivalents (§7.3.4),
|
|
180
|
+
* and icon labels — never to hide something a sighted user also needs. */
|
|
181
|
+
.gov-visually-hidden {
|
|
182
|
+
position: absolute;
|
|
183
|
+
inline-size: 1px;
|
|
184
|
+
block-size: 1px;
|
|
185
|
+
padding: 0;
|
|
186
|
+
margin: -1px;
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
clip-path: inset(50%);
|
|
189
|
+
white-space: nowrap;
|
|
190
|
+
border: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Focus (§5.2, normative).
|
|
194
|
+
*
|
|
195
|
+
* The double ring: `--gov-focus-ring-width` of `color.focus.ring` outside an equally-wide gap of
|
|
196
|
+
* `color.focus.offset`. It is drawn with box-shadow rather than `outline` + `outline-offset` for
|
|
197
|
+
* one specific reason: outline-offset leaves the element's OWN background showing in the gap, so
|
|
198
|
+
* on a primary button the gap would be blue-on-blue and the double ring would collapse into one
|
|
199
|
+
* thick edge. box-shadow lets the gap be an actual colour, which is what the spec requires when
|
|
200
|
+
* it says the ring must be "visible on any background including primary buttons and dark
|
|
201
|
+
* surfaces".
|
|
202
|
+
*
|
|
203
|
+
* High-contrast mode widens the ring to 3px; that comes from the token, not from a rule here. */
|
|
204
|
+
|
|
205
|
+
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
|
|
206
|
+
outline: none;
|
|
207
|
+
box-shadow:
|
|
208
|
+
0 0 0 var(--gov-focus-ring-width) var(--gov-color-focus-offset),
|
|
209
|
+
0 0 0 calc(var(--gov-focus-ring-width) * 2) var(--gov-color-focus-ring);
|
|
210
|
+
/* The ring is drawn outside the element and must never be clipped by an ancestor's overflow,
|
|
211
|
+
* nor hidden behind a sticky header (§4.1's focus-visibility test). */
|
|
212
|
+
position: relative;
|
|
213
|
+
z-index: var(--gov-z-sticky);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Focus is never removed (§5.2). A product stylesheet that sets `outline: none` without a
|
|
217
|
+
* replacement is a checker error; this backstop means it at least degrades to a visible ring. */
|
|
218
|
+
:where(a, button, input, select, textarea, summary, [tabindex]):focus:not(:focus-visible) {
|
|
219
|
+
outline: none;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* The focus ring must appear instantly — motion.duration.instant (§5.5): "state changes that must
|
|
223
|
+
* not animate — error appearance, focus ring". */
|
|
224
|
+
:where(a, button, input, select, textarea, summary, [tabindex]) {
|
|
225
|
+
transition-property: background-color, border-color, color;
|
|
226
|
+
transition-duration: var(--gov-motion-duration-fast);
|
|
227
|
+
transition-timing-function: var(--gov-motion-easing-standard);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Layout primitives (components/container.md, stack.md, page-section.md).
|
|
231
|
+
*
|
|
232
|
+
* These three are "the grid made installable": the only sanctioned way to set page width,
|
|
233
|
+
* vertical rhythm, and page bands, so spacing values never appear hardcoded in product code
|
|
234
|
+
* (§6.1.2). They carry no colour of their own except page-section's background variants. */
|
|
235
|
+
|
|
236
|
+
/* --- Container: max width, responsive side margins, centred ------------------------------- */
|
|
237
|
+
.gov-container {
|
|
238
|
+
inline-size: 100%;
|
|
239
|
+
max-inline-size: var(--gov-grid-max-width);
|
|
240
|
+
margin-inline: auto;
|
|
241
|
+
padding-inline: var(--gov-grid-margin);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Long-form reading and single-question form pages. The spec puts this at ~720px, which is the
|
|
245
|
+
* measure at which a line of body text stays comfortably readable (components/container.md). */
|
|
246
|
+
.gov-container--narrow {
|
|
247
|
+
max-inline-size: 720px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Only for edge-to-edge bands that contain their own container. */
|
|
251
|
+
.gov-container--full-bleed {
|
|
252
|
+
max-inline-size: none;
|
|
253
|
+
padding-inline: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* --- Stack: vertical rhythm ---------------------------------------------------------------
|
|
257
|
+
* One stack with one gap, rather than per-element margins. `gap` accepts spacing token steps
|
|
258
|
+
* only — an arbitrary pixel value is a checker violation (components/stack.md). */
|
|
259
|
+
.gov-stack {
|
|
260
|
+
display: flex;
|
|
261
|
+
flex-direction: column;
|
|
262
|
+
gap: var(--gov-stack-gap, var(--gov-space-4));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.gov-stack--1 { --gov-stack-gap: var(--gov-space-1); }
|
|
266
|
+
.gov-stack--2 { --gov-stack-gap: var(--gov-space-2); }
|
|
267
|
+
.gov-stack--3 { --gov-stack-gap: var(--gov-space-3); }
|
|
268
|
+
.gov-stack--4 { --gov-stack-gap: var(--gov-space-4); }
|
|
269
|
+
.gov-stack--6 { --gov-stack-gap: var(--gov-space-6); }
|
|
270
|
+
.gov-stack--8 { --gov-stack-gap: var(--gov-space-8); }
|
|
271
|
+
|
|
272
|
+
/* --- Page section: a full-width band with contained content ------------------------------- */
|
|
273
|
+
.gov-page-section {
|
|
274
|
+
padding-block: var(--gov-space-8);
|
|
275
|
+
background: var(--gov-color-background-default);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@media (min-width: 1024px) {
|
|
279
|
+
.gov-page-section {
|
|
280
|
+
padding-block: var(--gov-space-12);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Alternating bands give a landing page rhythm without decoration. Backgrounds come only from
|
|
285
|
+
* color.background.* — never a hue tint, because in Civic Calm a hue is always information
|
|
286
|
+
* (§5.2's colour hierarchy). */
|
|
287
|
+
.gov-page-section--secondary-background {
|
|
288
|
+
background: var(--gov-color-background-secondary);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.gov-page-section--inverse {
|
|
292
|
+
background: var(--gov-color-background-inverse);
|
|
293
|
+
color: var(--gov-color-text-inverse);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Button rows and other horizontal clusters. Not a stack — stack is vertical only
|
|
297
|
+
* (components/stack.md's "when not to use"). Wraps rather than overflowing on a 360px screen. */
|
|
298
|
+
.gov-cluster {
|
|
299
|
+
display: flex;
|
|
300
|
+
flex-wrap: wrap;
|
|
301
|
+
align-items: center;
|
|
302
|
+
gap: var(--gov-space-3);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* Button (components/button.md).
|
|
306
|
+
*
|
|
307
|
+
* "One primary button per view establishes the single next step" (§1.3, principle 1). The visual
|
|
308
|
+
* weight of the three variants is what makes that legible, so it is fixed here and not
|
|
309
|
+
* configurable per service. */
|
|
310
|
+
|
|
311
|
+
.gov-button {
|
|
312
|
+
display: inline-flex;
|
|
313
|
+
align-items: center;
|
|
314
|
+
justify-content: center;
|
|
315
|
+
gap: var(--gov-space-2);
|
|
316
|
+
|
|
317
|
+
/* The hit area is 44×44 minimum regardless of visual size (components/button.md's Anatomy).
|
|
318
|
+
* --gov-target-min-size is NOT density-scaled, so the officer desktop's 0.875 multiplier can
|
|
319
|
+
* compact the padding without ever shrinking a control below the floor
|
|
320
|
+
* (data/density-rules.yaml: "48dp minimum touch targets survive every multiplier"). */
|
|
321
|
+
min-block-size: var(--gov-target-min-size);
|
|
322
|
+
padding-inline: var(--gov-space-4);
|
|
323
|
+
padding-block: var(--gov-space-3);
|
|
324
|
+
|
|
325
|
+
border: var(--gov-border-width-md) solid transparent;
|
|
326
|
+
border-radius: var(--gov-radius-sm);
|
|
327
|
+
|
|
328
|
+
font-family: var(--gov-font-family-ui);
|
|
329
|
+
font-size: var(--gov-type-body-font-size);
|
|
330
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
331
|
+
line-height: var(--gov-type-body-line-height);
|
|
332
|
+
text-align: center;
|
|
333
|
+
text-decoration: none;
|
|
334
|
+
|
|
335
|
+
/* Citizens are trained by the consumer web; to a low-digital-literacy user the native-app
|
|
336
|
+
* "default cursor on buttons" reads as NOT clickable (§6.1.4, data/cursors.yaml). */
|
|
337
|
+
cursor: pointer;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* Adjacent controls keep the minimum spacing between targets (data/quantified-standards.yaml)
|
|
341
|
+
* so a mistap on a phone does not trigger the wrong action. */
|
|
342
|
+
.gov-button + .gov-button {
|
|
343
|
+
margin-inline-start: var(--gov-target-min-spacing);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* --- Variants ---------------------------------------------------------------------------- */
|
|
347
|
+
.gov-button--primary {
|
|
348
|
+
background: var(--gov-color-action-primary-default);
|
|
349
|
+
color: var(--gov-color-text-on-action);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.gov-button--primary:hover {
|
|
353
|
+
background: var(--gov-color-action-primary-hover);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.gov-button--primary:active {
|
|
357
|
+
background: var(--gov-color-action-primary-active);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.gov-button--secondary {
|
|
361
|
+
background: transparent;
|
|
362
|
+
color: var(--gov-color-action-secondary-text);
|
|
363
|
+
border-color: currentColor;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.gov-button--secondary:hover {
|
|
367
|
+
background: var(--gov-color-action-secondary-hover-background);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* Always paired with a confirmation dialog (components/button.md) — the colour is a warning, not
|
|
371
|
+
* the safeguard. Its red is deliberately the FUNCTIONAL red, never Simrik: "the colour of the
|
|
372
|
+
* nation is never the colour of failure" (§2.1). */
|
|
373
|
+
.gov-button--destructive {
|
|
374
|
+
background: var(--gov-color-action-destructive-default);
|
|
375
|
+
color: var(--gov-color-text-on-action);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.gov-button--destructive:hover {
|
|
379
|
+
background: var(--gov-color-action-destructive-hover);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.gov-button--destructive:active {
|
|
383
|
+
background: var(--gov-color-action-destructive-active);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* --- Sizes -------------------------------------------------------------------------------- */
|
|
387
|
+
/* sm is permitted only in dense officer tables (components/button.md's Platform notes). Even at
|
|
388
|
+
* sm the 44px hit-area floor holds — the padding shrinks, the target does not. */
|
|
389
|
+
.gov-button--sm {
|
|
390
|
+
padding-inline: var(--gov-space-3);
|
|
391
|
+
font-size: var(--gov-type-small-font-size);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.gov-button--lg {
|
|
395
|
+
padding-inline: var(--gov-space-6);
|
|
396
|
+
padding-block: var(--gov-space-4);
|
|
397
|
+
font-size: var(--gov-type-body-large-font-size);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Kiosk: lg is the default and targets rise to the recommended 48px for stand-up use (§8.1.4). */
|
|
401
|
+
[data-density="kiosk-counter"] .gov-button {
|
|
402
|
+
min-block-size: var(--gov-target-recommended-size);
|
|
403
|
+
font-size: var(--gov-type-body-large-font-size);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/* --- States ------------------------------------------------------------------------------- */
|
|
407
|
+
/* aria-disabled is preferred over the `disabled` attribute (components/button.md): a disabled
|
|
408
|
+
* control that drops out of the tab order with no explanation is "a support-call generator", so
|
|
409
|
+
* it stays focusable and something else on the page says why. */
|
|
410
|
+
.gov-button[disabled],
|
|
411
|
+
.gov-button[aria-disabled="true"] {
|
|
412
|
+
background: var(--gov-color-action-primary-disabled-background);
|
|
413
|
+
color: var(--gov-color-action-primary-disabled-text);
|
|
414
|
+
border-color: transparent;
|
|
415
|
+
cursor: not-allowed;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* Loading keeps the label ("Submitting…") and the button in the tab order; repeat activation is
|
|
419
|
+
* ignored in the behavior layer, not by removing the control. */
|
|
420
|
+
.gov-button[aria-busy="true"] {
|
|
421
|
+
cursor: progress;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.gov-button__spinner {
|
|
425
|
+
inline-size: var(--gov-icon-size-md);
|
|
426
|
+
block-size: var(--gov-icon-size-md);
|
|
427
|
+
border: var(--gov-border-width-md) solid currentColor;
|
|
428
|
+
border-block-start-color: transparent;
|
|
429
|
+
border-radius: var(--gov-radius-full);
|
|
430
|
+
/* The one sanctioned continuous loop is a genuine indeterminate-progress indicator (§5.5).
|
|
431
|
+
* Under reduced-motion the duration token is 0ms, so this stops dead rather than spinning. */
|
|
432
|
+
animation: gov-spin var(--gov-motion-duration-slow) linear infinite;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
@keyframes gov-spin {
|
|
436
|
+
to {
|
|
437
|
+
transform: rotate(360deg);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* Reduced motion collapses every duration to 0ms, which would leave the spinner frozen mid-turn.
|
|
442
|
+
* Remove the animation outright instead: the user still learns the button is busy from
|
|
443
|
+
* aria-busy and the "Submitting…" label — no information is carried by the motion (§5.5). */
|
|
444
|
+
@media (prefers-reduced-motion: reduce) {
|
|
445
|
+
.gov-button__spinner {
|
|
446
|
+
animation: none;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
[data-reduced-motion="true"] .gov-button__spinner {
|
|
451
|
+
animation: none;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Icons accompany labels; they never replace them for primary actions (§5.4). */
|
|
455
|
+
.gov-button__icon {
|
|
456
|
+
inline-size: var(--gov-icon-size-md);
|
|
457
|
+
block-size: var(--gov-icon-size-md);
|
|
458
|
+
flex-shrink: 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* Link (components/link.md).
|
|
462
|
+
*
|
|
463
|
+
* "If it is blue, it is interactive; if it is interactive, it is blue" (§5.2). Nothing decorative
|
|
464
|
+
* may be blue, which is why a link needs no other affordance — except the underline, below. */
|
|
465
|
+
|
|
466
|
+
.gov-link,
|
|
467
|
+
a {
|
|
468
|
+
color: var(--gov-color-link-default);
|
|
469
|
+
/* Underlined in body text, because a link may never be identified by colour alone (§4.1).
|
|
470
|
+
* This is the single most-broken accessibility rule on government sites, so it is the element
|
|
471
|
+
* default here rather than an opt-in class. */
|
|
472
|
+
text-decoration: underline;
|
|
473
|
+
text-underline-offset: 0.15em;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
a:hover,
|
|
477
|
+
.gov-link:hover {
|
|
478
|
+
color: var(--gov-color-link-hover);
|
|
479
|
+
text-decoration-thickness: 2px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* Shown, not suppressed: a citizen working through a list of guidance pages can see what they
|
|
483
|
+
* have already read (components/link.md, Platform notes). */
|
|
484
|
+
a:visited,
|
|
485
|
+
.gov-link:visited {
|
|
486
|
+
color: var(--gov-color-link-visited);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* Standalone links (not inside a paragraph) carry the same 44px minimum hit area as any other
|
|
490
|
+
* control. Inline links in running text are exempt — they are part of a text line. */
|
|
491
|
+
.gov-link--standalone {
|
|
492
|
+
display: inline-flex;
|
|
493
|
+
align-items: center;
|
|
494
|
+
min-block-size: var(--gov-target-min-size);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/* The "Back" affordance above a task-flow page's heading (components/link.md). */
|
|
498
|
+
.gov-link--back {
|
|
499
|
+
display: inline-flex;
|
|
500
|
+
align-items: center;
|
|
501
|
+
gap: var(--gov-space-2);
|
|
502
|
+
min-block-size: var(--gov-target-min-size);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* An external link is marked visibly, because §9.2's trust cues depend on a citizen knowing when
|
|
506
|
+
* they have left .gov.np — an unmarked jump off the domain is exactly what phishing exploits.
|
|
507
|
+
* The visible mark pairs with an accessible name in the behavior layer; neither alone is enough. */
|
|
508
|
+
.gov-link--external::after {
|
|
509
|
+
content: "↗";
|
|
510
|
+
margin-inline-start: 0.25em;
|
|
511
|
+
/* Decorative glyph: the accessible name already says the link is external. */
|
|
512
|
+
speak: never;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* A download link states format and size in its text so a citizen on metered mobile data can
|
|
516
|
+
* decide before spending it (§8.1.5). The stylesheet cannot enforce that; it only marks it. */
|
|
517
|
+
.gov-link--download::after {
|
|
518
|
+
content: "↓";
|
|
519
|
+
margin-inline-start: 0.25em;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* Text input (components/text-input.md).
|
|
523
|
+
*
|
|
524
|
+
* One question per row — the input IS the whole row (§7.1). Labels are always visible and stay
|
|
525
|
+
* visible after the user types; a placeholder is an example, never a label. */
|
|
526
|
+
|
|
527
|
+
.gov-field {
|
|
528
|
+
display: flex;
|
|
529
|
+
flex-direction: column;
|
|
530
|
+
gap: var(--gov-space-2);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.gov-field__label {
|
|
534
|
+
font-weight: var(--gov-font-weight-medium);
|
|
535
|
+
color: var(--gov-color-text-primary);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* Helper text carries the format example for hard fields — "Enter the number exactly as shown on
|
|
539
|
+
* your certificate, e.g. 12-01-76-12345" (§7.1). It is bound with aria-describedby, not placed
|
|
540
|
+
* inside the label, so a screen reader announces the question first and the hint after. */
|
|
541
|
+
.gov-field__hint {
|
|
542
|
+
color: var(--gov-color-text-secondary);
|
|
543
|
+
font-size: var(--gov-type-small-font-size);
|
|
544
|
+
line-height: var(--gov-type-small-line-height);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.gov-input {
|
|
548
|
+
inline-size: 100%;
|
|
549
|
+
min-block-size: var(--gov-target-min-size);
|
|
550
|
+
padding: var(--gov-space-3);
|
|
551
|
+
|
|
552
|
+
background: var(--gov-color-background-surface);
|
|
553
|
+
color: var(--gov-color-text-primary);
|
|
554
|
+
/* ≥3:1 against both the field fill and the page (WCAG 1.4.11) — a field whose edge you cannot
|
|
555
|
+
* see is not a field. Verified for every display mode by the contrast gate. */
|
|
556
|
+
border: var(--gov-border-width-md) solid var(--gov-color-border-input);
|
|
557
|
+
border-radius: var(--gov-radius-sm);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.gov-input::placeholder {
|
|
561
|
+
color: var(--gov-color-text-placeholder);
|
|
562
|
+
/* Placeholder is example-only. It must never be the label — the label stays visible above,
|
|
563
|
+
* because a placeholder disappears the moment the citizen starts typing (§7.1). */
|
|
564
|
+
opacity: 1;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/* Width hints content: a ward number is ~4ch wide, never full-width (components/text-input.md).
|
|
568
|
+
* A full-width input for a 2-digit field tells the citizen the wrong thing about what to enter. */
|
|
569
|
+
.gov-input--width-2 { inline-size: 5ch; }
|
|
570
|
+
.gov-input--width-4 { inline-size: 8ch; }
|
|
571
|
+
.gov-input--width-10 { inline-size: 15ch; }
|
|
572
|
+
.gov-input--width-20 { inline-size: 26ch; }
|
|
573
|
+
|
|
574
|
+
/* readonly is the officer view: still focusable and still copyable (components/text-input.md).
|
|
575
|
+
* It is NOT disabled — an officer must be able to select the value and paste it elsewhere. */
|
|
576
|
+
.gov-input[readonly] {
|
|
577
|
+
background: var(--gov-color-background-secondary);
|
|
578
|
+
border-color: var(--gov-color-border-default);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.gov-input[disabled] {
|
|
582
|
+
background: var(--gov-color-background-secondary);
|
|
583
|
+
color: var(--gov-color-text-disabled);
|
|
584
|
+
cursor: not-allowed;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/* Error state. The border thickens as well as changing colour, so the state is not carried by
|
|
588
|
+
* colour alone (§4.1) — and the message below says what to DO, never "Invalid input" (§3.1.3). */
|
|
589
|
+
.gov-input[aria-invalid="true"] {
|
|
590
|
+
border-color: var(--gov-color-status-error-border);
|
|
591
|
+
border-width: var(--gov-border-width-md);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.gov-field--error .gov-field__label {
|
|
595
|
+
color: var(--gov-color-status-error-text);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.gov-field__error {
|
|
599
|
+
display: flex;
|
|
600
|
+
align-items: flex-start;
|
|
601
|
+
gap: var(--gov-space-2);
|
|
602
|
+
color: var(--gov-color-status-error-text);
|
|
603
|
+
font-weight: var(--gov-font-weight-medium);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.gov-field__error-icon {
|
|
607
|
+
inline-size: var(--gov-icon-size-md);
|
|
608
|
+
block-size: var(--gov-icon-size-md);
|
|
609
|
+
flex-shrink: 0;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/* Prefix/suffix — रु, +977 (components/text-input.md's `prefixed` variant). The affix sits
|
|
613
|
+
* outside the input so it is never mistaken for a typed value the citizen has to delete. */
|
|
614
|
+
.gov-input-group {
|
|
615
|
+
display: flex;
|
|
616
|
+
align-items: stretch;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.gov-input-group__affix {
|
|
620
|
+
display: flex;
|
|
621
|
+
align-items: center;
|
|
622
|
+
padding-inline: var(--gov-space-3);
|
|
623
|
+
background: var(--gov-color-background-secondary);
|
|
624
|
+
border: var(--gov-border-width-md) solid var(--gov-color-border-input);
|
|
625
|
+
color: var(--gov-color-text-secondary);
|
|
626
|
+
white-space: nowrap;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.gov-input-group__affix:first-child {
|
|
630
|
+
border-start-start-radius: var(--gov-radius-sm);
|
|
631
|
+
border-end-start-radius: var(--gov-radius-sm);
|
|
632
|
+
border-inline-end: 0;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
.gov-input-group__affix:last-child {
|
|
636
|
+
border-start-end-radius: var(--gov-radius-sm);
|
|
637
|
+
border-end-end-radius: var(--gov-radius-sm);
|
|
638
|
+
border-inline-start: 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.gov-input-group .gov-input {
|
|
642
|
+
border-radius: 0;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.gov-input-group .gov-input:first-child {
|
|
646
|
+
border-start-start-radius: var(--gov-radius-sm);
|
|
647
|
+
border-end-start-radius: var(--gov-radius-sm);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.gov-input-group .gov-input:last-child {
|
|
651
|
+
border-start-end-radius: var(--gov-radius-sm);
|
|
652
|
+
border-end-end-radius: var(--gov-radius-sm);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/* Masked variant: sensitive identity numbers are masked by default and revealed only by an
|
|
656
|
+
* explicit, permission-gated action (§9.1). The reveal control is a button, never a hover. */
|
|
657
|
+
.gov-input--masked {
|
|
658
|
+
font-family: var(--gov-font-family-mono);
|
|
659
|
+
letter-spacing: 0.1em;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/* Error summary (components/error-summary.md).
|
|
663
|
+
*
|
|
664
|
+
* Mandatory on every form, on any failed validation (§7.1) — alongside the inline errors, never
|
|
665
|
+
* instead of them. Both renderings are built from the same validation result, so they can never
|
|
666
|
+
* disagree about what went wrong. */
|
|
667
|
+
|
|
668
|
+
.gov-error-summary {
|
|
669
|
+
padding: var(--gov-space-4);
|
|
670
|
+
/* The thick edge (border.width.lg) is the same device the alert uses: the state is carried by
|
|
671
|
+
* shape as well as colour, so it survives high-contrast mode, where the tint is removed
|
|
672
|
+
* entirely and only border + icon + text remain (§5.2's "shape over tint"). */
|
|
673
|
+
border: var(--gov-border-width-lg) solid var(--gov-color-status-error-border);
|
|
674
|
+
border-radius: var(--gov-radius-md);
|
|
675
|
+
background: var(--gov-color-status-error-background);
|
|
676
|
+
color: var(--gov-color-text-primary);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/* Focus moves here on failed submit (tabindex="-1", role="alert"), so it must show a focus ring
|
|
680
|
+
* even though it is not otherwise interactive. */
|
|
681
|
+
.gov-error-summary:focus-visible {
|
|
682
|
+
box-shadow:
|
|
683
|
+
0 0 0 var(--gov-focus-ring-width) var(--gov-color-focus-offset),
|
|
684
|
+
0 0 0 calc(var(--gov-focus-ring-width) * 2) var(--gov-color-focus-ring);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.gov-error-summary__title {
|
|
688
|
+
font-size: var(--gov-type-h3-font-size);
|
|
689
|
+
line-height: var(--gov-type-h3-line-height);
|
|
690
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
691
|
+
color: var(--gov-color-status-error-text);
|
|
692
|
+
margin-block-end: var(--gov-space-3);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.gov-error-summary__list {
|
|
696
|
+
list-style: none;
|
|
697
|
+
display: flex;
|
|
698
|
+
flex-direction: column;
|
|
699
|
+
gap: var(--gov-space-2);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/* Each entry is a real link to the field's id. Activating it moves FOCUS to the input, not just
|
|
703
|
+
* the scroll position — a keyboard user who lands next to the field but not in it has to hunt
|
|
704
|
+
* for it (components/error-summary.md). */
|
|
705
|
+
.gov-error-summary__link {
|
|
706
|
+
color: var(--gov-color-status-error-text);
|
|
707
|
+
font-weight: var(--gov-font-weight-medium);
|
|
708
|
+
text-decoration: underline;
|
|
709
|
+
min-block-size: var(--gov-target-min-size);
|
|
710
|
+
display: inline-flex;
|
|
711
|
+
align-items: center;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.gov-error-summary__link:hover,
|
|
715
|
+
.gov-error-summary__link:visited {
|
|
716
|
+
color: var(--gov-color-status-error-text);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* Alert (components/alert.md).
|
|
720
|
+
*
|
|
721
|
+
* Variant maps 1:1 to a color.status.* triple, so the display modes come for free: teal success
|
|
722
|
+
* in color-blind-safe, tint-free bordered boxes in high-contrast. Never construct an alert with
|
|
723
|
+
* custom colours. */
|
|
724
|
+
|
|
725
|
+
.gov-alert {
|
|
726
|
+
display: flex;
|
|
727
|
+
gap: var(--gov-space-3);
|
|
728
|
+
padding: var(--gov-space-4);
|
|
729
|
+
border-radius: var(--gov-radius-md);
|
|
730
|
+
/* Thick leading edge in the status border colour. Together with the icon and the title text,
|
|
731
|
+
* this means the status is never carried by colour alone (§4.1) — and it is what survives
|
|
732
|
+
* high-contrast mode, where the background tint is removed entirely. */
|
|
733
|
+
border-inline-start: var(--gov-border-width-lg) solid;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.gov-alert__icon {
|
|
737
|
+
inline-size: var(--gov-icon-size-md);
|
|
738
|
+
block-size: var(--gov-icon-size-md);
|
|
739
|
+
flex-shrink: 0;
|
|
740
|
+
margin-block-start: 0.15em;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.gov-alert__title {
|
|
744
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Body states what happened AND what to do next, with the reference number (§3.1.3). */
|
|
748
|
+
.gov-alert__body {
|
|
749
|
+
display: flex;
|
|
750
|
+
flex-direction: column;
|
|
751
|
+
gap: var(--gov-space-2);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.gov-alert--info {
|
|
755
|
+
background: var(--gov-color-status-info-background);
|
|
756
|
+
border-color: var(--gov-color-status-info-border);
|
|
757
|
+
color: var(--gov-color-status-info-text);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.gov-alert--success {
|
|
761
|
+
background: var(--gov-color-status-success-background);
|
|
762
|
+
border-color: var(--gov-color-status-success-border);
|
|
763
|
+
color: var(--gov-color-status-success-text);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.gov-alert--warning {
|
|
767
|
+
background: var(--gov-color-status-warning-background);
|
|
768
|
+
border-color: var(--gov-color-status-warning-border);
|
|
769
|
+
color: var(--gov-color-status-warning-text);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.gov-alert--error {
|
|
773
|
+
background: var(--gov-color-status-error-background);
|
|
774
|
+
border-color: var(--gov-color-status-error-border);
|
|
775
|
+
color: var(--gov-color-status-error-text);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/* Emergency (§7.4's precedence rule).
|
|
779
|
+
*
|
|
780
|
+
* A public-safety notice from the authorized emergency-communication office. It MUST NOT read
|
|
781
|
+
* like "your application failed" (components/alert.md's alert-emergency-not-form-error): a
|
|
782
|
+
* citizen has to tell a national disaster alert apart from their own form mistake instantly.
|
|
783
|
+
*
|
|
784
|
+
* So it inverts rather than tints — a solid fill where every routine alert is a pale wash. That
|
|
785
|
+
* is a categorical difference in weight, not a different hue, so it introduces no new colour
|
|
786
|
+
* into a system where every hue already means exactly one thing (§5.2). It also outranks every
|
|
787
|
+
* other banner on the page, sitting closest to the government header, above the phase banner and
|
|
788
|
+
* the cookie banner. It never auto-dismisses and is never suppressed by cookie or notification
|
|
789
|
+
* preferences — public-safety information is not gated by consent (§9.1.2). */
|
|
790
|
+
.gov-alert--emergency {
|
|
791
|
+
background: var(--gov-color-status-error-border);
|
|
792
|
+
border-color: var(--gov-color-status-error-text);
|
|
793
|
+
color: var(--gov-color-text-on-action);
|
|
794
|
+
border-inline-start-width: var(--gov-border-width-lg);
|
|
795
|
+
font-weight: var(--gov-font-weight-medium);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.gov-alert--emergency .gov-alert__title {
|
|
799
|
+
font-size: var(--gov-type-h3-font-size);
|
|
800
|
+
line-height: var(--gov-type-h3-line-height);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/* An emergency notice's links must stay legible on the solid fill. */
|
|
804
|
+
.gov-alert--emergency a {
|
|
805
|
+
color: var(--gov-color-text-on-action);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/* Status badge (components/badge.md).
|
|
809
|
+
*
|
|
810
|
+
* Renders the official status taxonomy (data/status-taxonomy.yaml) — Draft, Submitted, Under
|
|
811
|
+
* review, Correction required, Approved, Rejected, Printed, Delivered — and nothing else. An
|
|
812
|
+
* ad-hoc status is not a styling problem; extend the taxonomy first (§7.3). */
|
|
813
|
+
|
|
814
|
+
.gov-badge {
|
|
815
|
+
display: inline-flex;
|
|
816
|
+
align-items: center;
|
|
817
|
+
gap: var(--gov-space-1);
|
|
818
|
+
padding-inline: var(--gov-space-2);
|
|
819
|
+
padding-block: var(--gov-space-1);
|
|
820
|
+
border-radius: var(--gov-radius-full);
|
|
821
|
+
border: var(--gov-border-width-sm) solid;
|
|
822
|
+
|
|
823
|
+
font-size: var(--gov-type-small-font-size);
|
|
824
|
+
line-height: var(--gov-type-small-line-height);
|
|
825
|
+
font-weight: var(--gov-font-weight-medium);
|
|
826
|
+
white-space: nowrap;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/* Badges are never clickable — filtering happens in the filter bar (components/badge.md). The
|
|
830
|
+
* default cursor is therefore correct here, and is the one place it is. */
|
|
831
|
+
|
|
832
|
+
.gov-badge__icon {
|
|
833
|
+
inline-size: var(--gov-icon-size-sm);
|
|
834
|
+
block-size: var(--gov-icon-size-sm);
|
|
835
|
+
flex-shrink: 0;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/* The badge carries text + icon + colour, never colour alone (§4.1). The label is the taxonomy
|
|
839
|
+
* label, read aloud as words — no meaning lives in a title attribute. */
|
|
840
|
+
.gov-badge--neutral {
|
|
841
|
+
background: var(--gov-color-status-neutral-background);
|
|
842
|
+
border-color: var(--gov-color-status-neutral-border);
|
|
843
|
+
color: var(--gov-color-status-neutral-text);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
.gov-badge--info {
|
|
847
|
+
background: var(--gov-color-status-info-background);
|
|
848
|
+
border-color: var(--gov-color-status-info-border);
|
|
849
|
+
color: var(--gov-color-status-info-text);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.gov-badge--success {
|
|
853
|
+
background: var(--gov-color-status-success-background);
|
|
854
|
+
border-color: var(--gov-color-status-success-border);
|
|
855
|
+
color: var(--gov-color-status-success-text);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.gov-badge--warning {
|
|
859
|
+
background: var(--gov-color-status-warning-background);
|
|
860
|
+
border-color: var(--gov-color-status-warning-border);
|
|
861
|
+
color: var(--gov-color-status-warning-text);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.gov-badge--error {
|
|
865
|
+
background: var(--gov-color-status-error-background);
|
|
866
|
+
border-color: var(--gov-color-status-error-border);
|
|
867
|
+
color: var(--gov-color-status-error-text);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/* Government header (components/header.md, implementing identity/government-header).
|
|
871
|
+
*
|
|
872
|
+
* "The most-rendered identity surface in the whole system — every service, every page. It is
|
|
873
|
+
* deliberately boring: identical everywhere." There is no variant per ministry and no opt-out:
|
|
874
|
+
* a single header pattern is the citizen's primary cue that a site is genuinely governmental,
|
|
875
|
+
* and that only works if it is absolutely consistent (§9.2). Only the office name and service
|
|
876
|
+
* name change. */
|
|
877
|
+
|
|
878
|
+
.gov-header {
|
|
879
|
+
background: var(--gov-color-background-surface);
|
|
880
|
+
/* The 4px Simrik top rule is the single permitted crimson identity accent on the page.
|
|
881
|
+
* color.identity.* is reserved for the state; it is never a status, never destructive, and
|
|
882
|
+
* never interactive decoration (§2.1, §5.2). */
|
|
883
|
+
border-block-start: var(--gov-border-width-lg) solid var(--gov-color-identity-crimson);
|
|
884
|
+
border-block-end: var(--gov-border-width-sm) solid var(--gov-color-border-default);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.gov-header__inner {
|
|
888
|
+
display: flex;
|
|
889
|
+
align-items: center;
|
|
890
|
+
gap: var(--gov-space-4);
|
|
891
|
+
padding-block: var(--gov-space-3);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.gov-header__lockup {
|
|
895
|
+
display: flex;
|
|
896
|
+
align-items: center;
|
|
897
|
+
gap: var(--gov-space-3);
|
|
898
|
+
/* The lockup as a whole is not a link target competing with the service name. */
|
|
899
|
+
text-decoration: none;
|
|
900
|
+
color: var(--gov-color-text-primary);
|
|
901
|
+
margin-inline-end: auto;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/* The emblem is loaded from the verified master in design-assets. It is NEVER drawn here — not
|
|
905
|
+
* as an inline SVG, not as a font glyph, not as an approximation. Recreating, recolouring, or
|
|
906
|
+
* tracing it is prohibited (identity/emblem), and an outdated or redrawn emblem is a legal error,
|
|
907
|
+
* not a style choice. The reversed variant is selected for dark surfaces by the behavior layer. */
|
|
908
|
+
.gov-header__emblem {
|
|
909
|
+
block-size: 48px;
|
|
910
|
+
inline-size: auto;
|
|
911
|
+
flex-shrink: 0;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* Dev-only: shown when no emblem asset has been supplied. It is deliberately ugly and says so.
|
|
915
|
+
* design-assets/emblems/files/ is currently EMPTY — no verified master exists yet — and the one
|
|
916
|
+
* thing this system must not do is invent a stand-in that looks plausible enough to ship. */
|
|
917
|
+
.gov-header__emblem-missing {
|
|
918
|
+
display: flex;
|
|
919
|
+
align-items: center;
|
|
920
|
+
justify-content: center;
|
|
921
|
+
block-size: 48px;
|
|
922
|
+
inline-size: 48px;
|
|
923
|
+
flex-shrink: 0;
|
|
924
|
+
border: var(--gov-border-width-md) dashed var(--gov-color-status-error-border);
|
|
925
|
+
color: var(--gov-color-status-error-text);
|
|
926
|
+
font-size: var(--gov-type-caption-font-size);
|
|
927
|
+
line-height: 1.1;
|
|
928
|
+
text-align: center;
|
|
929
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/* Nepali first, English second — Article 7 makes Nepali in Devanagari the language of official
|
|
933
|
+
* business, and the header is where that is most visible (identity/government-header). */
|
|
934
|
+
.gov-header__office {
|
|
935
|
+
display: flex;
|
|
936
|
+
flex-direction: column;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.gov-header__office-ne {
|
|
940
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.gov-header__office-en {
|
|
944
|
+
color: var(--gov-color-text-secondary);
|
|
945
|
+
font-size: var(--gov-type-small-font-size);
|
|
946
|
+
line-height: var(--gov-type-small-line-height);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.gov-header__service {
|
|
950
|
+
font-size: var(--gov-type-h3-font-size);
|
|
951
|
+
line-height: var(--gov-type-h3-line-height);
|
|
952
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/* Language switcher: TEXT, never flags. Flags represent nations, not languages — Nepal's flag
|
|
956
|
+
* must not toggle English (identity/government-header). */
|
|
957
|
+
.gov-header__language {
|
|
958
|
+
display: flex;
|
|
959
|
+
align-items: center;
|
|
960
|
+
gap: var(--gov-space-2);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.gov-header__language a {
|
|
964
|
+
min-block-size: var(--gov-target-min-size);
|
|
965
|
+
display: inline-flex;
|
|
966
|
+
align-items: center;
|
|
967
|
+
padding-inline: var(--gov-space-2);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.gov-header__language [aria-current="true"] {
|
|
971
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
972
|
+
color: var(--gov-color-text-primary);
|
|
973
|
+
text-decoration: none;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/* Mobile: condensed top bar — emblem + service name. Navigation moves to bottom-navigation
|
|
977
|
+
* (§7.2), so the header does not try to carry it (components/header.md's Platform notes). */
|
|
978
|
+
@media (max-width: 767px) {
|
|
979
|
+
.gov-header__inner {
|
|
980
|
+
flex-wrap: wrap;
|
|
981
|
+
gap: var(--gov-space-2);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
.gov-header__office-en {
|
|
985
|
+
display: none;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/* GENERATED from the light-mode token set — do not edit. See src/print.css. */
|
|
990
|
+
@media print {
|
|
991
|
+
:root {
|
|
992
|
+
--gov-color-background-default: #F7F7F5;
|
|
993
|
+
--gov-color-background-surface: #FFFFFF;
|
|
994
|
+
--gov-color-background-secondary: #F1F1EF;
|
|
995
|
+
--gov-color-background-inverse: #1F1F1F;
|
|
996
|
+
--gov-color-text-primary: #1F1F1F;
|
|
997
|
+
--gov-color-text-secondary: #6B6B66;
|
|
998
|
+
--gov-color-text-placeholder: #6B6B66;
|
|
999
|
+
--gov-color-text-disabled: #C6C6BF;
|
|
1000
|
+
--gov-color-text-inverse: #FFFFFF;
|
|
1001
|
+
--gov-color-text-on-action: #FFFFFF;
|
|
1002
|
+
--gov-color-border-default: #DEDED8;
|
|
1003
|
+
--gov-color-border-input: #8F8F88;
|
|
1004
|
+
--gov-color-border-strong: #6B6B66;
|
|
1005
|
+
--gov-color-action-primary-default: #003893;
|
|
1006
|
+
--gov-color-action-primary-hover: #002D76;
|
|
1007
|
+
--gov-color-action-primary-active: #001F52;
|
|
1008
|
+
--gov-color-action-primary-disabled-background: #E8E8E4;
|
|
1009
|
+
--gov-color-action-primary-disabled-text: #8F8F88;
|
|
1010
|
+
--gov-color-action-secondary-text: #003893;
|
|
1011
|
+
--gov-color-action-secondary-hover-background: #E8EEF9;
|
|
1012
|
+
--gov-color-action-destructive-default: #D4351C;
|
|
1013
|
+
--gov-color-action-destructive-hover: #AA2A16;
|
|
1014
|
+
--gov-color-action-destructive-active: #7F1F10;
|
|
1015
|
+
--gov-color-link-default: #003893;
|
|
1016
|
+
--gov-color-link-hover: #002D76;
|
|
1017
|
+
--gov-color-link-visited: #5B3A8E;
|
|
1018
|
+
--gov-color-focus-ring: #003893;
|
|
1019
|
+
--gov-color-focus-offset: #FFFFFF;
|
|
1020
|
+
--gov-color-identity-crimson: #C1121F;
|
|
1021
|
+
--gov-color-identity-crimson-subtle: #FBE9EA;
|
|
1022
|
+
--gov-color-identity-blue: #003893;
|
|
1023
|
+
--gov-color-identity-gold: #D6A329;
|
|
1024
|
+
--gov-color-selection-background: #D4E0F4;
|
|
1025
|
+
--gov-color-interactive-hover-surface: #F1F1EF;
|
|
1026
|
+
--gov-color-interactive-pressed-surface: #E8E8E4;
|
|
1027
|
+
--gov-color-interactive-selected-background: #D4E0F4;
|
|
1028
|
+
--gov-color-interactive-selected-indicator: #003893;
|
|
1029
|
+
--gov-color-control-track: #E8E8E4;
|
|
1030
|
+
--gov-color-control-indicator: #003893;
|
|
1031
|
+
--gov-color-control-handle: #FFFFFF;
|
|
1032
|
+
--gov-color-overlay-scrim: #171715B3;
|
|
1033
|
+
--gov-color-overlay-hover: #1F1F1F14;
|
|
1034
|
+
--gov-color-overlay-pressed: #1F1F1F29;
|
|
1035
|
+
--gov-color-status-success-text: #00703C;
|
|
1036
|
+
--gov-color-status-success-background: #E7F4EC;
|
|
1037
|
+
--gov-color-status-success-border: #00703C;
|
|
1038
|
+
--gov-color-status-warning-text: #7A4D05;
|
|
1039
|
+
--gov-color-status-warning-background: #FDF3E1;
|
|
1040
|
+
--gov-color-status-warning-border: #B25E09;
|
|
1041
|
+
--gov-color-status-info-text: #003893;
|
|
1042
|
+
--gov-color-status-info-background: #E8EEF9;
|
|
1043
|
+
--gov-color-status-info-border: #003893;
|
|
1044
|
+
--gov-color-status-error-text: #D4351C;
|
|
1045
|
+
--gov-color-status-error-background: #FEF6F5;
|
|
1046
|
+
--gov-color-status-error-border: #D4351C;
|
|
1047
|
+
--gov-color-status-neutral-text: #6B6B66;
|
|
1048
|
+
--gov-color-status-neutral-background: #F1F1EF;
|
|
1049
|
+
--gov-color-status-neutral-border: #6B6B66;
|
|
1050
|
+
}
|
|
1051
|
+
body {
|
|
1052
|
+
background: var(--gov-color-background-surface);
|
|
1053
|
+
color: var(--gov-color-text-primary);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/* Print (§5.1.5, normative).
|
|
1058
|
+
*
|
|
1059
|
+
* Print is a first-class target, not an afterthought: officers print constantly (review packets,
|
|
1060
|
+
* the print-receipt-certificate pattern) and citizens print confirmations — "the citizen usually
|
|
1061
|
+
* leaves with paper" (§8.1.7).
|
|
1062
|
+
*
|
|
1063
|
+
* The colour half of this lives in the GENERATED print block above, which re-declares every
|
|
1064
|
+
* semantic colour token at its light-mode value inside `@media print`. That is what makes "dark
|
|
1065
|
+
* mode never prints dark" true: a `[data-mode="dark"]` override on :root would otherwise still
|
|
1066
|
+
* be in force on paper. Print is a rendering target, not a seventh display mode, so it re-states
|
|
1067
|
+
* the light values rather than becoming one — and it re-states them from the tokens, so there is
|
|
1068
|
+
* still no hardcoded hex anywhere in this package.
|
|
1069
|
+
*
|
|
1070
|
+
* What follows is the structural half: what disappears, what must not break across a page, and
|
|
1071
|
+
* what a citizen needs on paper that they did not need on screen. */
|
|
1072
|
+
|
|
1073
|
+
@media print {
|
|
1074
|
+
/* Chrome disappears; content, the reference number/QR code, and the government identity mark
|
|
1075
|
+
* remain (§5.1.5). */
|
|
1076
|
+
.gov-header__language,
|
|
1077
|
+
.gov-skip-link,
|
|
1078
|
+
nav,
|
|
1079
|
+
.gov-button,
|
|
1080
|
+
[data-print="hide"] {
|
|
1081
|
+
display: none !important;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/* Shadows are an on-screen elevation device and print as grey mud. */
|
|
1085
|
+
* {
|
|
1086
|
+
box-shadow: none !important;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/* A citizen reading a printed page cannot click a link, so its URL prints beside it (§5.1.5).
|
|
1090
|
+
* Only external/absolute links — printing "(#main)" next to a skip link helps nobody. */
|
|
1091
|
+
a[href^="http"]::after {
|
|
1092
|
+
content: " (" attr(href) ")";
|
|
1093
|
+
font-size: var(--gov-type-caption-font-size);
|
|
1094
|
+
word-break: break-all;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/* Page breaks never split a table row, a summary-list question/answer pair, or a signature
|
|
1098
|
+
* block across two pages (§5.1.5). */
|
|
1099
|
+
tr,
|
|
1100
|
+
.gov-field,
|
|
1101
|
+
.gov-alert,
|
|
1102
|
+
.gov-error-summary,
|
|
1103
|
+
[data-print="keep-together"] {
|
|
1104
|
+
break-inside: avoid;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
h1, h2, h3 {
|
|
1108
|
+
break-after: avoid;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/* Status must not be carried by colour alone — and on a monochrome printer or a photocopy,
|
|
1112
|
+
* colour is carried by nothing at all. The border and the label text are what survive
|
|
1113
|
+
* (rules/status-not-color-alone.yaml applies to print, not only screen; identity/
|
|
1114
|
+
* document-identity's print-fidelity rule says the same of generated certificates). */
|
|
1115
|
+
.gov-badge,
|
|
1116
|
+
.gov-alert,
|
|
1117
|
+
.gov-error-summary {
|
|
1118
|
+
border: var(--gov-border-width-sm) solid var(--gov-color-text-primary) !important;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/* Reference numbers stay legible in monochrome print and after a photocopy — the letterhead's
|
|
1122
|
+
* monochrome-legible rule (identity/official-letterhead). */
|
|
1123
|
+
.gov-reference {
|
|
1124
|
+
font-family: var(--gov-font-family-mono);
|
|
1125
|
+
font-weight: var(--gov-font-weight-semibold);
|
|
1126
|
+
}
|
|
1127
|
+
}
|