{{/* 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 }}