edgarodriguez commited on
Commit
1c5fed2
·
verified ·
1 Parent(s): a3df526

Upload 2 files

Browse files
Files changed (2) hide show
  1. depth_interactive_map_alpha.R +116 -27
  2. styles.css +13 -0
depth_interactive_map_alpha.R CHANGED
@@ -92,17 +92,26 @@ ENVIPE_PAL <- c("#fef0d9", "#fdcc8a", "#fc8d59", "#e34a33",
92
  "#b30000", "#7f0000") # OrRd 6
93
 
94
  # GIIM keys MUST match the Spanish category strings stored in
95
- # dim_remesas_mun.giim_mun (Muy bajo / Bajo / Medio / Alto / Muy alto) so the
96
- # MapLibre `match` paint expression actually pairs each muni with a colour.
97
- # "No aplica" and "Nulo" are intentionally absent here -- they paint via the
98
- # match-fallback to fully-transparent and are filtered out of the legend.
99
  GIIM_COLORS <- c(
 
100
  "Muy bajo" = "#dbeafe",
101
  "Bajo" = "#93c5fd",
102
  "Medio" = "#3b82f6",
103
  "Alto" = "#1d4ed8",
104
  "Muy alto" = "#1e3a8a"
105
  )
 
 
 
 
 
 
 
 
106
 
107
  MIGRANTS_PAL <- c("#ffffb2", "#fecc5c", "#fd8d3c",
108
  "#f03b20", "#bd0026", "#800026") # YlOrRd 6
@@ -149,6 +158,34 @@ PATP_DELITO_PAL <- c(
149
  "Libertad personal" = "#6a3d9a"
150
  )
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  # Infrastructure point categories -- grouped from the raw "category" field
153
  # (Shelter / restaurant / Government / lodging / Legal/NGO / Food / charity /
154
  # police / hospital / Religious / embassy / Medical / place-of-worship)
@@ -227,6 +264,14 @@ POP_COLS <- list(
227
 
228
  # PATP sub-types (kind controls paint family: "num" = step, "cat" = match).
229
  PATP_COLS <- list(
 
 
 
 
 
 
 
 
230
  "t_part" = list(col = "t_part", kind = "num", label = "Economic participation rate",
231
  breaks = c(35, 45, 50, 55, 60, 70)),
232
  "t_ocup" = list(col = "t_ocup", kind = "num", label = "Occupation rate",
@@ -480,9 +525,14 @@ WEB_SQL_TEMPLATES <- list(
480
  CAST(p.ind_conec AS DOUBLE) AS ind_conec,
481
  p.pr_pred_loc_rur,
482
  p.delitos_fc_b_j_a,
 
 
 
 
483
  c.wkt
484
  FROM crime_mun c
485
- LEFT JOIN dim_patp_mun p ON c.CVEGEO = p.CVEGEO",
 
486
 
487
  src_pobreza =
488
  "SELECT c.municipio, c.entidad, c.CVEGEO,
@@ -1023,6 +1073,17 @@ WEB_SPEC <- list(
1023
  patp_delito = PATP_DELITO_PAL
1024
  ),
1025
 
 
 
 
 
 
 
 
 
 
 
 
1026
  crime_cols = CRIME_COLS,
1027
  fosas_cols = FOSAS_COLS,
1028
  envipe_cols = ENVIPE_COLS,
@@ -1185,7 +1246,7 @@ WEB_SPEC <- list(
1185
  )),
1186
  list(kind = "radios", group = "patp"),
1187
  list(kind = "layer", value = "pobreza-choro",
1188
- label = "Poverty (CONEVAL 2020)",
1189
  tooltip = "CONEVAL 2020 poverty / extreme poverty share by municipality. Enable the grid view to see this layer.",
1190
  legend = list(type = "ramp", pal = "pobreza", unit = " %",
1191
  labels = "qualitative")),
@@ -1215,10 +1276,12 @@ WEB_SPEC <- list(
1215
  list(label = "Recent resident (abroad in 2015)", value = "PRESOP2015")
1216
  ),
1217
  patp = list(
1218
- list(label = "Economic Participation rate", value = "t_part"),
 
 
1219
  list(label = "Occupation rate", value = "t_ocup"),
1220
- list(label = "PR indicator", value = "pr"),
1221
- list(label = "connectivity index", value = "ind_conec"),
1222
  list(label = "Predominant rural problem", value = "pr_pred_loc_rur"),
1223
  list(label = "Common-jurisdiction crime", value = "delitos_fc_b_j_a")
1224
  ),
@@ -1330,7 +1393,7 @@ LUCIDE_JS <- tags$head(
1330
  Shiny.setInputValue('envipe_type', 'insecurity', { priority: 'event' });
1331
  Shiny.setInputValue('fosas_type', 'fosas', { priority: 'event' });
1332
  Shiny.setInputValue('pop_type', 'POBTOT', { priority: 'event' });
1333
- Shiny.setInputValue('patp_type', 't_part', { priority: 'event' });
1334
  Shiny.setInputValue('pobreza_type','pobreza_pct', { priority: 'event' });
1335
  Shiny.setInputValue('grid_nivel', '6', { priority: 'event' });
1336
  }, 300);
@@ -1785,7 +1848,8 @@ LUCIDE_JS <- tags$head(
1785
  // by setPATPType / setPobrezaType after they update window state, and
1786
  // also by updateActiveLayers when the layer toggle flips.
1787
  var _activeVariants = { patp: 'numeric', pobreza: 'numeric' };
1788
- var PATP_NUMERIC = ['t_part','t_ocup','pr','ind_conec'];
 
1789
  var POBREZA_NUMERIC = ['pobreza_pct','pobreza_ext_pct'];
1790
 
1791
  function _variantKeyFor(group, type) {
@@ -2336,28 +2400,38 @@ acc_legend_ramp <- function(pal, lo = "Low", hi = "High") {
2336
  ))
2337
  }
2338
 
2339
- acc_legend_cats <- function(cats, filterable_key = NULL) {
 
 
 
 
 
 
 
 
 
2340
  is_filter <- !is.null(filterable_key) && nzchar(filterable_key)
2341
  items <- paste(vapply(seq_along(cats), function(i) {
2342
  nm <- names(cats)[i]
2343
  col <- unname(cats[i])
 
2344
  if (is_filter) {
2345
  paste0(
2346
  '<button type="button" class="acc-legend-cat acc-legend-cat--filter is-on"',
2347
  ' data-filter-layer="', filterable_key, '"',
2348
  ' data-cat="', htmltools::htmlEscape(nm, attribute = TRUE), '"',
2349
  ' aria-pressed="true"',
2350
- ' aria-label="Toggle category ', htmltools::htmlEscape(nm, attribute = TRUE), '"',
2351
  ' onclick="toggleLegendFilter(this)">',
2352
  '<span class="acc-legend-swatch" style="background:', col, '"></span>',
2353
- '<span class="acc-legend-cat-label">', htmltools::htmlEscape(nm), '</span>',
2354
  '</button>'
2355
  )
2356
  } else {
2357
  paste0(
2358
  '<div class="acc-legend-cat">',
2359
  '<span class="acc-legend-swatch" style="background:', col, '"></span>',
2360
- '<span>', htmltools::htmlEscape(nm), '</span>',
2361
  '</div>'
2362
  )
2363
  }
@@ -2547,7 +2621,8 @@ acc_legend_from_spec <- function(lg) {
2547
  hi = lg$hi %||% bnds$hi)
2548
  }
2549
  },
2550
- cats = acc_legend_cats(pal, filterable_key = lg$filterable),
 
2551
  dot = acc_legend_dot(lg$color, lg$label %||% "Event / point"),
2552
  line = acc_legend_line(lg$color, lg$label %||% "Route",
2553
  dashed = isTRUE(lg$dashed)),
@@ -4257,7 +4332,7 @@ server <- function(input, output, session) {
4257
  envipe_type = input$envipe_type %||% "insecurity",
4258
  fosas_type = input$fosas_type %||% "fosas",
4259
  pop_type = input$pop_type %||% "POBTOT",
4260
- patp_type = input$patp_type %||% "t_part",
4261
  pobreza_type = input$pobreza_type %||% "pobreza_pct"
4262
  )
4263
  },
@@ -4545,20 +4620,34 @@ server <- function(input, output, session) {
4545
  }
4546
  }
4547
 
4548
- treemap_plot <- function(df, pal, base_size = 7) {
 
 
 
 
4549
  laid <- treemap_layout(df)
4550
  if (is.null(laid)) return(NULL)
4551
- laid$pct <- round(100 * laid$value / sum(laid$value))
4552
- laid$label_full <- paste0(laid$label, "\n", laid$pct, "%")
 
 
 
 
 
 
 
 
 
 
4553
  ggplot(laid, aes(xmin = xmin, xmax = xmax,
4554
  ymin = ymin, ymax = ymax,
4555
  fill = label)) +
4556
  geom_rect(color = "#0f172a", linewidth = 0.4) +
4557
- geom_text(aes(x = (xmin + xmax) / 2,
4558
- y = (ymin + ymax) / 2,
4559
- label = label_full),
4560
- size = base_size / .pt * 2.4, color = "white",
4561
- fontface = "bold", lineheight = 0.85) +
4562
  scale_fill_manual(values = pal, na.value = "#334155") +
4563
  coord_cartesian(expand = FALSE, xlim = c(0, 1), ylim = c(0, 1)) +
4564
  theme_void() +
@@ -4598,7 +4687,7 @@ server <- function(input, output, session) {
4598
  value = agg$n_dead,
4599
  color = unname(CAUSE_PAL[agg$cause_cat]),
4600
  stringsAsFactors = FALSE)
4601
- treemap_plot(summary_df, CAUSE_PAL, base_size = 8)
4602
  }, bg = "transparent", res = 110)
4603
 
4604
  output$migrants_treemap_demo <- renderPlot({
@@ -4612,7 +4701,7 @@ server <- function(input, output, session) {
4612
  color = unname(DEMO_PAL),
4613
  stringsAsFactors = FALSE
4614
  )
4615
- treemap_plot(summary_df, DEMO_PAL, base_size = 8)
4616
  }, bg = "transparent", res = 110)
4617
 
4618
  # Shared helper: temporal bar chart by year for point event tables
 
92
  "#b30000", "#7f0000") # OrRd 6
93
 
94
  # GIIM keys MUST match the Spanish category strings stored in
95
+ # dim_remesas_mun.giim_mun so the MapLibre `match` paint expression pairs
96
+ # each muni with a colour. The legend displays English via GIIM_LABELS_EN.
97
+ # "No aplica" is intentionally absent -- it paints via match-fallback to
98
+ # fully transparent and is excluded from the legend.
99
  GIIM_COLORS <- c(
100
+ "Nulo" = "#94a3b8", # slate-grey (no remittance flow)
101
  "Muy bajo" = "#dbeafe",
102
  "Bajo" = "#93c5fd",
103
  "Medio" = "#3b82f6",
104
  "Alto" = "#1d4ed8",
105
  "Muy alto" = "#1e3a8a"
106
  )
107
+ GIIM_LABELS_EN <- c(
108
+ "Nulo" = "Null",
109
+ "Muy bajo" = "Very low",
110
+ "Bajo" = "Low",
111
+ "Medio" = "Medium",
112
+ "Alto" = "High",
113
+ "Muy alto" = "Very High"
114
+ )
115
 
116
  MIGRANTS_PAL <- c("#ffffb2", "#fecc5c", "#fd8d3c",
117
  "#f03b20", "#bd0026", "#800026") # YlOrRd 6
 
158
  "Libertad personal" = "#6a3d9a"
159
  )
160
 
161
+ # Spanish-key -> English-display maps used by acc_legend_cats() so that the
162
+ # data keeps matching MapLibre paint expressions (in Spanish, as stored in
163
+ # the database) while the legend reads in English. Keyed by palette name
164
+ # (giim / patp_rural / patp_delito) -- LEGEND_LABEL_MAPS[[pal_name]] is
165
+ # threaded through acc_legend_from_spec().
166
+ PATP_RURAL_LABELS_EN <- c(
167
+ "Sociales y económicos" = "Social and economic",
168
+ "Carencia o deficiencia en servicios básicos" = "Lack / deficient basic services",
169
+ "Caminos, transportes y telecomunicaciones" = "Roads, transport and telecom",
170
+ "Inseguridad, delincuencia y adicciones" = "Insecurity, crime and addictions",
171
+ "Carencia o deficiencia en la infraestructura educativa y de salud" = "Lack / deficient education and health infrastructure",
172
+ "Municipios sin localidades objetivo" = "Municipalities without target localities",
173
+ "Sin problema" = "No problem",
174
+ "Falta de información / Otro problema" = "Missing information / other",
175
+ "Riesgos ambientales" = "Environmental risk",
176
+ "Problema no definido" = "Undefined problem"
177
+ )
178
+ PATP_DELITO_LABELS_EN <- c(
179
+ "El patrimonio" = "Property",
180
+ "otros bienes" = "Other property",
181
+ "La vida y la Integridad corporal" = "Life and bodily integrity",
182
+ "múltiples bienes" = "Multiple assets",
183
+ "La familia" = "Family",
184
+ "Sin delito" = "No crime",
185
+ "La libertad y la seguridad sexual" = "Sexual freedom and safety",
186
+ "Libertad personal" = "Personal freedom"
187
+ )
188
+
189
  # Infrastructure point categories -- grouped from the raw "category" field
190
  # (Shelter / restaurant / Government / lodging / Legal/NGO / Food / charity /
191
  # police / hospital / Religious / embassy / Medical / place-of-worship)
 
264
 
265
  # PATP sub-types (kind controls paint family: "num" = step, "cat" = match).
266
  PATP_COLS <- list(
267
+ # Poverty chips come first -- the user reads PATP-CONEVAL primarily as a
268
+ # poverty layer, so the default chip + the most-used variants are at the top.
269
+ "pobreza_pct" = list(col = "pobreza_pct", kind = "num",
270
+ label = "Poverty (%)",
271
+ breaks = c(20, 35, 50, 65, 80, 90)),
272
+ "pobreza_ext_pct" = list(col = "pobreza_ext_pct", kind = "num",
273
+ label = "Extreme poverty (%)",
274
+ breaks = c(2, 5, 10, 20, 35, 55)),
275
  "t_part" = list(col = "t_part", kind = "num", label = "Economic participation rate",
276
  breaks = c(35, 45, 50, 55, 60, 70)),
277
  "t_ocup" = list(col = "t_ocup", kind = "num", label = "Occupation rate",
 
525
  CAST(p.ind_conec AS DOUBLE) AS ind_conec,
526
  p.pr_pred_loc_rur,
527
  p.delitos_fc_b_j_a,
528
+ -- Joined-in CONEVAL poverty columns so the same patp-choro layer
529
+ -- can paint by poverty / extreme-poverty without a second source.
530
+ CAST(pob.pobreza_pct AS DOUBLE) AS pobreza_pct,
531
+ CAST(pob.pobreza_ext_pct AS DOUBLE) AS pobreza_ext_pct,
532
  c.wkt
533
  FROM crime_mun c
534
+ LEFT JOIN dim_patp_mun p ON c.CVEGEO = p.CVEGEO
535
+ LEFT JOIN dim_pobreza_mun pob ON c.CVEGEO = pob.CVEGEO",
536
 
537
  src_pobreza =
538
  "SELECT c.municipio, c.entidad, c.CVEGEO,
 
1073
  patp_delito = PATP_DELITO_PAL
1074
  ),
1075
 
1076
+ # Palettes whose keys are Spanish (because that's what the database stores)
1077
+ # but whose legends should display English. acc_legend_from_spec() looks up
1078
+ # the active palette name here and passes the matching map to
1079
+ # acc_legend_cats() so the visible label is English while the data-cat
1080
+ # attribute (used by the filter + the MapLibre `match`) stays Spanish.
1081
+ legend_label_maps = list(
1082
+ giim = GIIM_LABELS_EN,
1083
+ patp_rural = PATP_RURAL_LABELS_EN,
1084
+ patp_delito = PATP_DELITO_LABELS_EN
1085
+ ),
1086
+
1087
  crime_cols = CRIME_COLS,
1088
  fosas_cols = FOSAS_COLS,
1089
  envipe_cols = ENVIPE_COLS,
 
1246
  )),
1247
  list(kind = "radios", group = "patp"),
1248
  list(kind = "layer", value = "pobreza-choro",
1249
+ label = "Poverty",
1250
  tooltip = "CONEVAL 2020 poverty / extreme poverty share by municipality. Enable the grid view to see this layer.",
1251
  legend = list(type = "ramp", pal = "pobreza", unit = " %",
1252
  labels = "qualitative")),
 
1276
  list(label = "Recent resident (abroad in 2015)", value = "PRESOP2015")
1277
  ),
1278
  patp = list(
1279
+ list(label = "Poverty (%)", value = "pobreza_pct"),
1280
+ list(label = "Extreme poverty (%)", value = "pobreza_ext_pct"),
1281
+ list(label = "Economic participation rate", value = "t_part"),
1282
  list(label = "Occupation rate", value = "t_ocup"),
1283
+ list(label = "Remittance receipt per capita", value = "pr"),
1284
+ list(label = "Road connectivity index", value = "ind_conec"),
1285
  list(label = "Predominant rural problem", value = "pr_pred_loc_rur"),
1286
  list(label = "Common-jurisdiction crime", value = "delitos_fc_b_j_a")
1287
  ),
 
1393
  Shiny.setInputValue('envipe_type', 'insecurity', { priority: 'event' });
1394
  Shiny.setInputValue('fosas_type', 'fosas', { priority: 'event' });
1395
  Shiny.setInputValue('pop_type', 'POBTOT', { priority: 'event' });
1396
+ Shiny.setInputValue('patp_type', 'pobreza_pct', { priority: 'event' });
1397
  Shiny.setInputValue('pobreza_type','pobreza_pct', { priority: 'event' });
1398
  Shiny.setInputValue('grid_nivel', '6', { priority: 'event' });
1399
  }, 300);
 
1848
  // by setPATPType / setPobrezaType after they update window state, and
1849
  // also by updateActiveLayers when the layer toggle flips.
1850
  var _activeVariants = { patp: 'numeric', pobreza: 'numeric' };
1851
+ var PATP_NUMERIC = ['pobreza_pct','pobreza_ext_pct',
1852
+ 't_part','t_ocup','pr','ind_conec'];
1853
  var POBREZA_NUMERIC = ['pobreza_pct','pobreza_ext_pct'];
1854
 
1855
  function _variantKeyFor(group, type) {
 
2400
  ))
2401
  }
2402
 
2403
+ acc_legend_cats <- function(cats, filterable_key = NULL, label_map = NULL) {
2404
+ # `label_map` (optional) maps each palette key to a different DISPLAY label.
2405
+ # The data attribute (`data-cat`) keeps the palette key so the MapLibre
2406
+ # paint expression and the filter both match what's in the database; only
2407
+ # the visible text changes. Used to render Spanish-keyed palettes (GIIM,
2408
+ # PATP rural / crime) with English legend labels.
2409
+ display_for <- function(nm) {
2410
+ if (!is.null(label_map) && nm %in% names(label_map)) unname(label_map[nm])
2411
+ else nm
2412
+ }
2413
  is_filter <- !is.null(filterable_key) && nzchar(filterable_key)
2414
  items <- paste(vapply(seq_along(cats), function(i) {
2415
  nm <- names(cats)[i]
2416
  col <- unname(cats[i])
2417
+ disp <- display_for(nm)
2418
  if (is_filter) {
2419
  paste0(
2420
  '<button type="button" class="acc-legend-cat acc-legend-cat--filter is-on"',
2421
  ' data-filter-layer="', filterable_key, '"',
2422
  ' data-cat="', htmltools::htmlEscape(nm, attribute = TRUE), '"',
2423
  ' aria-pressed="true"',
2424
+ ' aria-label="Toggle category ', htmltools::htmlEscape(disp, attribute = TRUE), '"',
2425
  ' onclick="toggleLegendFilter(this)">',
2426
  '<span class="acc-legend-swatch" style="background:', col, '"></span>',
2427
+ '<span class="acc-legend-cat-label">', htmltools::htmlEscape(disp), '</span>',
2428
  '</button>'
2429
  )
2430
  } else {
2431
  paste0(
2432
  '<div class="acc-legend-cat">',
2433
  '<span class="acc-legend-swatch" style="background:', col, '"></span>',
2434
+ '<span>', htmltools::htmlEscape(disp), '</span>',
2435
  '</div>'
2436
  )
2437
  }
 
2621
  hi = lg$hi %||% bnds$hi)
2622
  }
2623
  },
2624
+ cats = acc_legend_cats(pal, filterable_key = lg$filterable,
2625
+ label_map = WEB_SPEC$legend_label_maps[[lg$pal]]),
2626
  dot = acc_legend_dot(lg$color, lg$label %||% "Event / point"),
2627
  line = acc_legend_line(lg$color, lg$label %||% "Route",
2628
  dashed = isTRUE(lg$dashed)),
 
4332
  envipe_type = input$envipe_type %||% "insecurity",
4333
  fosas_type = input$fosas_type %||% "fosas",
4334
  pop_type = input$pop_type %||% "POBTOT",
4335
+ patp_type = input$patp_type %||% "pobreza_pct",
4336
  pobreza_type = input$pobreza_type %||% "pobreza_pct"
4337
  )
4338
  },
 
4620
  }
4621
  }
4622
 
4623
+ # Compact text inside a treemap cell: short label + smaller %, sized so
4624
+ # they actually fit a ~70px tall card slot. geom_text `size` is in mm;
4625
+ # 2.2mm ~ 6.3pt for the label and 1.8mm ~ 5.1pt for the percentage --
4626
+ # smaller than the surrounding card text, which is the point.
4627
+ treemap_plot <- function(df, pal) {
4628
  laid <- treemap_layout(df)
4629
  if (is.null(laid)) return(NULL)
4630
+ total <- sum(laid$value)
4631
+ laid$pct <- round(100 * laid$value / total)
4632
+ laid$cx <- (laid$xmin + laid$xmax) / 2
4633
+ laid$cy <- (laid$ymin + laid$ymax) / 2
4634
+ laid$w <- laid$xmax - laid$xmin
4635
+ # Truncate long labels so they don't crash the cell border. ~13 chars
4636
+ # fits a half-row at the card width; less for narrow cells.
4637
+ max_chars <- pmax(6L, pmin(20L, as.integer(laid$w * 26)))
4638
+ short <- ifelse(nchar(laid$label) > max_chars,
4639
+ paste0(substr(laid$label, 1L, max_chars - 1L), "."),
4640
+ laid$label)
4641
+ laid$short <- short
4642
  ggplot(laid, aes(xmin = xmin, xmax = xmax,
4643
  ymin = ymin, ymax = ymax,
4644
  fill = label)) +
4645
  geom_rect(color = "#0f172a", linewidth = 0.4) +
4646
+ geom_text(aes(x = cx, y = cy + 0.10, label = short),
4647
+ size = 2.2, color = "white",
4648
+ fontface = "bold", lineheight = 0.9) +
4649
+ geom_text(aes(x = cx, y = cy - 0.18, label = paste0(pct, "%")),
4650
+ size = 1.9, color = "white", alpha = 0.85) +
4651
  scale_fill_manual(values = pal, na.value = "#334155") +
4652
  coord_cartesian(expand = FALSE, xlim = c(0, 1), ylim = c(0, 1)) +
4653
  theme_void() +
 
4687
  value = agg$n_dead,
4688
  color = unname(CAUSE_PAL[agg$cause_cat]),
4689
  stringsAsFactors = FALSE)
4690
+ treemap_plot(summary_df, CAUSE_PAL)
4691
  }, bg = "transparent", res = 110)
4692
 
4693
  output$migrants_treemap_demo <- renderPlot({
 
4701
  color = unname(DEMO_PAL),
4702
  stringsAsFactors = FALSE
4703
  )
4704
+ treemap_plot(summary_df, DEMO_PAL)
4705
  }, bg = "transparent", res = 110)
4706
 
4707
  # Shared helper: temporal bar chart by year for point event tables
styles.css CHANGED
@@ -663,6 +663,19 @@
663
  padding: var(--space-1) 10px var(--space-2);
664
  }
665
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  .ind-card-note {
667
  font-size: 11px;
668
  color: var(--c-text-mid);
 
663
  padding: var(--space-1) 10px var(--space-2);
664
  }
665
 
666
+ /* Sub-heading above an inline chart (e.g. each migrants treemap). Matches the
667
+ uppercase / mid-tone scale of .ind-card-title but slightly smaller so it
668
+ reads as a sub-section, not a peer title. */
669
+ .ind-card-chart-label {
670
+ font-family: var(--font-ui);
671
+ font-size: 9px;
672
+ font-weight: 600;
673
+ letter-spacing: 0.07em;
674
+ text-transform: uppercase;
675
+ color: var(--c-text-mid);
676
+ margin-bottom: 3px;
677
+ }
678
+
679
  .ind-card-note {
680
  font-size: 11px;
681
  color: var(--c-text-mid);