pandorga 1.6.1 → 1.6.2

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: a47af06e13cc8cf5264887f7ea3236ada5a5eb2f78b357c19861b30a6493ae55
4
+ data.tar.gz: 9e155005f14faf4a30d2095f8409d655d105b32528cda1fdec14c5a4488aea2a
5
5
  SHA512:
6
- metadata.gz: c649b33b2fa0afdc8f93c3558a9e07ba8d56f18e4dff63064d9eecdca0701587c7d64fcb030ddcfc51f71f6169ba3ef8745e1c555ad8cbcc10215baf7a82d81a
7
- data.tar.gz: 79ad62fc9e7cfca6a70416fed7865ce1a4c70be646c05262ad2fe37579f4281b0ad4eaf1a5732b8fb70879c2269759b566750a6b49ee7e4f6dda19f36e282195
6
+ metadata.gz: df895fc4b0d63410a5c620b73c7e842c045743e0de76514345176d55c3cbf771a2af251748976b8efee410f0cbd58e8f5c6ccf30ead7a832b3df4d1c16a35a9c
7
+ data.tar.gz: dc6321d8dc00e651fe8fcc2fdd61b8d78f45d730225d2f7100cd1e70fe9761c48c713fe9ca1d709b2c1cd8bb699bdd42df2f8b9bd6da4d05087c85a8bccd7d7b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.2] — 2026-10-10
4
+
5
+ ### Fixed
6
+
7
+ - The home hero summary is rendered from `content/pages/cv/summary.md` at
8
+ build time. It was painted from JSON, so the paragraph's LCP was almost
9
+ all render delay.
10
+ - The summary no longer reserves six empty lines. That box shifted the
11
+ call to action when the real paragraph arrived.
12
+ - The body face is requested before the ledger sheets. `font-display: swap`
13
+ stays. The fallback is Georgia, then serif, so the swap does not reflow
14
+ the summary from a sans.
15
+
16
+ No `pandorga:` config keys were added or renamed.
17
+
3
18
  ## [1.6.1] — 2026-10-10
4
19
 
5
20
  ### 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,9 @@
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
+ <link href="https://fonts.googleapis.com" rel="preconnect" />
62
+ <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
63
+ {% include theme/font-loader.html %}
61
64
  {% include theme/critical-preload.html %}
62
65
  <link rel="stylesheet" href="/assets/css/base.css" />
63
66
  <link rel="stylesheet" href="/assets/css/global-link.css" />
@@ -107,9 +110,6 @@
107
110
  {%- for _sheet in _ledger -%}
108
111
  <link rel="stylesheet" href="/assets/css/ledger/{{ _sheet }}.css" />
109
112
  {%- endfor -%}
110
- <link href="https://fonts.googleapis.com" rel="preconnect" />
111
- <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
112
- {% include theme/font-loader.html %}
113
113
  <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
114
114
  rel="stylesheet" />
115
115
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" />
@@ -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.2"
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,64 @@
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. PLT-AC-23.
6
+
7
+ require "pathname"
8
+ require "tmpdir"
9
+ require "fileutils"
10
+
11
+ ROOT = Pathname.new(__dir__).join("..", "..").expand_path
12
+
13
+ def fail!(message)
14
+ warn "FAIL test-hero-summary: #{message}"
15
+ exit 1
16
+ end
17
+
18
+ require_relative "../../lib/pandorga/hero_summary"
19
+
20
+ Dir.mktmpdir("hero-summary") do |dir|
21
+ fail!("missing file must not invent a summary") unless Pandorga::HeroSummary.markdown(dir) == ""
22
+
23
+ path = File.join(dir, "content/pages/cv")
24
+ FileUtils.mkdir_p(path)
25
+ File.write(File.join(path, "summary.md"), "Ada Example designs publishing frames.\n")
26
+ plain = Pandorga::HeroSummary.markdown(dir)
27
+ fail!("plain summary was #{plain.inspect}") unless plain == "Ada Example designs publishing frames."
28
+
29
+ File.write(File.join(path, "summary.md"), "---\ntitle: Summary\n---\nAfter the matter.\n")
30
+ mattered = Pandorga::HeroSummary.markdown(dir)
31
+ fail!("front matter leaked: #{mattered.inspect}") unless mattered == "After the matter."
32
+ end
33
+
34
+ fallback = Pandorga::HeroSummary.element("")
35
+ fail!("missing summary must stay a quiet fragment") unless fallback.include?('data-content-fragment="cv/summary" data-content-quiet')
36
+ fail!("missing summary must not claim to be static") if fallback.include?("data-content-static")
37
+
38
+ static = Pandorga::HeroSummary.element("<p>Ada Example designs publishing frames.</p>")
39
+ fail!("static summary dropped the sentence") unless static.include?("Ada Example designs publishing frames.")
40
+ fail!("static summary is not marked static") unless static.include?("data-content-static")
41
+ fail!("static summary still hydrates") if static.include?("data-content-fragment")
42
+
43
+ home = ROOT.join("_layouts/home.html").read
44
+ home_css = ROOT.join("assets/css/ledger/home.css").read
45
+ shell = ROOT.join("_layouts/shell.html").read
46
+ fonts = ROOT.join("_includes/theme/font-loader.html").read
47
+ shared = ROOT.join("_data/themes/shared.yml").read
48
+ fragments = ROOT.join("_includes/content-runtime/60-fragments.html").read
49
+
50
+ fail!("home does not render the summary tag") unless home.include?("pandorga_hero_summary")
51
+ fail!("early paint replaces a static summary") unless home.include?("el.hasAttribute('data-content-static')")
52
+ fail!("summary keeps a guessed empty box") if home_css.include?(".home-hero-summary:empty")
53
+ fail!("a static summary can still be rewritten") unless fragments.include?("data-content-static")
54
+ fail!("font stylesheet dropped display=swap") unless fonts.include?("&display=swap")
55
+
56
+ font_at = shell.index("theme/font-loader.html")
57
+ base_at = shell.index('href="/assets/css/base.css"')
58
+ preconnect_at = shell.index("fonts.googleapis.com")
59
+ fail!("font loader missing") unless font_at
60
+ fail!("body face is requested after the ledger sheets") unless font_at < base_at
61
+ fail!("font host is not preconnected before the stylesheet") unless preconnect_at && preconnect_at < font_at
62
+ fail!("body fallback is still a sans") unless shared.include?('body_fallback: "Georgia, serif"')
63
+
64
+ 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.2
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