pandorga 1.6.1 → 1.6.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5686edc300ca78ccb310e5f59909212720c54656998508c697f56e2689e4c21b
4
- data.tar.gz: 8b6a24524c80d7e9917c784d6230016406fc5e2791f5349ca09aa509ef650fd3
3
+ metadata.gz: 107838b82bee49181ddb10435ed0ab5726579fda06fe0bc0e5399ce0f17f86ad
4
+ data.tar.gz: f8e893a43d87ed1b846a522cef98b2314c56efdfd304804354458d6c5ae9e0be
5
5
  SHA512:
6
- metadata.gz: c649b33b2fa0afdc8f93c3558a9e07ba8d56f18e4dff63064d9eecdca0701587c7d64fcb030ddcfc51f71f6169ba3ef8745e1c555ad8cbcc10215baf7a82d81a
7
- data.tar.gz: 79ad62fc9e7cfca6a70416fed7865ce1a4c70be646c05262ad2fe37579f4281b0ad4eaf1a5732b8fb70879c2269759b566750a6b49ee7e4f6dda19f36e282195
6
+ metadata.gz: df29223d7d858b285e1b1e9cf991cd3362e192895fdbcbded93c3f2cc7991f7594779b45ee5a04d7c840ac7279cf26eb23bb704b25b55f17ab7b95d4a483743d
7
+ data.tar.gz: 1e1ac9acc5c296025106b85da0bc4535ca67a3bf72061932dbffc1273f027f66d69666dc17f265eb40d9298b37b99cdf23cef2476c510a9cd1e4862a5b965bd0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.3] — 2026-10-10
4
+
5
+ ### Fixed
6
+
7
+ - The Google Fonts stylesheet is linked with the ledger sheets again. In
8
+ 1.6.2 it sat above the preload script, and that script cannot run until
9
+ earlier stylesheets finish, so first paint waited on fonts.googleapis.com.
10
+ The font hosts are still preconnected before that script. The static
11
+ summary and the serif fallback are unchanged.
12
+
13
+ No `pandorga:` config keys were added or renamed.
14
+
15
+ ## [1.6.2] — 2026-10-10
16
+
17
+ ### Fixed
18
+
19
+ - The home hero summary is rendered from `content/pages/cv/summary.md` at
20
+ build time. It was painted from JSON, so the paragraph's LCP was almost
21
+ all render delay.
22
+ - The summary no longer reserves six empty lines. That box shifted the
23
+ call to action when the real paragraph arrived.
24
+ - The body face is requested before the ledger sheets. `font-display: swap`
25
+ stays. The fallback is Georgia, then serif, so the swap does not reflow
26
+ the summary from a sans.
27
+
28
+ No `pandorga:` config keys were added or renamed.
29
+
3
30
  ## [1.6.1] — 2026-10-10
4
31
 
5
32
  ### Fixed
data/DESIGN.md CHANGED
@@ -159,7 +159,7 @@ typography:
159
159
  title: "'Cinzel Decorative', serif"
160
160
  subtitle: "'Newsreader', serif"
161
161
  label: "'Marcellus SC', serif"
162
- body: "'Newsreader', sans-serif"
162
+ body: "'Newsreader', Georgia, serif"
163
163
  mono: "'Courier Prime', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace"
164
164
  code: "'Courier Prime', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace"
165
165
  rootFontSize: "110%"
@@ -13,8 +13,9 @@ fonts:
13
13
  code: "Courier Prime"
14
14
  cv_body: "Newsreader"
15
15
  cv_body_weight: 400
16
- # Generic CSS fallback after the named face (serif | sans-serif | monospace).
17
- body_fallback: "sans-serif"
16
+ # Fallback after the named face. Body is Newsreader, a serif. A sans
17
+ # fallback reflows the hero summary when the webfont swaps in.
18
+ body_fallback: "Georgia, serif"
18
19
  subtitle_fallback: "serif"
19
20
  title_fallback: "serif"
20
21
  label_fallback: "serif"
@@ -219,7 +219,7 @@
219
219
  function mountMarkdownFragment(relativePath, elementOrId, options) {
220
220
  options = options || {};
221
221
  var el = typeof elementOrId === 'string' ? document.getElementById(elementOrId) : elementOrId;
222
- if (!el) return Promise.resolve();
222
+ if (!el || el.hasAttribute('data-content-static')) return Promise.resolve();
223
223
  // A quiet slot keeps its reserved box. Writing "Loading..." into the
224
224
  // hero summary makes that placeholder the LCP, then swaps it away.
225
225
  var quiet = el.hasAttribute('data-content-quiet');
@@ -3,4 +3,4 @@
3
3
  {% assign font_subtitle = sf.subtitle | default: "Lato" %}
4
4
  {% assign font_label = sf.label | default: "Ysabeau SC" %}
5
5
  {% assign font_body = sf.body | default: "Newsreader" %}
6
- {"title":["var(--font-title)"],"subtitle":["var(--font-subtitle)","serif"],"label":["var(--font-label)","serif"],"body":["var(--font-body)","sans-serif"],"headline":["var(--font-title)"],"editorial":["var(--font-title)"],"serif":["var(--font-title)"],"sans":["var(--font-body)","sans-serif"],"mono":["var(--font-mono)"],"code":["var(--font-code)"]}
6
+ {"title":["var(--font-title)"],"subtitle":["var(--font-subtitle)","serif"],"label":["var(--font-label)","serif"],"body":["var(--font-body)","Georgia","serif"],"headline":["var(--font-title)"],"editorial":["var(--font-title)"],"serif":["var(--font-title)"],"sans":["var(--font-body)","Georgia","serif"],"mono":["var(--font-mono)"],"code":["var(--font-code)"]}
@@ -26,7 +26,7 @@
26
26
  {% assign font_title_fallback = sf.title_fallback | default: "serif" %}
27
27
  {% assign font_subtitle_fallback = sf.subtitle_fallback | default: "serif" %}
28
28
  {% assign font_label_fallback = sf.label_fallback | default: "serif" %}
29
- {% assign font_body_fallback = sf.body_fallback | default: "sans-serif" %}
29
+ {% assign font_body_fallback = sf.body_fallback | default: "Georgia, serif" %}
30
30
  {% assign bg_secondary = tn.background_secondary | default: tn.surface_container_low | default: "#f5f5f5" %}
31
31
  {% assign surface_value = tn.surface | default: "#ffffff" %}
32
32
  {% assign surface_variant_value = tn.surface_variant | default: "#e2e2e2" %}
@@ -36,7 +36,7 @@
36
36
  --font-subtitle: '{{ font_subtitle }}', {{ font_subtitle_fallback }};
37
37
  --font-label: '{{ font_label }}', {{ font_label_fallback }};
38
38
  --font-body: '{{ font_body }}', {{ font_body_fallback }};
39
- --font-cv-body: '{{ font_cv_body }}', sans-serif;
39
+ --font-cv-body: '{{ font_cv_body }}', {{ font_body_fallback }};
40
40
  --font-cv-body-weight: {{ font_cv_body_weight }};
41
41
  --font-serif: '{{ font_title }}', {{ font_title_fallback }};
42
42
  /* Content titles share the body face at 600 — Cinzel Decorative is
data/_layouts/home.html CHANGED
@@ -33,8 +33,7 @@ layout: shell
33
33
  <h1 class="home-hero-title">
34
34
  <span class="home-hero-given">{{ _hero_name.given }}</span>{%- if _hero_name.family != "" %} <span class="home-hero-family">{{ _hero_name.family }}</span>{%- endif %}
35
35
  </h1>
36
- <div id="home-cv-summary" class="home-hero-summary font-body"
37
- data-content-fragment="cv/summary" data-content-quiet></div>
36
+ {% pandorga_hero_summary %}
38
37
  <div class="home-hero-actions">
39
38
  {%- if _cv_page -%}
40
39
  <a class="ledger-cta ledger-cta--emphasis home-hero-cta" href="{{ _cv_page.url }}">
@@ -65,7 +64,7 @@ layout: shell
65
64
  function paint(id, path) {
66
65
  var el = document.getElementById(id);
67
66
  var pending = pre[path];
68
- if (!el || !pending || !runtime || !runtime.renderMarkdown) return;
67
+ if (!el || el.hasAttribute('data-content-static') || !pending || !runtime || !runtime.renderMarkdown) return;
69
68
  pending.then(function (fragment) {
70
69
  if (!fragment || el.getAttribute('data-content-painted') === '1') return;
71
70
  var html = runtime.renderMarkdown(fragment.body_markdown || '');
data/_layouts/shell.html CHANGED
@@ -58,6 +58,14 @@
58
58
  <meta name="twitter:image" content="{{ og_image_url }}" />
59
59
  <!-- Canonical URL -->
60
60
  <link rel="canonical" href="{{ canonical_path | absolute_url }}" />
61
+ {%- comment -%}
62
+ Preconnect only. font-loader's stylesheet is render-blocking, and the
63
+ preload script below is parser-blocking. A stylesheet before that script
64
+ holds the parser until fonts.googleapis.com answers, so the ledger sheets
65
+ and the hero summary cannot paint. The face is linked with the other sheets.
66
+ {%- endcomment -%}
67
+ <link href="https://fonts.googleapis.com" rel="preconnect" />
68
+ <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
61
69
  {% include theme/critical-preload.html %}
62
70
  <link rel="stylesheet" href="/assets/css/base.css" />
63
71
  <link rel="stylesheet" href="/assets/css/global-link.css" />
@@ -107,8 +115,6 @@
107
115
  {%- for _sheet in _ledger -%}
108
116
  <link rel="stylesheet" href="/assets/css/ledger/{{ _sheet }}.css" />
109
117
  {%- endfor -%}
110
- <link href="https://fonts.googleapis.com" rel="preconnect" />
111
- <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
112
118
  {% include theme/font-loader.html %}
113
119
  <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
114
120
  rel="stylesheet" />
@@ -312,11 +312,9 @@
312
312
  line-height: var(--leading-body);
313
313
  }
314
314
 
315
- /* Hold the summary's box until the fragment paints, so the CTA under it
316
- does not jump when the paragraph arrives. */
317
- .home-hero-summary:empty {
318
- min-height: calc(var(--type-body) * var(--leading-body) * 6);
319
- }
315
+ /* No empty min-height. A guessed line count shifts the call to action
316
+ when the summary is shorter or taller than the reserve. The paragraph
317
+ is in the HTML when content/pages/cv/summary.md exists. */
320
318
 
321
319
  .home-hero-summary p {
322
320
  margin: 0 0 var(--space-md);
@@ -1,3 +1,3 @@
1
1
  /* Compiled Tailwind utilities (3.4.17, forms plugin). Replaces the Play CDN.
2
2
  Regenerate with scripts/tailwind/build.sh after adding a utility class. */
3
- *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-body),sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--font-mono);font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media (forced-colors:active) {[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.left-0{left:0}.right-0{right:0}.top-0{top:0}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-full{grid-column:1/-1}.m-0{margin:0}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1\.5{margin-top:.375rem;margin-bottom:.375rem}.my-8{margin-top:2rem;margin-bottom:2rem}.my-\[1\.55em\]{margin-top:1.55em;margin-bottom:1.55em}.mb-10{margin-bottom:2.5rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[0\.35rem\]{margin-bottom:.35rem}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.\!grid{display:grid!important}.grid{display:grid}.contents{display:contents}.\!hidden{display:none!important}.hidden{display:none}.h-12{height:3rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[12vw\]{height:12vw}.h-\[1px\]{height:1px}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.min-w-0{min-width:0}.min-w-\[14rem\]{min-width:14rem}.min-w-\[3\.5rem\]{min-width:3.5rem}.min-w-\[9\.5rem\]{min-width:9.5rem}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.max-w-xs{max-width:20rem}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.scroll-mt-28{scroll-margin-top:7rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.rounded{border-radius:.125rem}.rounded-\[9999px\]{border-radius:9999px}.border{border-width:1px}.border-0{border-width:0}.border-t{border-top-width:1px}.border-gentle{border-color:var(--border-gentle)}.border-gentle-divider{border-color:var(--border-gentle-divider)}.border-gentle-subtle{border-color:var(--border-gentle-subtle)}.bg-background{background-color:var(--color-background)}.bg-surface{background-color:var(--color-surface)}.bg-surface-container-highest{background-color:var(--color-surface-container-highest)}.bg-surface-container-low{background-color:var(--color-surface-container-low)}.bg-transparent{background-color:transparent}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-16{padding-bottom:4rem}.pb-3\.5{padding-bottom:.875rem}.pt-10{padding-top:2.5rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.align-top{vertical-align:top}.font-body{font-family:var(--font-body),sans-serif}.font-label{font-family:var(--font-label),serif}.font-mono{font-family:var(--font-mono)}.font-title{font-family:var(--font-title)}.text-5xl{font-size:3rem;line-height:1}.text-\[0\.8em\]{font-size:.8em}.text-\[0\.9em\]{font-size:.9em}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal}.ordinal,.tabular-nums{font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.tabular-nums{--tw-numeric-spacing:tabular-nums}.leading-\[1\.55\]{line-height:1.55}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-widest{letter-spacing:.1em}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-variant{color:var(--color-on-surface-variant)}.text-outline{color:var(--color-outline)}.text-primary{color:var(--color-primary)}.text-secondary{color:var(--color-secondary)}.text-tertiary{color:var(--color-tertiary)}.underline{text-decoration-line:underline}.no-underline{text-decoration-line:none}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.bg-outline-variant\/30{background-color:color-mix(in srgb,var(--color-outline-variant) 30%,transparent)}.border-tertiary\/40{border-color:color-mix(in srgb,var(--color-tertiary) 40%,transparent)}.hover\:border-primary:hover{border-color:var(--color-primary)}.hover\:border-tertiary:hover{border-color:var(--color-tertiary)}.hover\:bg-surface-container-low:hover{background-color:var(--color-surface-container-low)}.hover\:text-primary:hover{color:var(--color-primary)}.hover\:underline:hover{text-decoration-line:underline}.group:hover .group-hover\:bg-primary-container{background-color:var(--color-primary-container)}.group:hover .group-hover\:text-on-primary-container{color:var(--color-on-primary-container)}@media (min-width:640px){.sm\:gap-4{gap:1rem}.sm\:gap-5{gap:1.25rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}}@media (min-width:768px){.md\:sticky{position:sticky}.md\:top-32{top:8rem}.md\:mb-12{margin-bottom:3rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:px-16{padding-left:4rem;padding-right:4rem}.md\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:top-32{top:8rem}.lg\:gap-12{gap:3rem}}
3
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-body),Georgia,serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--font-mono);font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media (forced-colors:active) {[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.left-0{left:0}.right-0{right:0}.top-0{top:0}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-full{grid-column:1/-1}.m-0{margin:0}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1\.5{margin-top:.375rem;margin-bottom:.375rem}.my-8{margin-top:2rem;margin-bottom:2rem}.my-\[1\.55em\]{margin-top:1.55em;margin-bottom:1.55em}.mb-10{margin-bottom:2.5rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[0\.35rem\]{margin-bottom:.35rem}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.\!grid{display:grid!important}.grid{display:grid}.contents{display:contents}.\!hidden{display:none!important}.hidden{display:none}.h-12{height:3rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[12vw\]{height:12vw}.h-\[1px\]{height:1px}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.min-w-0{min-width:0}.min-w-\[14rem\]{min-width:14rem}.min-w-\[3\.5rem\]{min-width:3.5rem}.min-w-\[9\.5rem\]{min-width:9.5rem}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.max-w-xs{max-width:20rem}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.scroll-mt-28{scroll-margin-top:7rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.rounded{border-radius:.125rem}.rounded-\[9999px\]{border-radius:9999px}.border{border-width:1px}.border-0{border-width:0}.border-t{border-top-width:1px}.border-gentle{border-color:var(--border-gentle)}.border-gentle-divider{border-color:var(--border-gentle-divider)}.border-gentle-subtle{border-color:var(--border-gentle-subtle)}.bg-background{background-color:var(--color-background)}.bg-surface{background-color:var(--color-surface)}.bg-surface-container-highest{background-color:var(--color-surface-container-highest)}.bg-surface-container-low{background-color:var(--color-surface-container-low)}.bg-transparent{background-color:transparent}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-16{padding-bottom:4rem}.pb-3\.5{padding-bottom:.875rem}.pt-10{padding-top:2.5rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.align-top{vertical-align:top}.font-body{font-family:var(--font-body),Georgia,serif}.font-label{font-family:var(--font-label),serif}.font-mono{font-family:var(--font-mono)}.font-title{font-family:var(--font-title)}.text-5xl{font-size:3rem;line-height:1}.text-\[0\.8em\]{font-size:.8em}.text-\[0\.9em\]{font-size:.9em}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal}.ordinal,.tabular-nums{font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.tabular-nums{--tw-numeric-spacing:tabular-nums}.leading-\[1\.55\]{line-height:1.55}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-widest{letter-spacing:.1em}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-variant{color:var(--color-on-surface-variant)}.text-outline{color:var(--color-outline)}.text-primary{color:var(--color-primary)}.text-secondary{color:var(--color-secondary)}.text-tertiary{color:var(--color-tertiary)}.underline{text-decoration-line:underline}.no-underline{text-decoration-line:none}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.bg-outline-variant\/30{background-color:color-mix(in srgb,var(--color-outline-variant) 30%,transparent)}.border-tertiary\/40{border-color:color-mix(in srgb,var(--color-tertiary) 40%,transparent)}.hover\:border-primary:hover{border-color:var(--color-primary)}.hover\:border-tertiary:hover{border-color:var(--color-tertiary)}.hover\:bg-surface-container-low:hover{background-color:var(--color-surface-container-low)}.hover\:text-primary:hover{color:var(--color-primary)}.hover\:underline:hover{text-decoration-line:underline}.group:hover .group-hover\:bg-primary-container{background-color:var(--color-primary-container)}.group:hover .group-hover\:text-on-primary-container{color:var(--color-on-primary-container)}@media (min-width:640px){.sm\:gap-4{gap:1rem}.sm\:gap-5{gap:1.25rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}}@media (min-width:768px){.md\:sticky{position:sticky}.md\:top-32{top:8rem}.md\:mb-12{margin-bottom:3rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:px-16{padding-left:4rem;padding-right:4rem}.md\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:top-32{top:8rem}.lg\:gap-12{gap:3rem}}
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Home hero summary from content/pages/cv/summary.md.
4
+ # That paragraph is the LCP element. Leaving it empty until JSON arrives
5
+ # makes most of LCP render delay, and a guessed empty box shifts the
6
+ # call to action when the real text replaces it.
7
+ # Refs: PLT-AC-23
8
+ module Pandorga
9
+ module HeroSummary
10
+ RELATIVE = "content/pages/cv/summary.md"
11
+ FALLBACK = '<div id="home-cv-summary" class="home-hero-summary font-body" ' \
12
+ 'data-content-fragment="cv/summary" data-content-quiet></div>'
13
+
14
+ module_function
15
+
16
+ def markdown(source_root)
17
+ root = File.expand_path(source_root.to_s)
18
+ path = File.expand_path(RELATIVE, root)
19
+ prefix = root.end_with?(File::SEPARATOR) ? root : root + File::SEPARATOR
20
+ return "" unless path.start_with?(prefix)
21
+ return "" unless File.file?(path)
22
+
23
+ strip_front_matter(File.read(path, encoding: "UTF-8")).strip
24
+ end
25
+
26
+ def strip_front_matter(text)
27
+ text = text.to_s.sub(/\A\xEF\xBB\xBF/, "")
28
+ return text unless text.start_with?("---\n")
29
+
30
+ parts = text.split(/^---\s*$\n?/, 3)
31
+ return text unless parts.length == 3
32
+
33
+ parts[2]
34
+ end
35
+
36
+ def html_for(site)
37
+ text = markdown(site.source)
38
+ return "" if text.empty?
39
+
40
+ converter = site.find_converter_instance(::Jekyll::Converters::Markdown)
41
+ converter.convert(text).to_s.strip
42
+ end
43
+
44
+ def element(html)
45
+ body = html.to_s.strip
46
+ return FALLBACK if body.empty?
47
+
48
+ %(<div id="home-cv-summary" class="home-hero-summary font-body" data-content-static>#{body}</div>)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll"
4
+ require_relative "../../hero_summary"
5
+
6
+ module Pandorga
7
+ # Emits the hero summary element. HTML is raw so the paragraph is in the
8
+ # first response when the markdown file exists.
9
+ class HeroSummaryTag < Liquid::Tag
10
+ def render(context)
11
+ site = context.registers[:site]
12
+ HeroSummary.element(HeroSummary.html_for(site))
13
+ end
14
+ end
15
+ end
16
+
17
+ Liquid::Template.register_tag("pandorga_hero_summary", Pandorga::HeroSummaryTag)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pandorga
4
- VERSION = "1.6.1"
4
+ VERSION = "1.6.3"
5
5
  end
@@ -81,11 +81,11 @@ module.exports = {
81
81
  title: ["var(--font-title)"],
82
82
  subtitle: ["var(--font-subtitle)", "serif"],
83
83
  label: ["var(--font-label)", "serif"],
84
- body: ["var(--font-body)", "sans-serif"],
84
+ body: ["var(--font-body)", "Georgia", "serif"],
85
85
  headline: ["var(--font-title)"],
86
86
  editorial: ["var(--font-title)"],
87
87
  serif: ["var(--font-title)"],
88
- sans: ["var(--font-body)", "sans-serif"],
88
+ sans: ["var(--font-body)", "Georgia", "serif"],
89
89
  mono: ["var(--font-mono)"],
90
90
  code: ["var(--font-code)"],
91
91
  },
@@ -55,6 +55,26 @@ end
55
55
  warn "FAIL test-examples-build: #{name} home layout missing"
56
56
  exit 1
57
57
  end
58
+ static_summary = 'id="home-cv-summary" class="home-hero-summary font-body" data-content-static>'
59
+ if name == "full"
60
+ unless html.include?(static_summary) && html.include?("Ada Example designs publishing frames")
61
+ warn "FAIL test-examples-build: full home summary is not static HTML"
62
+ exit 1
63
+ end
64
+ if html.include?('data-content-fragment="cv/summary"')
65
+ warn "FAIL test-examples-build: full home still hydrates the summary"
66
+ exit 1
67
+ end
68
+ else
69
+ unless html.include?('id="home-cv-summary" class="home-hero-summary font-body" data-content-fragment="cv/summary" data-content-quiet')
70
+ warn "FAIL test-examples-build: minimal home dropped the summary fallback"
71
+ exit 1
72
+ end
73
+ if html.include?(static_summary)
74
+ warn "FAIL test-examples-build: minimal home inlined a missing summary"
75
+ exit 1
76
+ end
77
+ end
58
78
  origin = name == "full" ? "https://example.org" : "https://example.com"
59
79
  sitemap = example.join("_site/sitemap.xml").read
60
80
  robots = example.join("_site/robots.txt").read
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Hero summary is HTML at build time. The empty box and the sans fallback
5
+ # were the home CLS. The font stylesheet must not precede the preload
6
+ # script: that script is parser-blocking, so a sheet above it holds first
7
+ # paint on fonts.googleapis.com. PLT-AC-23.
8
+
9
+ require "pathname"
10
+ require "tmpdir"
11
+ require "fileutils"
12
+
13
+ ROOT = Pathname.new(__dir__).join("..", "..").expand_path
14
+
15
+ def fail!(message)
16
+ warn "FAIL test-hero-summary: #{message}"
17
+ exit 1
18
+ end
19
+
20
+ require_relative "../../lib/pandorga/hero_summary"
21
+
22
+ Dir.mktmpdir("hero-summary") do |dir|
23
+ fail!("missing file must not invent a summary") unless Pandorga::HeroSummary.markdown(dir) == ""
24
+
25
+ path = File.join(dir, "content/pages/cv")
26
+ FileUtils.mkdir_p(path)
27
+ File.write(File.join(path, "summary.md"), "Ada Example designs publishing frames.\n")
28
+ plain = Pandorga::HeroSummary.markdown(dir)
29
+ fail!("plain summary was #{plain.inspect}") unless plain == "Ada Example designs publishing frames."
30
+
31
+ File.write(File.join(path, "summary.md"), "---\ntitle: Summary\n---\nAfter the matter.\n")
32
+ mattered = Pandorga::HeroSummary.markdown(dir)
33
+ fail!("front matter leaked: #{mattered.inspect}") unless mattered == "After the matter."
34
+ end
35
+
36
+ fallback = Pandorga::HeroSummary.element("")
37
+ fail!("missing summary must stay a quiet fragment") unless fallback.include?('data-content-fragment="cv/summary" data-content-quiet')
38
+ fail!("missing summary must not claim to be static") if fallback.include?("data-content-static")
39
+
40
+ static = Pandorga::HeroSummary.element("<p>Ada Example designs publishing frames.</p>")
41
+ fail!("static summary dropped the sentence") unless static.include?("Ada Example designs publishing frames.")
42
+ fail!("static summary is not marked static") unless static.include?("data-content-static")
43
+ fail!("static summary still hydrates") if static.include?("data-content-fragment")
44
+
45
+ home = ROOT.join("_layouts/home.html").read
46
+ home_css = ROOT.join("assets/css/ledger/home.css").read
47
+ shell = ROOT.join("_layouts/shell.html").read
48
+ fonts = ROOT.join("_includes/theme/font-loader.html").read
49
+ shared = ROOT.join("_data/themes/shared.yml").read
50
+ fragments = ROOT.join("_includes/content-runtime/60-fragments.html").read
51
+
52
+ fail!("home does not render the summary tag") unless home.include?("pandorga_hero_summary")
53
+ fail!("early paint replaces a static summary") unless home.include?("el.hasAttribute('data-content-static')")
54
+ fail!("summary keeps a guessed empty box") if home_css.include?(".home-hero-summary:empty")
55
+ fail!("a static summary can still be rewritten") unless fragments.include?("data-content-static")
56
+ fail!("font stylesheet dropped display=swap") unless fonts.include?("&display=swap")
57
+
58
+ font_at = shell.index("theme/font-loader.html")
59
+ base_at = shell.index('href="/assets/css/base.css"')
60
+ script_at = shell.index("theme/critical-preload.html")
61
+ preconnect_at = shell.index("fonts.googleapis.com")
62
+ fail!("font loader missing") unless font_at && script_at && base_at
63
+ fail!("font stylesheet precedes the preload script") unless script_at < font_at
64
+ fail!("font stylesheet precedes local CSS") unless base_at < font_at
65
+ fail!("font host is not preconnected before the preload script") unless preconnect_at && preconnect_at < script_at
66
+ fail!("body fallback is still a sans") unless shared.include?('body_fallback: "Georgia, serif"')
67
+
68
+ puts "PASS test-hero-summary"
@@ -35,14 +35,16 @@ fail!("loadJson ignores the preload cache") unless fragments.include?("window.__
35
35
  fail!("quiet fragments still write Loading...") unless fragments.include?("data-content-quiet")
36
36
  fail!("a painted fragment is written twice") unless fragments.include?("data-content-painted")
37
37
 
38
- fail!("hero summary is not quiet") unless home.include?('data-content-fragment="cv/summary" data-content-quiet')
38
+ summary_tag = ROOT.join("lib/pandorga/hero_summary.rb").read
39
+ fail!("hero summary fallback is not quiet") unless summary_tag.include?('data-content-fragment="cv/summary" data-content-quiet')
39
40
  fail!("hero subtitle is not quiet") unless home.include?('data-content-fragment="home/subtitle" data-content-quiet')
40
41
  fail!("hero does not paint the summary early") unless home.include?("paint('home-cv-summary'")
42
+ fail!("early paint replaces a static summary") unless home.include?("el.hasAttribute('data-content-static')")
41
43
  fail!("hero subtitle size left --type-body") unless home_css.include?("font-size: var(--type-body);")
42
44
  tagline = home_css[/\.home-hero-tagline \{[^}]*\}/m]
43
45
  fail!("tagline rule missing") unless tagline
44
46
  fail!("tagline is not body size") unless tagline.include?("font-size: var(--type-body);")
45
- fail!("hero summary has no reserved box") unless home_css.include?(".home-hero-summary:empty")
47
+ fail!("hero summary keeps a guessed empty box") if home_css.include?(".home-hero-summary:empty")
46
48
 
47
49
  fail!("articles listing has no row reserve") unless articles.include?("writing-reserve-row")
48
50
  fail!("articles lead has no reserved box") unless writing_css.include?("#articles-lead.is-pending:empty")
data/scripts/validate.sh CHANGED
@@ -58,6 +58,7 @@ TESTS=(
58
58
  scripts/test/test-validate-allowlist.rb
59
59
  scripts/test/test-shell-a11y.rb
60
60
  scripts/test/test-hydrate-reserve.rb
61
+ scripts/test/test-hero-summary.rb
61
62
  scripts/test/test-css-delivery.rb
62
63
  scripts/test/test-discovery.rb
63
64
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandorga
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Pandorga contributors
@@ -272,6 +272,7 @@ files:
272
272
  - lib/pandorga/commands/serve.rb
273
273
  - lib/pandorga/commands/studio_schema.rb
274
274
  - lib/pandorga/discovery.rb
275
+ - lib/pandorga/hero_summary.rb
275
276
  - lib/pandorga/jekyll.rb
276
277
  - lib/pandorga/jekyll/generator.rb
277
278
  - lib/pandorga/jekyll/plugins/bibliography_artifact.rb
@@ -289,6 +290,7 @@ files:
289
290
  - lib/pandorga/jekyll/plugins/force_utf8_encoding.rb
290
291
  - lib/pandorga/jekyll/plugins/git_chronology.rb
291
292
  - lib/pandorga/jekyll/plugins/git_metadata.rb
293
+ - lib/pandorga/jekyll/plugins/hero_summary.rb
292
294
  - lib/pandorga/jekyll/plugins/identity_name.rb
293
295
  - lib/pandorga/jekyll/plugins/job_sections.rb
294
296
  - lib/pandorga/jekyll/plugins/lib/content_validators.rb
@@ -404,6 +406,7 @@ files:
404
406
  - scripts/test/test-hero-name.rb
405
407
  - scripts/test/test-hero-portraits.mjs
406
408
  - scripts/test/test-hero-portraits.rb
409
+ - scripts/test/test-hero-summary.rb
407
410
  - scripts/test/test-home-band-art.rb
408
411
  - scripts/test/test-hydrate-reserve.rb
409
412
  - scripts/test/test-install-functions.rb