diff --git a/_TODO.md b/_TODO.md
index 1f3a96d6..fc206ab9 100644
--- a/_TODO.md
+++ b/_TODO.md
@@ -23,15 +23,14 @@ https://aws.plainenglish.io/how-to-build-a-chatbot-using-aws-lex-and-lambda-in-2
- Moving the scroll bar up quickly with the mouse seems to make the header logic break - the Switcher component and Breadcrumbs are hidden under the header
- Themepicker and search icon are too big in non-squished header. Logo too - the initial presentation should be smaller.
-## Content Issues
+## Resume
-- Need an article on OpenStack
+- Finish styling
-## Youtube video for Backstage IDP hero on Home page
+## Env Vars
-- Discuss agentic AI integrations to add to Backstage
-- Home page reorganization: move the "What I Deliver" box from the Hero into the Backstage image. Move the Backstage image / video to the hero.
+- Add HubSpot env vars to Vercel
-## Deep Dive Link
+## Content Issues
-- Add a "Preview Special" item to our Download CTA that lets the user know the Deep Dive content can be previewed in HTML format, and offer a switch to it.
+- Need an article on OpenStack
diff --git a/public/downloads/alert-fatigue-reduction-triage-actionable-alerts.pdf b/public/downloads/alert-fatigue-reduction-triage-actionable-alerts.pdf
new file mode 100644
index 00000000..663d0f5e
Binary files /dev/null and b/public/downloads/alert-fatigue-reduction-triage-actionable-alerts.pdf differ
diff --git a/public/downloads/api-deprecation-sunset-headers-consumer-migration.pdf b/public/downloads/api-deprecation-sunset-headers-consumer-migration.pdf
new file mode 100644
index 00000000..3dd112b1
Binary files /dev/null and b/public/downloads/api-deprecation-sunset-headers-consumer-migration.pdf differ
diff --git a/public/downloads/api-gateway-metrics-traces-logs-debugging.pdf b/public/downloads/api-gateway-metrics-traces-logs-debugging.pdf
new file mode 100644
index 00000000..bd18032f
Binary files /dev/null and b/public/downloads/api-gateway-metrics-traces-logs-debugging.pdf differ
diff --git a/public/downloads/api-usage-metering-quotas-cost-attribution.pdf b/public/downloads/api-usage-metering-quotas-cost-attribution.pdf
new file mode 100644
index 00000000..fd35999b
Binary files /dev/null and b/public/downloads/api-usage-metering-quotas-cost-attribution.pdf differ
diff --git a/public/downloads/argocd-sync-failures-gitops-debugging-troubleshooting.pdf b/public/downloads/argocd-sync-failures-gitops-debugging-troubleshooting.pdf
new file mode 100644
index 00000000..cdfd0c44
Binary files /dev/null and b/public/downloads/argocd-sync-failures-gitops-debugging-troubleshooting.pdf differ
diff --git a/public/downloads/availability-targets-five-nines-cost-benefit-analysis.pdf b/public/downloads/availability-targets-five-nines-cost-benefit-analysis.pdf
new file mode 100644
index 00000000..ba47ee0f
Binary files /dev/null and b/public/downloads/availability-targets-five-nines-cost-benefit-analysis.pdf differ
diff --git a/public/downloads/backpressure-load-shedding-admission-control-overload.pdf b/public/downloads/backpressure-load-shedding-admission-control-overload.pdf
new file mode 100644
index 00000000..8e00c980
Binary files /dev/null and b/public/downloads/backpressure-load-shedding-admission-control-overload.pdf differ
diff --git a/public/downloads/blameless-postmortem-incident-analysis-systemic-causes.pdf b/public/downloads/blameless-postmortem-incident-analysis-systemic-causes.pdf
new file mode 100644
index 00000000..210d49ab
Binary files /dev/null and b/public/downloads/blameless-postmortem-incident-analysis-systemic-causes.pdf differ
diff --git a/public/downloads/blue-green-canary-deployment-strategy-comparison.pdf b/public/downloads/blue-green-canary-deployment-strategy-comparison.pdf
new file mode 100644
index 00000000..95147884
Binary files /dev/null and b/public/downloads/blue-green-canary-deployment-strategy-comparison.pdf differ
diff --git a/public/downloads/cdn-edge-caching-cache-keys-vary-headers.pdf b/public/downloads/cdn-edge-caching-cache-keys-vary-headers.pdf
new file mode 100644
index 00000000..002c135f
Binary files /dev/null and b/public/downloads/cdn-edge-caching-cache-keys-vary-headers.pdf differ
diff --git a/public/downloads/chaos-engineering-failure-injection-low-cost-experiments.pdf b/public/downloads/chaos-engineering-failure-injection-low-cost-experiments.pdf
new file mode 100644
index 00000000..d2e83052
Binary files /dev/null and b/public/downloads/chaos-engineering-failure-injection-low-cost-experiments.pdf differ
diff --git a/public/downloads/ci-pipeline-caching-docker-layers-dependency-cache.pdf b/public/downloads/ci-pipeline-caching-docker-layers-dependency-cache.pdf
index 31292705..c09cc493 100644
Binary files a/public/downloads/ci-pipeline-caching-docker-layers-dependency-cache.pdf and b/public/downloads/ci-pipeline-caching-docker-layers-dependency-cache.pdf differ
diff --git a/public/downloads/circuit-breaker-retry-budget-cascade-failure-prevention.pdf b/public/downloads/circuit-breaker-retry-budget-cascade-failure-prevention.pdf
new file mode 100644
index 00000000..98c85ac4
Binary files /dev/null and b/public/downloads/circuit-breaker-retry-budget-cascade-failure-prevention.pdf differ
diff --git a/public/downloads/consumer-driven-contract-testing-pact-internal-apis.pdf b/public/downloads/consumer-driven-contract-testing-pact-internal-apis.pdf
new file mode 100644
index 00000000..d2530f59
Binary files /dev/null and b/public/downloads/consumer-driven-contract-testing-pact-internal-apis.pdf differ
diff --git a/public/downloads/container-vulnerability-scanning-ci-shift-left-security.pdf b/public/downloads/container-vulnerability-scanning-ci-shift-left-security.pdf
new file mode 100644
index 00000000..57f6e7db
Binary files /dev/null and b/public/downloads/container-vulnerability-scanning-ci-shift-left-security.pdf differ
diff --git a/public/downloads/database-schema-migrations-continuous-deployment-zero-downtime.pdf b/public/downloads/database-schema-migrations-continuous-deployment-zero-downtime.pdf
new file mode 100644
index 00000000..ccf4dc7b
Binary files /dev/null and b/public/downloads/database-schema-migrations-continuous-deployment-zero-downtime.pdf differ
diff --git a/public/downloads/dead-letter-queue-design-replay-debugging.pdf b/public/downloads/dead-letter-queue-design-replay-debugging.pdf
new file mode 100644
index 00000000..dba78a7d
Binary files /dev/null and b/public/downloads/dead-letter-queue-design-replay-debugging.pdf differ
diff --git a/public/downloads/distributed-tracing-sampling-strategies-head-tail.pdf b/public/downloads/distributed-tracing-sampling-strategies-head-tail.pdf
new file mode 100644
index 00000000..6fd0c4bb
Binary files /dev/null and b/public/downloads/distributed-tracing-sampling-strategies-head-tail.pdf differ
diff --git a/public/downloads/eol-runtime-upgrade-dependency-hell-migration.pdf b/public/downloads/eol-runtime-upgrade-dependency-hell-migration.pdf
new file mode 100644
index 00000000..4bfaa373
Binary files /dev/null and b/public/downloads/eol-runtime-upgrade-dependency-hell-migration.pdf differ
diff --git a/public/downloads/ephemeral-preview-environments-cost-control-cleanup.pdf b/public/downloads/ephemeral-preview-environments-cost-control-cleanup.pdf
new file mode 100644
index 00000000..9ac04473
Binary files /dev/null and b/public/downloads/ephemeral-preview-environments-cost-control-cleanup.pdf differ
diff --git a/public/downloads/flaky-test-diagnosis-race-conditions-e2e-stabilization.pdf b/public/downloads/flaky-test-diagnosis-race-conditions-e2e-stabilization.pdf
new file mode 100644
index 00000000..3e6c94c1
Binary files /dev/null and b/public/downloads/flaky-test-diagnosis-race-conditions-e2e-stabilization.pdf differ
diff --git a/public/downloads/golden-paths-developer-experience-standardization-autonomy.pdf b/public/downloads/golden-paths-developer-experience-standardization-autonomy.pdf
new file mode 100644
index 00000000..20d44aaa
Binary files /dev/null and b/public/downloads/golden-paths-developer-experience-standardization-autonomy.pdf differ
diff --git a/public/downloads/grafana-dashboard-hygiene-pruning-actionable-metrics.pdf b/public/downloads/grafana-dashboard-hygiene-pruning-actionable-metrics.pdf
new file mode 100644
index 00000000..73989c95
Binary files /dev/null and b/public/downloads/grafana-dashboard-hygiene-pruning-actionable-metrics.pdf differ
diff --git a/public/downloads/helm-release-management-drift-detection-debugging.pdf b/public/downloads/helm-release-management-drift-detection-debugging.pdf
new file mode 100644
index 00000000..4a232d68
Binary files /dev/null and b/public/downloads/helm-release-management-drift-detection-debugging.pdf differ
diff --git a/public/downloads/idempotent-message-handlers-deduplication-retries.pdf b/public/downloads/idempotent-message-handlers-deduplication-retries.pdf
new file mode 100644
index 00000000..140b3a11
Binary files /dev/null and b/public/downloads/idempotent-message-handlers-deduplication-retries.pdf differ
diff --git a/public/downloads/internal-cli-kubectl-terraform-wrapper-abstraction.pdf b/public/downloads/internal-cli-kubectl-terraform-wrapper-abstraction.pdf
new file mode 100644
index 00000000..fbb38b54
Binary files /dev/null and b/public/downloads/internal-cli-kubectl-terraform-wrapper-abstraction.pdf differ
diff --git a/public/downloads/internal-developer-portal-platform-self-service-actions.pdf b/public/downloads/internal-developer-portal-platform-self-service-actions.pdf
new file mode 100644
index 00000000..7a07891d
Binary files /dev/null and b/public/downloads/internal-developer-portal-platform-self-service-actions.pdf differ
diff --git a/public/downloads/internal-platform-api-versioning-deprecation-breaking-changes.pdf b/public/downloads/internal-platform-api-versioning-deprecation-breaking-changes.pdf
new file mode 100644
index 00000000..2620a371
Binary files /dev/null and b/public/downloads/internal-platform-api-versioning-deprecation-breaking-changes.pdf differ
diff --git a/public/downloads/kubernetes-cluster-upgrade-playbook-risk-reduction.pdf b/public/downloads/kubernetes-cluster-upgrade-playbook-risk-reduction.pdf
new file mode 100644
index 00000000..c289a16d
Binary files /dev/null and b/public/downloads/kubernetes-cluster-upgrade-playbook-risk-reduction.pdf differ
diff --git a/public/downloads/kubernetes-cost-optimization-resource-sizing-spot-instances.pdf b/public/downloads/kubernetes-cost-optimization-resource-sizing-spot-instances.pdf
new file mode 100644
index 00000000..8e9f8aac
Binary files /dev/null and b/public/downloads/kubernetes-cost-optimization-resource-sizing-spot-instances.pdf differ
diff --git a/public/downloads/kubernetes-decision-framework-when-not-to-use.pdf b/public/downloads/kubernetes-decision-framework-when-not-to-use.pdf
new file mode 100644
index 00000000..e306b122
Binary files /dev/null and b/public/downloads/kubernetes-decision-framework-when-not-to-use.pdf differ
diff --git a/public/downloads/kubernetes-dns-debugging-ndots-coredns-troubleshooting.pdf b/public/downloads/kubernetes-dns-debugging-ndots-coredns-troubleshooting.pdf
new file mode 100644
index 00000000..07dfc351
Binary files /dev/null and b/public/downloads/kubernetes-dns-debugging-ndots-coredns-troubleshooting.pdf differ
diff --git a/public/downloads/kubernetes-hpa-autoscaling-metrics-tuning-latency.pdf b/public/downloads/kubernetes-hpa-autoscaling-metrics-tuning-latency.pdf
new file mode 100644
index 00000000..c3de6e8d
Binary files /dev/null and b/public/downloads/kubernetes-hpa-autoscaling-metrics-tuning-latency.pdf differ
diff --git a/public/downloads/kubernetes-ingress-gateway-api-comparison-migration.pdf b/public/downloads/kubernetes-ingress-gateway-api-comparison-migration.pdf
new file mode 100644
index 00000000..0ce07bc1
Binary files /dev/null and b/public/downloads/kubernetes-ingress-gateway-api-comparison-migration.pdf differ
diff --git a/public/downloads/kubernetes-multi-cluster-fleet-management-configuration.pdf b/public/downloads/kubernetes-multi-cluster-fleet-management-configuration.pdf
new file mode 100644
index 00000000..75ab25dd
Binary files /dev/null and b/public/downloads/kubernetes-multi-cluster-fleet-management-configuration.pdf differ
diff --git a/public/downloads/kubernetes-pod-resource-requests-limits-qos-classes.pdf b/public/downloads/kubernetes-pod-resource-requests-limits-qos-classes.pdf
new file mode 100644
index 00000000..9aae0a8b
Binary files /dev/null and b/public/downloads/kubernetes-pod-resource-requests-limits-qos-classes.pdf differ
diff --git a/public/downloads/kubernetes-secrets-external-secrets-operator-csi-vault.pdf b/public/downloads/kubernetes-secrets-external-secrets-operator-csi-vault.pdf
new file mode 100644
index 00000000..fd5ac7bb
Binary files /dev/null and b/public/downloads/kubernetes-secrets-external-secrets-operator-csi-vault.pdf differ
diff --git a/public/downloads/legacy-code-testing-characterization-tests-seams.pdf b/public/downloads/legacy-code-testing-characterization-tests-seams.pdf
new file mode 100644
index 00000000..250ae4e1
Binary files /dev/null and b/public/downloads/legacy-code-testing-characterization-tests-seams.pdf differ
diff --git a/public/downloads/monorepo-affected-builds-remote-caching-ci-optimization.pdf b/public/downloads/monorepo-affected-builds-remote-caching-ci-optimization.pdf
new file mode 100644
index 00000000..ac3a8ad7
Binary files /dev/null and b/public/downloads/monorepo-affected-builds-remote-caching-ci-optimization.pdf differ
diff --git a/public/downloads/mtls-certificate-rotation-service-mesh-authentication.pdf b/public/downloads/mtls-certificate-rotation-service-mesh-authentication.pdf
new file mode 100644
index 00000000..a43f15fb
Binary files /dev/null and b/public/downloads/mtls-certificate-rotation-service-mesh-authentication.pdf differ
diff --git a/public/downloads/nginx-haproxy-reverse-proxy-production-tuning.pdf b/public/downloads/nginx-haproxy-reverse-proxy-production-tuning.pdf
new file mode 100644
index 00000000..bfa871eb
Binary files /dev/null and b/public/downloads/nginx-haproxy-reverse-proxy-production-tuning.pdf differ
diff --git a/public/downloads/on-call-rotation-small-teams-sustainable-coverage.pdf b/public/downloads/on-call-rotation-small-teams-sustainable-coverage.pdf
new file mode 100644
index 00000000..c47a8b0c
Binary files /dev/null and b/public/downloads/on-call-rotation-small-teams-sustainable-coverage.pdf differ
diff --git a/public/downloads/opa-conftest-policy-as-code-infrastructure-guardrails.pdf b/public/downloads/opa-conftest-policy-as-code-infrastructure-guardrails.pdf
new file mode 100644
index 00000000..7514ea8c
Binary files /dev/null and b/public/downloads/opa-conftest-policy-as-code-infrastructure-guardrails.pdf differ
diff --git a/public/downloads/openapi-spec-documentation-sdk-generation-validation.pdf b/public/downloads/openapi-spec-documentation-sdk-generation-validation.pdf
new file mode 100644
index 00000000..c2c87330
Binary files /dev/null and b/public/downloads/openapi-spec-documentation-sdk-generation-validation.pdf differ
diff --git a/public/downloads/opentelemetry-span-design-granularity-overhead.pdf b/public/downloads/opentelemetry-span-design-granularity-overhead.pdf
new file mode 100644
index 00000000..610954aa
Binary files /dev/null and b/public/downloads/opentelemetry-span-design-granularity-overhead.pdf differ
diff --git a/public/downloads/performance-testing-load-models-benchmark-accuracy.pdf b/public/downloads/performance-testing-load-models-benchmark-accuracy.pdf
new file mode 100644
index 00000000..43a4b9d3
Binary files /dev/null and b/public/downloads/performance-testing-load-models-benchmark-accuracy.pdf differ
diff --git a/public/downloads/platform-architecture-control-plane-data-plane-separation.pdf b/public/downloads/platform-architecture-control-plane-data-plane-separation.pdf
new file mode 100644
index 00000000..d2b3a1bd
Binary files /dev/null and b/public/downloads/platform-architecture-control-plane-data-plane-separation.pdf differ
diff --git a/public/downloads/platform-engineering-metrics-lead-time-developer-friction.pdf b/public/downloads/platform-engineering-metrics-lead-time-developer-friction.pdf
new file mode 100644
index 00000000..8e23a5f8
Binary files /dev/null and b/public/downloads/platform-engineering-metrics-lead-time-developer-friction.pdf differ
diff --git a/public/downloads/postgresql-connection-pooling-saturation-sizing.pdf b/public/downloads/postgresql-connection-pooling-saturation-sizing.pdf
new file mode 100644
index 00000000..67695c71
Binary files /dev/null and b/public/downloads/postgresql-connection-pooling-saturation-sizing.pdf differ
diff --git a/public/downloads/private-networking-dns-routing-tls-debugging.pdf b/public/downloads/private-networking-dns-routing-tls-debugging.pdf
new file mode 100644
index 00000000..05c36966
Binary files /dev/null and b/public/downloads/private-networking-dns-routing-tls-debugging.pdf differ
diff --git a/public/downloads/prometheus-high-cardinality-metrics-label-design.pdf b/public/downloads/prometheus-high-cardinality-metrics-label-design.pdf
new file mode 100644
index 00000000..811e0323
Binary files /dev/null and b/public/downloads/prometheus-high-cardinality-metrics-label-design.pdf differ
diff --git a/public/downloads/rate-limiting-token-bucket-leaky-bucket-implementation.pdf b/public/downloads/rate-limiting-token-bucket-leaky-bucket-implementation.pdf
new file mode 100644
index 00000000..4826fecd
Binary files /dev/null and b/public/downloads/rate-limiting-token-bucket-leaky-bucket-implementation.pdf differ
diff --git a/public/downloads/release-quality-gates-automated-deployment-validation.pdf b/public/downloads/release-quality-gates-automated-deployment-validation.pdf
new file mode 100644
index 00000000..36532735
Binary files /dev/null and b/public/downloads/release-quality-gates-automated-deployment-validation.pdf differ
diff --git a/public/downloads/reverse-engineering-documentation-legacy-systems.pdf b/public/downloads/reverse-engineering-documentation-legacy-systems.pdf
new file mode 100644
index 00000000..9a24cdd0
Binary files /dev/null and b/public/downloads/reverse-engineering-documentation-legacy-systems.pdf differ
diff --git a/public/downloads/service-catalog-metadata-schema-ownership-tracking.pdf b/public/downloads/service-catalog-metadata-schema-ownership-tracking.pdf
new file mode 100644
index 00000000..9fc1684c
Binary files /dev/null and b/public/downloads/service-catalog-metadata-schema-ownership-tracking.pdf differ
diff --git a/public/downloads/service-decommissioning-scream-test-shutdown.pdf b/public/downloads/service-decommissioning-scream-test-shutdown.pdf
new file mode 100644
index 00000000..43615542
Binary files /dev/null and b/public/downloads/service-decommissioning-scream-test-shutdown.pdf differ
diff --git a/public/downloads/slo-error-budget-practical-guide.pdf b/public/downloads/slo-error-budget-practical-guide.pdf
new file mode 100644
index 00000000..ea209154
Binary files /dev/null and b/public/downloads/slo-error-budget-practical-guide.pdf differ
diff --git a/public/downloads/slsa-build-provenance-artifact-signing-supply-chain.pdf b/public/downloads/slsa-build-provenance-artifact-signing-supply-chain.pdf
new file mode 100644
index 00000000..3260619a
Binary files /dev/null and b/public/downloads/slsa-build-provenance-artifact-signing-supply-chain.pdf differ
diff --git a/public/downloads/strangler-fig-migration-complete-guide.pdf b/public/downloads/strangler-fig-migration-complete-guide.pdf
new file mode 100644
index 00000000..556a7a75
Binary files /dev/null and b/public/downloads/strangler-fig-migration-complete-guide.pdf differ
diff --git a/public/downloads/structured-logging-correlation-ids-log-schema-design.pdf b/public/downloads/structured-logging-correlation-ids-log-schema-design.pdf
new file mode 100644
index 00000000..b2ee5804
Binary files /dev/null and b/public/downloads/structured-logging-correlation-ids-log-schema-design.pdf differ
diff --git a/public/downloads/symptom-based-alerting-runbooks-alert-design.pdf b/public/downloads/symptom-based-alerting-runbooks-alert-design.pdf
new file mode 100644
index 00000000..9b290d83
Binary files /dev/null and b/public/downloads/symptom-based-alerting-runbooks-alert-design.pdf differ
diff --git a/public/downloads/synthetic-test-data-pii-anonymization-fixtures.pdf b/public/downloads/synthetic-test-data-pii-anonymization-fixtures.pdf
new file mode 100644
index 00000000..506441e1
Binary files /dev/null and b/public/downloads/synthetic-test-data-pii-anonymization-fixtures.pdf differ
diff --git a/public/downloads/terraform-module-design-defaults-versioning-interfaces.pdf b/public/downloads/terraform-module-design-defaults-versioning-interfaces.pdf
new file mode 100644
index 00000000..817542be
Binary files /dev/null and b/public/downloads/terraform-module-design-defaults-versioning-interfaces.pdf differ
diff --git a/public/downloads/terraform-state-locking-corruption-recovery-backend.pdf b/public/downloads/terraform-state-locking-corruption-recovery-backend.pdf
new file mode 100644
index 00000000..2fd84fe0
Binary files /dev/null and b/public/downloads/terraform-state-locking-corruption-recovery-backend.pdf differ
diff --git a/public/downloads/workload-identity-federation-keyless-cloud-authentication.pdf b/public/downloads/workload-identity-federation-keyless-cloud-authentication.pdf
new file mode 100644
index 00000000..5441478d
Binary files /dev/null and b/public/downloads/workload-identity-federation-keyless-cloud-authentication.pdf differ
diff --git a/scripts/generate-pdfs/index.mjs b/scripts/generate-pdfs/index.mjs
index c46b52b5..f3647e4f 100644
--- a/scripts/generate-pdfs/index.mjs
+++ b/scripts/generate-pdfs/index.mjs
@@ -49,6 +49,8 @@ const CONTENT_PADDING_LEFT_IN = CONTENT_PADDING_CM.left / CM_PER_IN
const CONTENT_PADDING_RIGHT_IN = CONTENT_PADDING_CM.right / CM_PER_IN
const CONTENT_HEIGHT_PX = (PAGE_HEIGHT_IN - CONTENT_PADDING_TOP_IN - CONTENT_PADDING_BOTTOM_IN) * 96
const CONTENT_WIDTH_PX = (8.5 - CONTENT_PADDING_LEFT_IN - CONTENT_PADDING_RIGHT_IN) * 96
+const ASSET_SETTLE_TIMEOUT_MS = 30_000
+const LAYOUT_SETTLE_DELAY_MS = 500
// --- Templates ---
@@ -116,6 +118,81 @@ const writeMergedPdf = async ({ coverPdfBytes, fullPdfBytes, outputPdf }) => {
writeFileSync(outputPdf, await mergedPdf.save())
}
+const wait = (durationMs) => new Promise(resolve => setTimeout(resolve, durationMs))
+
+const forceLazyAssetsToLoad = async (page) => {
+ await page.evaluate(async () => {
+ const documentRoot = globalThis.document.scrollingElement ?? globalThis.document.documentElement
+ const pause = (durationMs) => new Promise(resolve => globalThis.setTimeout(resolve, durationMs))
+ const viewportHeight = globalThis.innerHeight || 800
+ const step = Math.max(200, Math.floor(viewportHeight * 0.9))
+
+ for (const image of Array.from(globalThis.document.images)) {
+ image.loading = 'eager'
+ image.decoding = 'sync'
+
+ if ('fetchPriority' in image) {
+ image.fetchPriority = 'high'
+ }
+ }
+
+ for (let top = 0; top < documentRoot.scrollHeight; top += step) {
+ documentRoot.scrollTop = top
+ await pause(50)
+ }
+
+ documentRoot.scrollTop = 0
+ await pause(50)
+ })
+}
+
+const waitForPageAssets = async (page) => {
+ await page.evaluate(async (timeoutMs) => {
+ const pause = (durationMs) => new Promise(resolve => globalThis.setTimeout(resolve, durationMs))
+ const withTimeout = async (promiseFactory) => {
+ const timeoutPromise = pause(timeoutMs)
+
+ try {
+ await Promise.race([promiseFactory(), timeoutPromise])
+ } catch {
+ await timeoutPromise
+ }
+ }
+
+ if (globalThis.document.fonts?.ready) {
+ await withTimeout(() => globalThis.document.fonts.ready)
+ }
+
+ await Promise.allSettled(
+ Array.from(globalThis.document.images).map(async (image) => {
+ image.loading = 'eager'
+ image.decoding = 'sync'
+
+ if ('fetchPriority' in image) {
+ image.fetchPriority = 'high'
+ }
+
+ if (!image.complete) {
+ await withTimeout(() => new Promise(resolve => {
+ const done = () => {
+ image.removeEventListener('load', done)
+ image.removeEventListener('error', done)
+ resolve()
+ }
+
+ image.addEventListener('load', done, { once: true })
+ image.addEventListener('error', done, { once: true })
+ }))
+ }
+
+ if (typeof image.decode === 'function') {
+ await withTimeout(() => image.decode())
+ }
+ })
+ )
+ }, ASSET_SETTLE_TIMEOUT_MS)
+}
+
// --- PDF generation ---
const generatePdf = async (browser, slug) => {
@@ -135,24 +212,14 @@ const generatePdf = async (browser, slug) => {
height: Math.round(CONTENT_HEIGHT_PX),
})
- await page.goto(inputUrl, { waitUntil: 'networkidle2', timeout: 60_000 })
+ await page.goto(inputUrl, { waitUntil: 'domcontentloaded', timeout: 60_000 })
await page.emulateMediaType('print')
- // Wait for web fonts so PDF typography matches the site instead of fallback metrics.
- await page.evaluate(() => {
- return globalThis.document.fonts.ready
- })
+ await forceLazyAssetsToLoad(page)
+ await waitForPageAssets(page)
- // Wait for all images to finish loading
- await page.evaluate(() => {
- const doc = globalThis.document
-
- return Promise.all(
- Array.from(doc.images)
- .filter(img => !img.complete)
- .map(img => new Promise(r => { img.onload = r; img.onerror = r }))
- )
- })
+ // Final settle — give any remaining layout shifts a moment to resolve
+ await wait(LAYOUT_SETTLE_DELAY_MS)
const title = await page.title()
@@ -184,10 +251,10 @@ const generatePdf = async (browser, slug) => {
}
}, CONTENT_HEIGHT_PX)
- const [coverPdfBytes, fullPdfBytes] = await Promise.all([
- page.pdf(buildPdfOptions({ includeHeaderFooter: false, pageRanges: '1' })),
- page.pdf(buildPdfOptions({ includeHeaderFooter: true, title })),
- ])
+ const coverPdfBytes = await page.pdf(
+ buildPdfOptions({ includeHeaderFooter: false, pageRanges: '1' })
+ )
+ const fullPdfBytes = await page.pdf(buildPdfOptions({ includeHeaderFooter: true, title }))
await writeMergedPdf({ coverPdfBytes, fullPdfBytes, outputPdf })
diff --git a/scripts/generate-pdfs/styles.mjs b/scripts/generate-pdfs/styles.mjs
index 5f381b5e..fcbcc335 100644
--- a/scripts/generate-pdfs/styles.mjs
+++ b/scripts/generate-pdfs/styles.mjs
@@ -183,7 +183,7 @@ export const buildTemplateStyles = () => {
.pdf-layout-footer__company-name {
color: #001A39;
- font-size: 12pt;
+ font-size: 10pt;
font-style: normal;
font-weight: 600;
line-height: 1.1;
@@ -193,7 +193,7 @@ export const buildTemplateStyles = () => {
.pdf-layout-footer__address p {
color: #001A39;
- font-size: 10pt;
+ font-size: 8pt;
font-style: normal;
line-height: 1.1;
margin: 0;
@@ -207,7 +207,7 @@ export const buildTemplateStyles = () => {
display: flex;
justify-content: center;
color: #001A39;
- font-size: 10pt;
+ font-size: 8pt;
line-height: 1.1;
margin: 0;
width: 20%;
@@ -221,6 +221,7 @@ export const buildTemplateStyles = () => {
align-items: flex-end;
display: flex;
flex-direction: column;
+ gap: 2px;
justify-content: center;
min-width: 0;
width: 40%;
@@ -228,7 +229,7 @@ export const buildTemplateStyles = () => {
.pdf-layout-footer__right p {
color: #001A39;
- font-size: 10pt;
+ font-size: 8pt;
font-style: normal;
line-height: 1.2;
margin: 0;
diff --git a/src/Why Your Quality Gates Are Slowing You Down.pdf b/src/Why Your Quality Gates Are Slowing You Down.pdf
deleted file mode 100644
index 0ae121b3..00000000
Binary files a/src/Why Your Quality Gates Are Slowing You Down.pdf and /dev/null differ
diff --git a/src/components/FileExplorer/Print.astro b/src/components/FileExplorer/Print.astro
new file mode 100644
index 00000000..0348f139
--- /dev/null
+++ b/src/components/FileExplorer/Print.astro
@@ -0,0 +1,84 @@
+---
+import type { FileSystemNode } from '@components/FileExplorer/client/index'
+import PrintNode from '@components/FileExplorer/PrintNode.astro'
+
+export type Props = {
+ data: FileSystemNode[]
+ figure?: string
+ classes?: {
+ wrapper?: string
+ }
+ fullWidth?: boolean
+}
+
+const {
+ data = [],
+ figure,
+ classes = {},
+ fullWidth = true,
+} = Astro.props
+
+const wrapperClass = [
+ 'file-explorer-print',
+ 'my-6',
+ 'block',
+ 'mx-auto',
+ fullWidth ? 'w-full' : 'w-fit max-w-full',
+ classes.wrapper,
+].filter(Boolean).join(' ')
+---
+
+
+ {data.map((node, index) =>
+
{node.note}
} + + {hasChildren && ( +