{{/*
HugoBlox Theme Engine: Typography Rendering
Resolves font families, emits @font-face for bundled fonts,
Google Fonts tags for remote fonts, and CSS custom properties.
Font resolution order (per family):
1. system-sans / system-serif / system-mono → native OS font stack
2. Bundled file in assets/dist/font/* → local @font-face
3. Fallback → Google Fonts CDN
Input: Theme config dict from get_theme_config:
- typography: { families, weights, sizes, leading, tracking, variable }
Output: @font-face (bundled) + (Google Fonts) +
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{/* Build Google Fonts URL */}}
{{ $gf_families := slice }}
{{ $seen := dict }}
{{ range $role := $roles }}
{{ with index $resolve_family $role }}
{{ if .google }}
{{ $name := .name }}
{{ $is_variable := index $variable $role | default false }}
{{/* Use full range for variable fonts, discrete weights for static */}}
{{ $weight_spec := "" }}
{{ if $is_variable }}
{{ $weight_spec = "100..900" }}
{{ else }}
{{ $role_weights := index $weights $role | default (slice 400) }}
{{ $weight_spec = delimit $role_weights "," }}
{{ end }}
{{/* Dedup key includes weight spec so the same font can appear as both static and variable if needed */}}
{{ $dedup_key := printf "%s|%s" $name $weight_spec }}
{{ if not (index $seen $dedup_key) }}
{{ $seen = merge $seen (dict $dedup_key true) }}
{{ $encoded := replace $name " " "+" }}
{{ $gf_families = $gf_families | append (printf "%s:wght@%s" $encoded $weight_spec) }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ if gt (len $gf_families) 0 }}
{{ $gf_url := printf "https://fonts.googleapis.com/css2?%s&display=swap" (delimit (apply $gf_families "printf" "family=%s" ".") "&") }}
{{ end }}
{{/* Font size vars */}}
{{ $font_size_base := $sizes.base | default "1rem" }}
{{ $font_size_sm := $sizes.sm | default "0.875rem" }}
{{ $font_size_lg := $sizes.lg | default "1.125rem" }}
{{/* Resolve CSS font-family values */}}
{{ $heading_css := $system_sans }}
{{ with index $resolve_family "heading" }}{{ $heading_css = .css }}{{ end }}
{{ $body_css := $system_sans }}
{{ with index $resolve_family "body" }}{{ $body_css = .css }}{{ end }}
{{ $code_css := $system_mono }}
{{ with index $resolve_family "code" }}{{ $code_css = .css }}{{ end }}
{{ $nav_css := $heading_css }}
{{ with index $resolve_family "nav" }}{{ if .css }}{{ $nav_css = .css }}{{ end }}{{ end }}
{{/* Get primary weight for each role (first in array) */}}
{{ $heading_weight := 700 }}
{{ with $weights.heading }}{{ $heading_weight = index . 0 }}{{ end }}
{{ $body_weight := 400 }}
{{ with $weights.body }}{{ $body_weight = index . 0 }}{{ end }}
{{/* Bold body weight: second value in array, or primary + 200 (capped at 900) */}}
{{ $body_weight_bold := math.Min 900 (add $body_weight 200) }}
{{ with $weights.body }}{{ if ge (len .) 2 }}{{ $body_weight_bold = index . 1 }}{{ end }}{{ end }}