@govnepal/css 0.1.0 → 0.2.1

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.
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Civic Calm — @govnepal/css
3
3
  * The framework-agnostic visual layer. Semantic HTML plus .gov-* classes; no JavaScript.
4
- * Built against design-guidelines 0.2.0-dev (7af0babf).
4
+ * Built against design-guidelines 0.2.0-dev (816565b5).
5
5
  *
6
6
  * This stylesheet holds ALL of Civic Calm's visual decisions. @govnepal/ui adds only behavior
7
7
  * (ARIA, keyboard, focus management) on top of these classes — so a plain-HTML site or a CMS
@@ -343,8 +343,21 @@ code, kbd, samp, pre,
343
343
  margin-inline-start: var(--gov-target-min-spacing);
344
344
  }
345
345
 
346
+ /* A button may be rendered as a link (<a class="gov-button">) for a primary call-to-action that
347
+ * navigates — a "start" button. The generic `a` and `a:visited` rules (link.css) would otherwise
348
+ * win: `a:visited` has higher specificity (0,1,1) than a single button class (0,1,0), so after one
349
+ * click the label would turn the link-visited colour — invisible on a filled button. Pinning the
350
+ * label colour on `:link`/`:visited` per variant restores the correct specificity, and the
351
+ * inherited underline is removed. */
352
+ .gov-button:link,
353
+ .gov-button:visited {
354
+ text-decoration: none;
355
+ }
356
+
346
357
  /* --- Variants ---------------------------------------------------------------------------- */
347
- .gov-button--primary {
358
+ .gov-button--primary,
359
+ .gov-button--primary:link,
360
+ .gov-button--primary:visited {
348
361
  background: var(--gov-color-action-primary-default);
349
362
  color: var(--gov-color-text-on-action);
350
363
  }
@@ -357,7 +370,9 @@ code, kbd, samp, pre,
357
370
  background: var(--gov-color-action-primary-active);
358
371
  }
359
372
 
360
- .gov-button--secondary {
373
+ .gov-button--secondary,
374
+ .gov-button--secondary:link,
375
+ .gov-button--secondary:visited {
361
376
  background: transparent;
362
377
  color: var(--gov-color-action-secondary-text);
363
378
  border-color: currentColor;
@@ -370,7 +385,9 @@ code, kbd, samp, pre,
370
385
  /* Always paired with a confirmation dialog (components/button.md) — the colour is a warning, not
371
386
  * the safeguard. Its red is deliberately the FUNCTIONAL red, never Simrik: "the colour of the
372
387
  * nation is never the colour of failure" (§2.1). */
373
- .gov-button--destructive {
388
+ .gov-button--destructive,
389
+ .gov-button--destructive:link,
390
+ .gov-button--destructive:visited {
374
391
  background: var(--gov-color-action-destructive-default);
375
392
  color: var(--gov-color-text-on-action);
376
393
  }
@@ -659,6 +676,194 @@ a:visited,
659
676
  letter-spacing: 0.1em;
660
677
  }
661
678
 
679
+ /* Checkbox and radio (components/checkbox.md, radio.md).
680
+ *
681
+ * Both are the native input with a styled indicator, and both follow the §5.2 colour hierarchy:
682
+ * the checked mark is color.action.primary — if it is interactive, it is blue. The whole row
683
+ * (input + label) is the hit target, 44px minimum, so a mistap on a phone still lands. */
684
+
685
+ .gov-choice {
686
+ display: flex;
687
+ align-items: flex-start;
688
+ gap: var(--gov-space-3);
689
+ min-block-size: var(--gov-target-min-size);
690
+ padding-block: var(--gov-space-2);
691
+ cursor: pointer;
692
+ }
693
+
694
+ /* The native input is kept (not replaced) so it stays fully accessible; it is visually sized to
695
+ * the 24px indicator and its focus ring is drawn by the shared focus rule. */
696
+ .gov-choice__input {
697
+ inline-size: 24px;
698
+ block-size: 24px;
699
+ flex-shrink: 0;
700
+ margin: 0;
701
+ accent-color: var(--gov-color-action-primary-default);
702
+ cursor: pointer;
703
+ }
704
+
705
+ .gov-choice__label {
706
+ /* Line up the label with the indicator, allowing for the taller Devanagari line. */
707
+ padding-block-start: 0.1em;
708
+ }
709
+
710
+ .gov-choice__hint {
711
+ display: block;
712
+ color: var(--gov-color-text-secondary);
713
+ font-size: var(--gov-type-small-font-size);
714
+ line-height: var(--gov-type-small-line-height);
715
+ }
716
+
717
+ /* A group of choices — the fieldset carries the question as its legend (components/checkbox.md,
718
+ * radio.md). Errors mark the group, never one option. */
719
+ .gov-choice-group {
720
+ border: 0;
721
+ padding: 0;
722
+ margin: 0;
723
+ display: flex;
724
+ flex-direction: column;
725
+ gap: var(--gov-space-2);
726
+ }
727
+
728
+ .gov-choice-group__legend {
729
+ padding: 0;
730
+ font-weight: var(--gov-font-weight-medium);
731
+ margin-block-end: var(--gov-space-2);
732
+ }
733
+
734
+ .gov-choice-group--error {
735
+ /* The whole group gets a lead edge so the error attaches to the question, not a single row. */
736
+ border-inline-start: var(--gov-border-width-lg) solid var(--gov-color-status-error-border);
737
+ padding-inline-start: var(--gov-space-4);
738
+ }
739
+
740
+ .gov-choice-group__error {
741
+ display: flex;
742
+ align-items: flex-start;
743
+ gap: var(--gov-space-2);
744
+ color: var(--gov-color-status-error-text);
745
+ font-weight: var(--gov-font-weight-medium);
746
+ }
747
+
748
+ /* Kiosk: options render as large pressable rows (§8.1.4) — a bordered card per choice. */
749
+ [data-density="kiosk-counter"] .gov-choice {
750
+ border: var(--gov-border-width-md) solid var(--gov-color-border-input);
751
+ border-radius: var(--gov-radius-md);
752
+ padding: var(--gov-space-4);
753
+ }
754
+
755
+ /* Select (components/select.md).
756
+ *
757
+ * The native <select> is the baseline on every platform — it inherits the OS picker on mobile,
758
+ * which beats any custom dropdown on a small screen and works with every assistive technology.
759
+ * Styling touches only the closed control; the option list is never restyled. */
760
+
761
+ .gov-select {
762
+ inline-size: 100%;
763
+ min-block-size: var(--gov-target-min-size);
764
+ padding-inline: var(--gov-space-3);
765
+ padding-block: var(--gov-space-3);
766
+ /* Room for the chevron on the trailing side (logical, so it flips for RTL if ever needed). */
767
+ padding-inline-end: var(--gov-space-8);
768
+
769
+ background: var(--gov-color-background-surface);
770
+ color: var(--gov-color-text-primary);
771
+ border: var(--gov-border-width-md) solid var(--gov-color-border-input);
772
+ border-radius: var(--gov-radius-sm);
773
+
774
+ font-size: var(--gov-type-body-font-size);
775
+ cursor: pointer;
776
+
777
+ /* The chevron is a background SVG using currentColor via a data URI — no icon font, no extra
778
+ * request. appearance:none removes the OS chevron so ours sits consistently. */
779
+ appearance: none;
780
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%231F1F1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
781
+ background-repeat: no-repeat;
782
+ background-position: right var(--gov-space-3) center;
783
+ }
784
+
785
+ /* The chevron colour can't read a token from inside a data URI, so restate it per dark surface. */
786
+ [data-mode="dark"] .gov-select {
787
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23F1F1EF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
788
+ }
789
+
790
+ .gov-select[aria-invalid="true"] {
791
+ border-color: var(--gov-color-status-error-border);
792
+ }
793
+
794
+ .gov-select[disabled] {
795
+ background-color: var(--gov-color-background-secondary);
796
+ color: var(--gov-color-text-disabled);
797
+ cursor: not-allowed;
798
+ }
799
+
800
+ /* The disabled first option ("Select your province") reads as an instruction, not a value. */
801
+ .gov-select option[disabled] {
802
+ color: var(--gov-color-text-placeholder);
803
+ }
804
+
805
+ /* Details (components/details.md) and warning text (components/warning-text.md).
806
+ *
807
+ * Details is native <details>/<summary> — the platform's own disclosure semantics, so a screen
808
+ * reader announces collapsed/expanded for free and Enter/Space just work. The label states what is
809
+ * inside ("Why we ask this"), never a bare "More". */
810
+
811
+ .gov-details {
812
+ border-block-start: var(--gov-border-width-sm) solid var(--gov-color-border-default);
813
+ padding-block: var(--gov-space-2);
814
+ }
815
+
816
+ .gov-details__summary {
817
+ display: flex;
818
+ align-items: center;
819
+ gap: var(--gov-space-2);
820
+ min-block-size: var(--gov-target-min-size);
821
+ cursor: pointer;
822
+ color: var(--gov-color-link-default);
823
+ font-weight: var(--gov-font-weight-medium);
824
+ /* Remove the default triangle; a rotating chevron replaces it. */
825
+ list-style: none;
826
+ }
827
+
828
+ .gov-details__summary::-webkit-details-marker {
829
+ display: none;
830
+ }
831
+
832
+ .gov-details__chevron {
833
+ inline-size: var(--gov-icon-size-md);
834
+ block-size: var(--gov-icon-size-md);
835
+ flex-shrink: 0;
836
+ transition: transform var(--gov-motion-duration-base) var(--gov-motion-easing-standard);
837
+ }
838
+
839
+ .gov-details[open] .gov-details__chevron {
840
+ transform: rotate(90deg);
841
+ }
842
+
843
+ .gov-details__content {
844
+ padding-block-start: var(--gov-space-3);
845
+ padding-inline-start: var(--gov-space-6);
846
+ color: var(--gov-color-text-secondary);
847
+ }
848
+
849
+ /* Warning text — an inline icon + a short sentence, left-aligned with what it warns about. No
850
+ * card, border, or fill: that treatment belongs to alert. The SENTENCE carries the meaning; the
851
+ * icon and colour reinforce it (rules/status-not-color-alone). */
852
+ .gov-warning-text {
853
+ display: flex;
854
+ align-items: flex-start;
855
+ gap: var(--gov-space-2);
856
+ color: var(--gov-color-status-warning-text);
857
+ font-weight: var(--gov-font-weight-medium);
858
+ }
859
+
860
+ .gov-warning-text__icon {
861
+ inline-size: var(--gov-icon-size-sm);
862
+ block-size: var(--gov-icon-size-sm);
863
+ flex-shrink: 0;
864
+ margin-block-start: 0.15em;
865
+ }
866
+
662
867
  /* Error summary (components/error-summary.md).
663
868
  *
664
869
  * Mandatory on every form, on any failed validation (§7.1) — alongside the inline errors, never
@@ -867,6 +1072,140 @@ a:visited,
867
1072
  color: var(--gov-color-status-error-text);
868
1073
  }
869
1074
 
1075
+ /* Phase banner (components/phase-banner.md), stepper (components/stepper.md), and language
1076
+ * switcher (components/language-switcher.md) — the standalone navigation pieces. */
1077
+
1078
+ /* Phase banner: a single-line band directly below the government header, above content. Plain
1079
+ * text, never colour alone. A thin Simrik-free band using a status tint. */
1080
+ .gov-phase-banner {
1081
+ display: flex;
1082
+ flex-wrap: wrap;
1083
+ align-items: baseline;
1084
+ gap: var(--gov-space-2);
1085
+ padding-block: var(--gov-space-2);
1086
+ background: var(--gov-color-status-info-background);
1087
+ border-block-end: var(--gov-border-width-sm) solid var(--gov-color-status-info-border);
1088
+ }
1089
+
1090
+ .gov-phase-banner__tag {
1091
+ font-weight: var(--gov-font-weight-semibold);
1092
+ color: var(--gov-color-status-info-text);
1093
+ text-transform: uppercase;
1094
+ font-size: var(--gov-type-small-font-size);
1095
+ letter-spacing: 0.03em;
1096
+ }
1097
+
1098
+ /* Stepper: an ordered list of named steps — completed / current / upcoming. */
1099
+ .gov-stepper {
1100
+ list-style: none;
1101
+ display: flex;
1102
+ flex-wrap: wrap;
1103
+ gap: var(--gov-space-4);
1104
+ padding: 0;
1105
+ }
1106
+
1107
+ .gov-stepper__step {
1108
+ display: flex;
1109
+ align-items: center;
1110
+ gap: var(--gov-space-2);
1111
+ color: var(--gov-color-text-secondary);
1112
+ }
1113
+
1114
+ .gov-stepper__step--complete {
1115
+ color: var(--gov-color-status-success-text);
1116
+ }
1117
+
1118
+ .gov-stepper__step--current {
1119
+ color: var(--gov-color-text-primary);
1120
+ font-weight: var(--gov-font-weight-semibold);
1121
+ }
1122
+
1123
+ .gov-stepper__marker {
1124
+ inline-size: 28px;
1125
+ block-size: 28px;
1126
+ flex-shrink: 0;
1127
+ display: inline-flex;
1128
+ align-items: center;
1129
+ justify-content: center;
1130
+ border-radius: var(--gov-radius-full);
1131
+ border: var(--gov-border-width-md) solid currentColor;
1132
+ font-size: var(--gov-type-small-font-size);
1133
+ font-weight: var(--gov-font-weight-semibold);
1134
+ }
1135
+
1136
+ .gov-stepper__step--current .gov-stepper__marker {
1137
+ background: var(--gov-color-interactive-selected-indicator);
1138
+ color: var(--gov-color-text-on-action);
1139
+ border-color: var(--gov-color-interactive-selected-indicator);
1140
+ }
1141
+
1142
+ .gov-stepper__link {
1143
+ color: inherit;
1144
+ }
1145
+
1146
+ /* Condensed "Step 2 of 5" for mobile — shown instead of the full rail below the breakpoint. */
1147
+ .gov-stepper__condensed {
1148
+ display: none;
1149
+ font-weight: var(--gov-font-weight-medium);
1150
+ }
1151
+
1152
+ @media (max-width: 767px) {
1153
+ .gov-stepper {
1154
+ display: none;
1155
+ }
1156
+ .gov-stepper__condensed {
1157
+ display: block;
1158
+ }
1159
+ }
1160
+
1161
+ /* Language switcher: a compact text toggle, each language shown by its autonym, current one
1162
+ * distinguished by weight + underline (never colour alone). */
1163
+ .gov-language-switcher {
1164
+ display: flex;
1165
+ align-items: center;
1166
+ gap: var(--gov-space-2);
1167
+ }
1168
+
1169
+ .gov-language-switcher a {
1170
+ min-block-size: var(--gov-target-min-size);
1171
+ display: inline-flex;
1172
+ align-items: center;
1173
+ padding-inline: var(--gov-space-2);
1174
+ text-decoration: none;
1175
+ color: var(--gov-color-link-default);
1176
+ }
1177
+
1178
+ .gov-language-switcher [aria-current="true"] {
1179
+ color: var(--gov-color-text-primary);
1180
+ font-weight: var(--gov-font-weight-semibold);
1181
+ text-decoration: underline;
1182
+ text-underline-offset: 0.2em;
1183
+ }
1184
+
1185
+ .gov-language-switcher__divider {
1186
+ color: var(--gov-color-text-secondary);
1187
+ }
1188
+
1189
+ /* National identity marks — the emblem and flag (identity/emblem, identity/flag).
1190
+ *
1191
+ * Base sizing only. Both are <img> of verified masters; neither is boxed, recoloured, or given a
1192
+ * background plate. The flag in particular has NO rectangular canvas — its double-pennant
1193
+ * silhouette sits directly on the page background (identity/flag), so it never gets a border or
1194
+ * fill here. */
1195
+
1196
+ .gov-emblem {
1197
+ block-size: auto;
1198
+ max-inline-size: 100%;
1199
+ }
1200
+
1201
+ .gov-flag {
1202
+ block-size: auto;
1203
+ max-inline-size: 100%;
1204
+ /* Explicitly no border, background, or box — the constitutional shape must show as-is. */
1205
+ background: none;
1206
+ border: 0;
1207
+ }
1208
+
870
1209
  /* Government header (components/header.md, implementing identity/government-header).
871
1210
  *
872
1211
  * "The most-rendered identity surface in the whole system — every service, every page. It is
@@ -901,32 +1240,17 @@ a:visited,
901
1240
  margin-inline-end: auto;
902
1241
  }
903
1242
 
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. */
1243
+ /* The emblem is loaded from the verified master (identity/emblem), never drawn here — not as an
1244
+ * inline SVG, not as a font glyph, not an approximation. Recreating, recolouring, or tracing it is
1245
+ * prohibited; an outdated or redrawn emblem is a legal error, not a style choice. */
908
1246
  .gov-header__emblem {
909
- block-size: 48px;
910
- inline-size: auto;
1247
+ display: inline-flex;
911
1248
  flex-shrink: 0;
912
1249
  }
913
1250
 
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;
1251
+ .gov-header__emblem .gov-emblem {
921
1252
  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);
1253
+ inline-size: auto;
930
1254
  }
931
1255
 
932
1256
  /* Nepali first, English second — Article 7 makes Nepali in Devanagari the language of official