diff --git a/README.md b/README.md index b4d41b6..3a59223 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,14 @@ ## 🚀 Features - ✅ **Bilingual Support** - Spanish and English with instant switching (no page reload) -- ✅ **PDF Export** - Print-optimized design for PDF generation via browser +- ✅ **Server-Side PDF Export** - Professional PDF generation using chromedp (headless Chrome) +- ✅ **Browser Print** - Alternative print-friendly layout for manual PDF creation - ✅ **HTMX Dynamic Updates** - Smooth UX without heavy JavaScript - ✅ **Paper Design** - Professional CV on elegant white paper with gray background - ✅ **Responsive** - Mobile, tablet, and desktop friendly - ✅ **JSON-Based Content** - Easy to update without touching code - ✅ **AI Development Section** - Showcases modern AI-assisted development skills -- ✅ **Fast & Lightweight** - Go backend, minimal dependencies +- ✅ **Fast & Lightweight** - Go backend with chromedp for PDF generation ## 📋 Quick Start @@ -41,15 +42,34 @@ No code changes needed - just refresh browser! ## 🖨️ Export to PDF -1. Click **"Download PDF"** button -2. Use browser print (Cmd/Ctrl + P) -3. Save as PDF +### Server-Side PDF Generation (Recommended) + +1. Click **"Download as PDF"** button in the action bar +2. PDF is generated server-side using headless Chrome +3. File downloads automatically: `CV-Juan-Andres-Moreno-Rubio-{lang}.pdf` + +**Advantages:** +- Consistent rendering across all platforms +- Perfect font rendering +- No browser compatibility issues +- Professional quality output + +### Browser Print (Alternative) + +1. Click **"Print Friendly"** button +2. Use browser print dialog (Cmd/Ctrl + P) +3. Select "Save as PDF" + +**Endpoints:** +- English PDF: `http://localhost:1999/export/pdf?lang=en` +- Spanish PDF: `http://localhost:1999/export/pdf?lang=es` ## 🎯 Key Technologies - Backend: **Go** (stdlib net/http) +- PDF Generation: **chromedp** (headless Chrome automation) - Frontend: **HTMX** 1.9.10 -- Styling: Custom **CSS** +- Styling: Custom **CSS** with Quicksand font - Data: **JSON** files --- diff --git a/cv-site b/cv-app similarity index 56% rename from cv-site rename to cv-app index 319ba90..e20c5a0 100755 Binary files a/cv-site and b/cv-app differ diff --git a/go.mod b/go.mod index 8e80479..d1546eb 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,14 @@ module github.com/juanatsap/cv-site go 1.25.1 + +require ( + github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 // indirect + github.com/chromedp/chromedp v0.14.2 // indirect + github.com/chromedp/sysutil v1.1.0 // indirect + github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.4.0 // indirect + golang.org/x/sys v0.34.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ddedad3 --- /dev/null +++ b/go.sum @@ -0,0 +1,17 @@ +github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 h1:UQ4AU+BGti3Sy/aLU8KVseYKNALcX9UXY6DfpwQ6J8E= +github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k= +github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM= +github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo= +github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM= +github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8= +github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 h1:iizUGZ9pEquQS5jTGkh4AqeeHCMbfbjeb0zMt0aEFzs= +github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/internal/pdf/generator.go b/internal/pdf/generator.go new file mode 100644 index 0000000..fc86d8c --- /dev/null +++ b/internal/pdf/generator.go @@ -0,0 +1,89 @@ +package pdf + +import ( + "context" + "fmt" + "io" + "time" + + "github.com/chromedp/cdproto/page" + "github.com/chromedp/chromedp" +) + +// Generator handles PDF generation using headless Chrome +type Generator struct { + timeout time.Duration +} + +// NewGenerator creates a new PDF generator with the specified timeout +func NewGenerator(timeout time.Duration) *Generator { + if timeout == 0 { + timeout = 30 * time.Second + } + return &Generator{ + timeout: timeout, + } +} + +// GenerateFromURL generates a PDF from a given URL +func (g *Generator) GenerateFromURL(ctx context.Context, url string) ([]byte, error) { + // Create context with timeout + ctx, cancel := context.WithTimeout(ctx, g.timeout) + defer cancel() + + // Create chromedp context + allocCtx, allocCancel := chromedp.NewContext(ctx) + defer allocCancel() + + // Buffer to store PDF + var pdfBuffer []byte + + // Run chromedp tasks + err := chromedp.Run(allocCtx, + // Navigate to URL + chromedp.Navigate(url), + + // Wait for page to be ready + chromedp.WaitReady("body"), + + // Small delay to ensure all content is loaded + chromedp.Sleep(500*time.Millisecond), + + // Generate PDF with print-optimized settings + chromedp.ActionFunc(func(ctx context.Context) error { + var err error + pdfBuffer, _, err = page.PrintToPDF(). + WithPrintBackground(true). + WithPreferCSSPageSize(true). + WithMarginTop(0). + WithMarginBottom(0). + WithMarginLeft(0). + WithMarginRight(0). + WithPaperWidth(8.27). // A4 width in inches + WithPaperHeight(11.69). // A4 height in inches + Do(ctx) + return err + }), + ) + + if err != nil { + return nil, fmt.Errorf("chromedp execution failed: %w", err) + } + + if len(pdfBuffer) == 0 { + return nil, fmt.Errorf("generated PDF is empty") + } + + return pdfBuffer, nil +} + +// StreamFromURL generates a PDF and writes it to the provided writer +func (g *Generator) StreamFromURL(ctx context.Context, url string, w io.Writer) error { + pdfData, err := g.GenerateFromURL(ctx, url) + if err != nil { + return err + } + + _, err = w.Write(pdfData) + return err +} diff --git a/main.go b/main.go index 8d86dd9..11f5f27 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ func main() { } // Initialize handlers - cvHandler := handlers.NewCVHandler(templateMgr) + cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address()) healthHandler := handlers.NewHealthHandler(version) // Setup router diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..f9ffc06 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,35 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +module.exports = defineConfig({ + testDir: './tests', + fullyParallel: false, // Run tests sequentially for consistent measurements + forbidOnly: !!process.env.CI, + retries: 0, + workers: 1, + reporter: 'html', + use: { + trace: 'on-first-retry', + screenshot: 'on', + video: 'retain-on-failure' + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: [ + { + command: 'echo "Sites should already be running on 3000 and 1999"', + url: 'http://localhost:1999', + reuseExistingServer: true, + timeout: 5000, + }, + { + url: 'http://localhost:3000', + reuseExistingServer: true, + timeout: 5000, + } + ], +}); diff --git a/static/css/logo-toggle.css b/static/css/logo-toggle.css new file mode 100644 index 0000000..9efd256 --- /dev/null +++ b/static/css/logo-toggle.css @@ -0,0 +1,131 @@ +/* Logo Toggle Component */ +.logo-toggle { + display: flex; + align-items: center; + justify-content: center; +} + +.toggle-switch { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + user-select: none; +} + +.toggle-switch input[type="checkbox"] { + position: absolute; + opacity: 0; + width: 0; + height: 0; +} + +.toggle-slider { + position: relative; + display: inline-block; + width: 44px; + height: 24px; + background-color: #ccc; + border-radius: 24px; + transition: background-color 0.3s ease; +} + +.toggle-slider::after { + content: ''; + position: absolute; + width: 18px; + height: 18px; + border-radius: 50%; + background-color: white; + top: 3px; + left: 3px; + transition: transform 0.3s ease; +} + +.toggle-switch input[type="checkbox"]:checked + .toggle-slider { + background-color: var(--accent-blue); +} + +.toggle-switch input[type="checkbox"]:checked + .toggle-slider::after { + transform: translateX(20px); +} + +.toggle-switch input[type="checkbox"]:focus + .toggle-slider { + box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.2); +} + +.toggle-label { + font-size: 0.9rem; + font-weight: 500; + color: #ccc; +} + +/* Experience Item with Logo Support */ +.experience-item { + margin-bottom: 1.5rem; + page-break-inside: avoid; + display: flex; + gap: 1rem; + position: relative; +} + +.company-logo { + display: none; /* Hidden by default */ + flex-shrink: 0; +} + +.company-logo img { + width: 48px; + height: 48px; + object-fit: contain; + border-radius: 4px; + border: 1px solid #ddd; + background: white; +} + +.experience-content { + flex: 1; + min-width: 0; /* Prevents flex item from overflowing */ +} + +/* Show logos when toggle is active */ +.show-logos .company-logo { + display: block; +} + +/* Hide logos in print by default */ +@media print { + .company-logo { + display: none !important; + } +} + +/* Mobile responsiveness */ +@media (max-width: 768px) { + .logo-toggle { + order: 3; /* Move to bottom on mobile */ + } + + .toggle-label { + font-size: 0.85rem; + } + + .toggle-slider { + width: 38px; + height: 20px; + } + + .toggle-slider::after { + width: 14px; + height: 14px; + } + + .toggle-switch input[type="checkbox"]:checked + .toggle-slider::after { + transform: translateX(18px); + } + + .company-logo img { + width: 40px; + height: 40px; + } +} diff --git a/static/css/main.css b/static/css/main.css index a54dbdd..fcd3065 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -53,7 +53,7 @@ a:hover { margin: 0 auto; padding: 1rem 2rem; display: grid; - grid-template-columns: 1fr auto 1fr; + grid-template-columns: auto auto auto 1fr; align-items: center; gap: 2rem; } @@ -357,10 +357,7 @@ a:hover { } /* Experience */ -.experience-item { - margin-bottom: 1.5rem; - page-break-inside: avoid; -} +/* Experience item layout moved to logo-toggle.css */ .experience-header { margin-bottom: 0.6rem; diff --git a/static/images/logos/README.md b/static/images/logos/README.md new file mode 100644 index 0000000..e2af546 --- /dev/null +++ b/static/images/logos/README.md @@ -0,0 +1,25 @@ +# Company Logos + +Place company logos here with the filenames matching the `companyLogo` field in the CV JSON data. + +## Expected Format: +- **Size**: 48x48px minimum (will be displayed at 48x48px) +- **Format**: PNG or SVG preferred +- **Background**: Transparent or white +- **Naming**: Should match exactly the filename in `cv-en.json` / `cv-es.json` + +## Current logos needed: +- olympic-broadcasting.png +- aena.png +- sap.png +- gigya.png +- everis.png +- megabanner.png +- ebantic.png +- indra.png +- emailing-network.png +- penta-msi.png +- homeria.png +- insa.png + +Note: Logos are optional. If a logo file doesn't exist, it will be hidden gracefully. diff --git a/templates.backup/cv-content.html b/templates.backup/cv-content.html new file mode 100644 index 0000000..d93c778 --- /dev/null +++ b/templates.backup/cv-content.html @@ -0,0 +1,149 @@ + +
+ {{if eq .Lang "es"}}ANALISTA PROGRAMADOR{{else}}ANALYST PROGRAMMER{{end}} + | + NODEJS + REACTJS {{if eq .Lang "es"}}DESARROLLADOR{{else}}DEVELOPER{{end}} + | + WEB {{if eq .Lang "es"}}DESARROLLADOR{{else}}DEVELOPER{{end}} + | + GO {{if eq .Lang "es"}}DESARROLLADOR{{else}}DEVELOPER{{end}} + | + PHP {{if eq .Lang "es"}}DESARROLLADOR{{else}}DEVELOPER{{end}} +
+ + + + + +
+ +
+
+
+

{{.CV.Personal.Name}}

+

{{if eq .Lang "es"}}20 años de experiencia{{else}}20 years of experience{{end}}

+ +
{{.CV.Summary}}
+
+
+ {{.CV.Personal.Name}} +
+
+
+ + +
+

{{if eq .Lang "es"}}Formación{{else}}Training{{end}}

+ {{range .CV.Education}} +
+ {{.Degree}} ({{.StartDate}}-{{.EndDate}}) {{if eq $.Lang "es"}}obtenido de{{else}}obtained from the{{end}} {{.Institution}} ({{.Location}}) +
+ {{end}} +
+ + +
+

{{if eq .Lang "es"}}Competencias{{else}}Skills{{end}}

+

+ {{if eq .Lang "es"}} + Amplio conocimiento en entornos web, tanto J2EE como PHP. Experto en tecnologías front-end, aunque con considerable experiencia en sistemas back-end. Receptivo al aprendizaje de nuevas tecnologías, y con una gran dosis de creatividad. Capacidad de analizar problemas y aportar soluciones específicas adaptadas a cada tipo de cliente. Me gusta trabajar tanto solo como en grupos. + {{else}} + Extensive knowledge in web environments, both J2EE and PHP. Expert in front-end technologies, although with considerable experience in back-end systems. Receptive to learning new technologies, and with a large dose of creativity. Ability to analyze problems and provide specific solutions tailored to each client type. I like to work both alone and in groups. + {{end}} +

+
+ + +
+

{{if eq .Lang "es"}}Experiencia{{else}}Experience{{end}}

+ + {{range .CV.Experience}} +
+
+
+

{{.Position}} / {{if eq $.Lang "es"}}Analista Programador{{else}}Analyst Programmer{{end}}

+ {{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} - ({{.Location}}) +
+
+ + {{if .ShortDescription}} +

{{.ShortDescription}}

+ {{end}} + +
+
    + {{range .Responsibilities}} +
  • {{.}}
  • + {{end}} +
+
+
+ {{end}} +
+ +
diff --git a/templates.backup/index-improved.html b/templates.backup/index-improved.html new file mode 100644 index 0000000..f2a8d51 --- /dev/null +++ b/templates.backup/index-improved.html @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + {{.CV.Personal.Name}} - Curriculum Vitae + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ {{template "cv-content.html" .}} +
+
+ + + + + + + + + + + diff --git a/templates.backup/index.html b/templates.backup/index.html new file mode 100644 index 0000000..74256e4 --- /dev/null +++ b/templates.backup/index.html @@ -0,0 +1,274 @@ + + + + + + + + {{.CV.Personal.Name}} - {{if eq .Lang "es"}}Curriculum Vitae{{else}}Curriculum Vitae{{end}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ {{template "cv-content.html" .}} +
+
+ + + + + + + + + + diff --git a/templates.backup/partials/.gitkeep b/templates.backup/partials/.gitkeep new file mode 100644 index 0000000..d14176f --- /dev/null +++ b/templates.backup/partials/.gitkeep @@ -0,0 +1 @@ +# Placeholder for future partial templates diff --git a/templates/cv-content.html b/templates/cv-content.html index 69814c3..a45d654 100644 --- a/templates/cv-content.html +++ b/templates/cv-content.html @@ -71,34 +71,41 @@ {{range .CV.Experience}}
-
-
-

- {{.Position}} - {{if .Company}} - {{if .CompanyURL}} - {{.Company}} - {{else}} - {{.Company}} - {{end}} - {{end}} -

- {{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} -  -  - ({{.Location}}) -
+ {{if .CompanyLogo}} + - - {{if .ShortDescription}} -

{{.ShortDescription}}

{{end}} +
+
+
+

+ {{.Position}} + {{if .Company}} + {{if .CompanyURL}} + {{.Company}} + {{else}} + {{.Company}} + {{end}} + {{end}} +

+ {{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} +  -  + ({{.Location}}) +
+
-
-
    - {{range .Responsibilities}} -
  • {{.}}
  • - {{end}} -
+ {{if .ShortDescription}} +

{{.ShortDescription}}

+ {{end}} + +
+
    + {{range .Responsibilities}} +
  • {{.}}
  • + {{end}} +
+
{{end}} @@ -207,20 +214,31 @@
+ +
+ +
+
{ + const app = document.getElementById('app') || document.body; + return { + innerHTML: app.innerHTML.substring(0, 2000), + hasContent: app.innerHTML.length > 100, + classes: Array.from(document.querySelectorAll('[class]')).map(el => el.className).filter(c => c).slice(0, 50) + }; + }); + + console.log('OLD site content loaded:', oldContent.hasContent); + console.log('OLD site classes found:', oldContent.classes.length); + if (oldContent.classes.length > 0) { + console.log('Sample classes:', oldContent.classes.slice(0, 10)); + } + + // NEW SITE + const pageNew = await browser.newPage({ viewport: { width: 1920, height: 1080 } }); + console.log('\nLoading NEW site (Go+HTMX)...'); + await pageNew.goto('http://localhost:1999', { waitUntil: 'networkidle' }); + + await pageNew.screenshot({ + path: './tests/screenshots/new-full-rendered.png', + fullPage: true + }); + + // SIDE-BY-SIDE COMPARISON + console.log('\n=== HEADER BADGES COMPARISON ===\n'); + + // Try multiple selectors for old site + const oldBadgeSelectors = [ + '[class*="badge"]', + '[class*="title"]', + 'div[class*="cv"]', + '.badge', + '.title-badge' + ]; + + let oldBadges = null; + for (const selector of oldBadgeSelectors) { + try { + const count = await pageOld.locator(selector).count(); + if (count > 0) { + console.log(`Found ${count} elements with selector: ${selector}`); + oldBadges = await pageOld.$$eval(selector, elements => + elements.slice(0, 5).map(el => { + const computed = window.getComputedStyle(el); + return { + tag: el.tagName, + class: el.className, + text: el.textContent?.substring(0, 50), + styles: { + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + padding: computed.padding, + height: computed.height + } + }; + }) + ); + break; + } + } catch (e) { + // Try next selector + } + } + + const newBadges = await pageNew.$$eval('.title-badge', elements => + elements.slice(0, 5).map(el => { + const computed = window.getComputedStyle(el); + return { + tag: el.tagName, + class: el.className, + text: el.textContent?.trim(), + styles: { + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + padding: computed.padding, + height: computed.height + } + }; + }) + ); + + console.log('\nOLD site badges:'); + console.log(JSON.stringify(oldBadges, null, 2)); + + console.log('\nNEW site badges:'); + console.log(JSON.stringify(newBadges, null, 2)); + + // VISUAL PIXEL COMPARISON + console.log('\n=== VISUAL COMPARISON ===\n'); + + // Get dimensions + const oldDimensions = await pageOld.evaluate(() => ({ + width: document.documentElement.scrollWidth, + height: document.documentElement.scrollHeight + })); + + const newDimensions = await pageNew.evaluate(() => ({ + width: document.documentElement.scrollWidth, + height: document.documentElement.scrollHeight + })); + + console.log('OLD site dimensions:', oldDimensions); + console.log('NEW site dimensions:', newDimensions); + + // Screenshot specific sections + try { + // Header comparison + const oldHeader = pageOld.locator('header, [class*="header"], div').first(); + const newHeader = pageNew.locator('.cv-title-badges-header').first(); + + if (await oldHeader.count() > 0) { + await oldHeader.screenshot({ path: './tests/screenshots/old-header-section.png' }); + } + await newHeader.screenshot({ path: './tests/screenshots/new-header-section.png' }); + + // Sidebar comparison + const oldSidebar = pageOld.locator('[class*="sidebar"], aside').first(); + const newSidebar = pageNew.locator('.cv-sidebar').first(); + + if (await oldSidebar.count() > 0) { + await oldSidebar.screenshot({ path: './tests/screenshots/old-sidebar-section.png' }); + } + await newSidebar.screenshot({ path: './tests/screenshots/new-sidebar-section.png' }); + } catch (e) { + console.log('Error capturing sections:', e.message); + } + + // CREATE COMPARISON REPORT + const report = { + timestamp: new Date().toISOString(), + oldSite: { + url: 'http://localhost:3000', + hasContent: oldContent.hasContent, + classesFound: oldContent.classes.length, + dimensions: oldDimensions, + badges: oldBadges + }, + newSite: { + url: 'http://localhost:1999', + dimensions: newDimensions, + badges: newBadges + }, + comparison: { + dimensionsMatch: Math.abs(oldDimensions.width - newDimensions.width) < 50 && + Math.abs(oldDimensions.height - newDimensions.height) < 50, + pixelPerfect: null // To be determined by visual inspection + } + }; + + fs.writeFileSync( + './tests/screenshots/comparison-report.json', + JSON.stringify(report, null, 2) + ); + + console.log('\n✓ Comparison complete!'); + console.log('✓ Screenshots saved to tests/screenshots/'); + console.log('✓ Report saved to comparison-report.json'); + + await browser.close(); +} + +compareRendered().catch(console.error); diff --git a/tests/inspect-structure.js b/tests/inspect-structure.js new file mode 100644 index 0000000..ba7203e --- /dev/null +++ b/tests/inspect-structure.js @@ -0,0 +1,98 @@ +const { chromium } = require('playwright'); + +async function inspectStructure() { + const browser = await chromium.launch(); + const page = await browser.newPage(); + + console.log('\n=== INSPECTING OLD SITE (localhost:3000) ===\n'); + await page.goto('http://localhost:3000', { waitUntil: 'networkidle' }); + + // Get all class names + const classes = await page.evaluate(() => { + const allElements = document.querySelectorAll('*'); + const classSet = new Set(); + allElements.forEach(el => { + if (el.className && typeof el.className === 'string') { + el.className.split(' ').forEach(cls => { + if (cls.trim()) classSet.add(cls.trim()); + }); + } + }); + return Array.from(classSet).sort(); + }); + + console.log('All classes found:'); + console.log(classes.filter(c => c.includes('badge') || c.includes('title') || c.includes('cv') || c.includes('sidebar')).join('\n')); + + // Get main structure + const structure = await page.evaluate(() => { + const getStructure = (el, depth = 0) => { + if (depth > 3) return null; + const tag = el.tagName.toLowerCase(); + const classes = el.className || ''; + const id = el.id || ''; + return { + tag, + classes, + id, + children: Array.from(el.children).map(child => getStructure(child, depth + 1)).filter(Boolean) + }; + }; + return getStructure(document.body); + }); + + console.log('\n\nMain structure:'); + console.log(JSON.stringify(structure, null, 2).substring(0, 5000)); + + // Find elements with "badge" or "title" in their classes + const badgeElements = await page.$$eval('[class*="badge"], [class*="title"]', elements => + elements.slice(0, 20).map(el => ({ + tag: el.tagName, + class: el.className, + text: el.textContent?.substring(0, 100), + computedStyles: (() => { + const computed = window.getComputedStyle(el); + return { + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + padding: computed.padding, + height: computed.height + }; + })() + })) + ); + + console.log('\n\nBadge/Title elements:'); + console.log(JSON.stringify(badgeElements, null, 2)); + + console.log('\n\n=== INSPECTING NEW SITE (localhost:1999) ===\n'); + await page.goto('http://localhost:1999', { waitUntil: 'networkidle' }); + + const newBadgeElements = await page.$$eval('[class*="badge"], [class*="title"]', elements => + elements.slice(0, 20).map(el => ({ + tag: el.tagName, + class: el.className, + text: el.textContent?.substring(0, 100), + computedStyles: (() => { + const computed = window.getComputedStyle(el); + return { + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + padding: computed.padding, + height: computed.height + }; + })() + })) + ); + + console.log('Badge/Title elements:'); + console.log(JSON.stringify(newBadgeElements, null, 2)); + + await browser.close(); +} + +inspectStructure().catch(console.error); diff --git a/tests/screenshots/badge-measurements.json b/tests/screenshots/badge-measurements.json new file mode 100644 index 0000000..d8fd707 --- /dev/null +++ b/tests/screenshots/badge-measurements.json @@ -0,0 +1,24 @@ +{ + "old": {}, + "new": { + "badge": { + "box": { + "x": 528.046875, + "y": 173.96875, + "width": 164, + "height": 21.609375 + }, + "styles": { + "height": "21.6094px", + "padding": "0px", + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "borderRadius": "0px", + "display": "block", + "alignItems": "normal" + } + } + } +} \ No newline at end of file diff --git a/tests/screenshots/comparison-report.json b/tests/screenshots/comparison-report.json new file mode 100644 index 0000000..25149fd --- /dev/null +++ b/tests/screenshots/comparison-report.json @@ -0,0 +1,91 @@ +{ + "timestamp": "2025-10-31T15:52:05.485Z", + "oldSite": { + "url": "http://localhost:3000", + "hasContent": true, + "classesFound": 0, + "dimensions": { + "width": 1920, + "height": 1080 + }, + "badges": null + }, + "newSite": { + "url": "http://localhost:1999", + "dimensions": { + "width": 1920, + "height": 2195 + }, + "badges": [ + { + "tag": "SPAN", + "class": "title-badge", + "text": "ANALYST PROGRAMMER", + "styles": { + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "padding": "0px", + "height": "21.6094px" + } + }, + { + "tag": "SPAN", + "class": "title-badge", + "text": "NODEJS + REACTJS DEVELOPER", + "styles": { + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "padding": "0px", + "height": "21.6094px" + } + }, + { + "tag": "SPAN", + "class": "title-badge", + "text": "WEB DEVELOPER", + "styles": { + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "padding": "0px", + "height": "21.6094px" + } + }, + { + "tag": "SPAN", + "class": "title-badge", + "text": "JAVA DEVELOPER", + "styles": { + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "padding": "0px", + "height": "21.6094px" + } + }, + { + "tag": "SPAN", + "class": "title-badge", + "text": "PHP DEVELOPER", + "styles": { + "fontSize": "14.4px", + "fontWeight": "400", + "color": "rgb(204, 204, 204)", + "backgroundColor": "rgba(0, 0, 0, 0)", + "padding": "0px", + "height": "21.6094px" + } + } + ] + }, + "comparison": { + "dimensionsMatch": false, + "pixelPerfect": null + } +} \ No newline at end of file diff --git a/tests/screenshots/critical-elements-full-styles.json b/tests/screenshots/critical-elements-full-styles.json new file mode 100644 index 0000000..e82987f --- /dev/null +++ b/tests/screenshots/critical-elements-full-styles.json @@ -0,0 +1,2501 @@ +{ + "old": {}, + "new": { + ".cv-title-badges-header": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "center", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgb(48, 48, 48)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "46px", + "border-block-end-color": "rgb(52, 73, 94)", + "border-block-end-style": "solid", + "border-block-end-width": "2px", + "border-block-start-color": "rgb(41, 43, 44)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(52, 73, 94)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "solid", + "border-bottom-width": "2px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(41, 43, 44)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(41, 43, 44)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(41, 43, 44)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(41, 43, 44)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(41, 43, 44)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "auto", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(41, 43, 44)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(41, 43, 44)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "0px", + "column-rule-color": "rgb(41, 43, 44)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "flex", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "wrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, \"Source Sans Pro\", -apple-system, system-ui, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "16px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "400", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "-1", + "grid-column-start": "1", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "46px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "1200px", + "inset-block-end": "auto", + "inset-block-start": "auto", + "inset-inline-end": "auto", + "inset-inline-start": "auto", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "center", + "justify-items": "normal", + "justify-self": "auto", + "left": "auto", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "24px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "0px", + "margin-block-start": "0px", + "margin-bottom": "0px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "0px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "auto", + "min-height": "auto", + "min-inline-size": "auto", + "min-width": "auto", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(41, 43, 44)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "10px", + "padding-block-start": "10px", + "padding-bottom": "10px", + "padding-inline-end": "20px", + "padding-inline-start": "20px", + "padding-left": "20px", + "padding-right": "20px", + "padding-top": "10px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "600px 23px", + "pointer-events": "auto", + "position": "static", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "auto", + "rotate": "none", + "row-gap": "0px", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(41, 43, 44)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(41, 43, 44)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "none", + "text-underline-position": "auto", + "text-wrap-mode": "wrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "auto", + "touch-action": "auto", + "transform": "none", + "transform-origin": "600px 23px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "isolate", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "1200px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(41, 43, 44)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(41, 43, 44)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + }, + ".title-badge": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "normal", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgba(0, 0, 0, 0)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "21.6094px", + "border-block-end-color": "rgb(204, 204, 204)", + "border-block-end-style": "none", + "border-block-end-width": "0px", + "border-block-start-color": "rgb(204, 204, 204)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(204, 204, 204)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "none", + "border-bottom-width": "0px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(204, 204, 204)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(204, 204, 204)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(204, 204, 204)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(204, 204, 204)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(204, 204, 204)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "auto", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(204, 204, 204)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(204, 204, 204)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "normal", + "column-rule-color": "rgb(204, 204, 204)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "block", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "nowrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, \"Source Sans Pro\", -apple-system, system-ui, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "14.4px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "400", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "auto", + "grid-column-start": "auto", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "21.6094px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "164px", + "inset-block-end": "auto", + "inset-block-start": "auto", + "inset-inline-end": "auto", + "inset-inline-start": "auto", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "normal", + "justify-items": "normal", + "justify-self": "auto", + "left": "auto", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "21.6px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "0px", + "margin-block-start": "0px", + "margin-bottom": "0px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "0px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "auto", + "min-height": "auto", + "min-inline-size": "auto", + "min-width": "auto", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(204, 204, 204)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "0px", + "padding-block-start": "0px", + "padding-bottom": "0px", + "padding-inline-end": "0px", + "padding-inline-start": "0px", + "padding-left": "0px", + "padding-right": "0px", + "padding-top": "0px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "82px 10.7969px", + "pointer-events": "auto", + "position": "static", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "auto", + "rotate": "none", + "row-gap": "normal", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(204, 204, 204)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(204, 204, 204)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "uppercase", + "text-underline-position": "auto", + "text-wrap-mode": "nowrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "auto", + "touch-action": "auto", + "transform": "none", + "transform-origin": "82px 10.8047px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "normal", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "164px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(204, 204, 204)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(204, 204, 204)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + }, + ".badge-separator": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "normal", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgba(0, 0, 0, 0)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "24px", + "border-block-end-color": "rgb(204, 204, 204)", + "border-block-end-style": "none", + "border-block-end-width": "0px", + "border-block-start-color": "rgb(204, 204, 204)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(204, 204, 204)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "none", + "border-bottom-width": "0px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(204, 204, 204)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(204, 204, 204)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(204, 204, 204)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(204, 204, 204)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(204, 204, 204)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "1px", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(204, 204, 204)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(204, 204, 204)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "normal", + "column-rule-color": "rgb(204, 204, 204)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "block", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "nowrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, \"Source Sans Pro\", -apple-system, system-ui, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "16px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "400", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "auto", + "grid-column-start": "auto", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "24px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "33.2812px", + "inset-block-end": "1px", + "inset-block-start": "-1px", + "inset-inline-end": "0px", + "inset-inline-start": "0px", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "normal", + "justify-items": "normal", + "justify-self": "auto", + "left": "0px", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "24px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "0px", + "margin-block-start": "0px", + "margin-bottom": "0px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "0px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "auto", + "min-height": "auto", + "min-inline-size": "auto", + "min-width": "auto", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(204, 204, 204)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "0px", + "padding-block-start": "0px", + "padding-bottom": "0px", + "padding-inline-end": "15px", + "padding-inline-start": "15px", + "padding-left": "15px", + "padding-right": "15px", + "padding-top": "0px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "16.6406px 12px", + "pointer-events": "auto", + "position": "relative", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "0px", + "rotate": "none", + "row-gap": "normal", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(204, 204, 204)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(204, 204, 204)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "none", + "text-underline-position": "auto", + "text-wrap-mode": "wrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "-1px", + "touch-action": "auto", + "transform": "none", + "transform-origin": "16.6406px 12px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "normal", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "33.2812px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(204, 204, 204)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(204, 204, 204)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + }, + ".sidebar-title": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "normal", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgba(0, 0, 0, 0)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "38.4688px", + "border-block-end-color": "rgb(51, 51, 51)", + "border-block-end-style": "none", + "border-block-end-width": "0px", + "border-block-start-color": "rgb(51, 51, 51)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(51, 51, 51)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "none", + "border-bottom-width": "0px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(51, 51, 51)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(51, 51, 51)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(51, 51, 51)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(51, 51, 51)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(51, 51, 51)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "auto", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(51, 51, 51)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(51, 51, 51)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "normal", + "column-rule-color": "rgb(51, 51, 51)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "block", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "nowrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "18.72px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "500", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "auto", + "grid-column-start": "auto", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "38.4688px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "252px", + "inset-block-end": "auto", + "inset-block-start": "auto", + "inset-inline-end": "auto", + "inset-inline-start": "auto", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "normal", + "justify-items": "normal", + "justify-self": "auto", + "left": "auto", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "22.464px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "8px", + "margin-block-start": "0px", + "margin-bottom": "8px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "0px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "0px", + "min-height": "0px", + "min-inline-size": "0px", + "min-width": "0px", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(51, 51, 51)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "8px", + "padding-block-start": "8px", + "padding-bottom": "8px", + "padding-inline-end": "0px", + "padding-inline-start": "0px", + "padding-left": "0px", + "padding-right": "0px", + "padding-top": "8px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "126px 19.2344px", + "pointer-events": "auto", + "position": "static", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "auto", + "rotate": "none", + "row-gap": "normal", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(51, 51, 51)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(51, 51, 51)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "none", + "text-underline-position": "auto", + "text-wrap-mode": "wrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "auto", + "touch-action": "auto", + "transform": "none", + "transform-origin": "126px 19.2344px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "isolate", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "252px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(51, 51, 51)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(51, 51, 51)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + }, + ".section-title": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "normal", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgba(0, 0, 0, 0)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "24.9531px", + "border-block-end-color": "rgb(51, 51, 51)", + "border-block-end-style": "none", + "border-block-end-width": "0px", + "border-block-start-color": "rgb(51, 51, 51)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(51, 51, 51)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "none", + "border-bottom-width": "0px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(51, 51, 51)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(51, 51, 51)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(51, 51, 51)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(51, 51, 51)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(51, 51, 51)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "auto", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(51, 51, 51)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(51, 51, 51)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "normal", + "column-rule-color": "rgb(51, 51, 51)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "block", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "nowrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "20.8px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "500", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "auto", + "grid-column-start": "auto", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "24.9531px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "820px", + "inset-block-end": "auto", + "inset-block-start": "auto", + "inset-inline-end": "auto", + "inset-inline-start": "auto", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "normal", + "justify-items": "normal", + "justify-self": "auto", + "left": "auto", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "24.96px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "10px", + "margin-block-start": "10px", + "margin-bottom": "10px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "10px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "0px", + "min-height": "0px", + "min-inline-size": "0px", + "min-width": "0px", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(51, 51, 51)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "0px", + "padding-block-start": "0px", + "padding-bottom": "0px", + "padding-inline-end": "0px", + "padding-inline-start": "0px", + "padding-left": "0px", + "padding-right": "0px", + "padding-top": "0px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "410px 12.4688px", + "pointer-events": "auto", + "position": "static", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "auto", + "rotate": "none", + "row-gap": "normal", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(51, 51, 51)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(51, 51, 51)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "none", + "text-underline-position": "auto", + "text-wrap-mode": "wrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "auto", + "touch-action": "auto", + "transform": "none", + "transform-origin": "410px 12.4766px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "isolate", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "820px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(51, 51, 51)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(51, 51, 51)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + }, + ".cv-name": { + "accent-color": "auto", + "align-content": "normal", + "align-items": "normal", + "align-self": "auto", + "alignment-baseline": "auto", + "anchor-name": "none", + "anchor-scope": "none", + "animation-composition": "replace", + "animation-delay": "0s", + "animation-direction": "normal", + "animation-duration": "0s", + "animation-fill-mode": "none", + "animation-iteration-count": "1", + "animation-name": "none", + "animation-play-state": "running", + "animation-range-end": "normal", + "animation-range-start": "normal", + "animation-timeline": "auto", + "animation-timing-function": "ease", + "app-region": "none", + "appearance": "none", + "backdrop-filter": "none", + "backface-visibility": "visible", + "background-attachment": "scroll", + "background-blend-mode": "normal", + "background-clip": "border-box", + "background-color": "rgba(0, 0, 0, 0)", + "background-image": "none", + "background-origin": "padding-box", + "background-position": "0% 0%", + "background-repeat": "repeat", + "background-size": "auto", + "baseline-shift": "0px", + "baseline-source": "auto", + "block-size": "38.7188px", + "border-block-end-color": "rgb(0, 0, 0)", + "border-block-end-style": "none", + "border-block-end-width": "0px", + "border-block-start-color": "rgb(0, 0, 0)", + "border-block-start-style": "none", + "border-block-start-width": "0px", + "border-bottom-color": "rgb(0, 0, 0)", + "border-bottom-left-radius": "0px", + "border-bottom-right-radius": "0px", + "border-bottom-style": "none", + "border-bottom-width": "0px", + "border-collapse": "separate", + "border-end-end-radius": "0px", + "border-end-start-radius": "0px", + "border-image-outset": "0", + "border-image-repeat": "stretch", + "border-image-slice": "100%", + "border-image-source": "none", + "border-image-width": "1", + "border-inline-end-color": "rgb(0, 0, 0)", + "border-inline-end-style": "none", + "border-inline-end-width": "0px", + "border-inline-start-color": "rgb(0, 0, 0)", + "border-inline-start-style": "none", + "border-inline-start-width": "0px", + "border-left-color": "rgb(0, 0, 0)", + "border-left-style": "none", + "border-left-width": "0px", + "border-right-color": "rgb(0, 0, 0)", + "border-right-style": "none", + "border-right-width": "0px", + "border-start-end-radius": "0px", + "border-start-start-radius": "0px", + "border-top-color": "rgb(0, 0, 0)", + "border-top-left-radius": "0px", + "border-top-right-radius": "0px", + "border-top-style": "none", + "border-top-width": "0px", + "bottom": "auto", + "box-decoration-break": "slice", + "box-shadow": "none", + "box-sizing": "border-box", + "break-after": "auto", + "break-before": "auto", + "break-inside": "auto", + "buffered-rendering": "auto", + "caption-side": "top", + "caret-animation": "auto", + "caret-color": "rgb(0, 0, 0)", + "clear": "none", + "clip": "auto", + "clip-path": "none", + "clip-rule": "nonzero", + "color": "rgb(0, 0, 0)", + "color-interpolation": "srgb", + "color-interpolation-filters": "linearrgb", + "color-rendering": "auto", + "column-count": "auto", + "column-gap": "normal", + "column-rule-color": "rgb(0, 0, 0)", + "column-rule-style": "none", + "column-rule-width": "0px", + "column-span": "none", + "column-width": "auto", + "contain-intrinsic-block-size": "none", + "contain-intrinsic-height": "none", + "contain-intrinsic-inline-size": "none", + "contain-intrinsic-size": "none", + "contain-intrinsic-width": "none", + "container-name": "none", + "container-type": "normal", + "content": "normal", + "corner-bottom-left-shape": "round", + "corner-bottom-right-shape": "round", + "corner-end-end-shape": "round", + "corner-end-start-shape": "round", + "corner-start-end-shape": "round", + "corner-start-start-shape": "round", + "corner-top-left-shape": "round", + "corner-top-right-shape": "round", + "cursor": "auto", + "cx": "0px", + "cy": "0px", + "d": "none", + "direction": "ltr", + "display": "block", + "dominant-baseline": "auto", + "dynamic-range-limit": "no-limit", + "empty-cells": "show", + "field-sizing": "fixed", + "fill": "rgb(0, 0, 0)", + "fill-opacity": "1", + "fill-rule": "nonzero", + "filter": "none", + "flex-basis": "auto", + "flex-direction": "row", + "flex-grow": "0", + "flex-shrink": "1", + "flex-wrap": "nowrap", + "float": "none", + "flood-color": "rgb(0, 0, 0)", + "flood-opacity": "1", + "font-family": "Quicksand, sans-serif", + "font-kerning": "auto", + "font-optical-sizing": "auto", + "font-palette": "normal", + "font-size": "35.2px", + "font-size-adjust": "none", + "font-stretch": "100%", + "font-style": "normal", + "font-synthesis-small-caps": "auto", + "font-synthesis-style": "auto", + "font-synthesis-weight": "auto", + "font-variant": "normal", + "font-variant-alternates": "normal", + "font-variant-caps": "normal", + "font-variant-east-asian": "normal", + "font-variant-emoji": "normal", + "font-variant-ligatures": "normal", + "font-variant-numeric": "normal", + "font-variant-position": "normal", + "font-weight": "400", + "grid-auto-columns": "auto", + "grid-auto-flow": "row", + "grid-auto-rows": "auto", + "grid-column-end": "auto", + "grid-column-start": "auto", + "grid-row-end": "auto", + "grid-row-start": "auto", + "grid-template-areas": "none", + "grid-template-columns": "none", + "grid-template-rows": "none", + "height": "38.7188px", + "hyphenate-character": "auto", + "hyphenate-limit-chars": "auto", + "hyphens": "manual", + "image-orientation": "from-image", + "image-rendering": "auto", + "initial-letter": "normal", + "inline-size": "638px", + "inset-block-end": "auto", + "inset-block-start": "auto", + "inset-inline-end": "auto", + "inset-inline-start": "auto", + "interactivity": "auto", + "interpolate-size": "numeric-only", + "isolation": "auto", + "justify-content": "normal", + "justify-items": "normal", + "justify-self": "auto", + "left": "auto", + "letter-spacing": "normal", + "lighting-color": "rgb(255, 255, 255)", + "line-break": "auto", + "line-height": "38.72px", + "list-style-image": "none", + "list-style-position": "outside", + "list-style-type": "disc", + "margin-block-end": "8px", + "margin-block-start": "0px", + "margin-bottom": "8px", + "margin-inline-end": "0px", + "margin-inline-start": "0px", + "margin-left": "0px", + "margin-right": "0px", + "margin-top": "0px", + "marker-end": "none", + "marker-mid": "none", + "marker-start": "none", + "mask-clip": "border-box", + "mask-composite": "add", + "mask-image": "none", + "mask-mode": "match-source", + "mask-origin": "border-box", + "mask-position": "0% 0%", + "mask-repeat": "repeat", + "mask-size": "auto", + "mask-type": "luminance", + "math-depth": "0", + "math-shift": "normal", + "math-style": "normal", + "max-block-size": "none", + "max-height": "none", + "max-inline-size": "none", + "max-width": "none", + "min-block-size": "0px", + "min-height": "0px", + "min-inline-size": "0px", + "min-width": "0px", + "mix-blend-mode": "normal", + "object-fit": "fill", + "object-position": "50% 50%", + "object-view-box": "none", + "offset-anchor": "auto", + "offset-distance": "0px", + "offset-path": "none", + "offset-position": "normal", + "offset-rotate": "auto 0deg", + "opacity": "1", + "order": "0", + "orphans": "2", + "outline-color": "rgb(0, 0, 0)", + "outline-offset": "0px", + "outline-style": "none", + "outline-width": "0px", + "overflow-anchor": "auto", + "overflow-block": "visible", + "overflow-clip-margin": "0px", + "overflow-inline": "visible", + "overflow-wrap": "normal", + "overflow-x": "visible", + "overflow-y": "visible", + "overlay": "none", + "overscroll-behavior-block": "auto", + "overscroll-behavior-inline": "auto", + "padding-block-end": "0px", + "padding-block-start": "0px", + "padding-bottom": "0px", + "padding-inline-end": "0px", + "padding-inline-start": "0px", + "padding-left": "0px", + "padding-right": "0px", + "padding-top": "0px", + "paint-order": "normal", + "perspective": "none", + "perspective-origin": "319px 19.3594px", + "pointer-events": "auto", + "position": "static", + "position-anchor": "auto", + "position-area": "none", + "position-try-fallbacks": "none", + "position-try-order": "normal", + "position-visibility": "always", + "print-color-adjust": "economy", + "r": "0px", + "reading-flow": "normal", + "reading-order": "0", + "resize": "none", + "right": "auto", + "rotate": "none", + "row-gap": "normal", + "ruby-align": "space-around", + "ruby-position": "over", + "rx": "auto", + "ry": "auto", + "scale": "none", + "scroll-behavior": "auto", + "scroll-initial-target": "none", + "scroll-margin-block-end": "0px", + "scroll-margin-block-start": "0px", + "scroll-margin-inline-end": "0px", + "scroll-margin-inline-start": "0px", + "scroll-marker-group": "none", + "scroll-padding-block-end": "auto", + "scroll-padding-block-start": "auto", + "scroll-padding-inline-end": "auto", + "scroll-padding-inline-start": "auto", + "scroll-target-group": "none", + "scroll-timeline-axis": "block", + "scroll-timeline-name": "none", + "scrollbar-color": "auto", + "scrollbar-gutter": "auto", + "scrollbar-width": "auto", + "shape-image-threshold": "0", + "shape-margin": "0px", + "shape-outside": "none", + "shape-rendering": "auto", + "speak": "normal", + "stop-color": "rgb(0, 0, 0)", + "stop-opacity": "1", + "stroke": "none", + "stroke-dasharray": "none", + "stroke-dashoffset": "0px", + "stroke-linecap": "butt", + "stroke-linejoin": "miter", + "stroke-miterlimit": "4", + "stroke-opacity": "1", + "stroke-width": "1px", + "tab-size": "8", + "table-layout": "auto", + "text-align": "start", + "text-align-last": "auto", + "text-anchor": "start", + "text-autospace": "no-autospace", + "text-box-edge": "auto", + "text-box-trim": "none", + "text-decoration": "none", + "text-decoration-color": "rgb(0, 0, 0)", + "text-decoration-line": "none", + "text-decoration-skip-ink": "auto", + "text-decoration-style": "solid", + "text-emphasis-color": "rgb(0, 0, 0)", + "text-emphasis-position": "over", + "text-emphasis-style": "none", + "text-indent": "0px", + "text-overflow": "clip", + "text-rendering": "auto", + "text-shadow": "none", + "text-size-adjust": "auto", + "text-spacing-trim": "normal", + "text-transform": "none", + "text-underline-position": "auto", + "text-wrap-mode": "wrap", + "text-wrap-style": "auto", + "timeline-scope": "none", + "top": "auto", + "touch-action": "auto", + "transform": "none", + "transform-origin": "319px 19.3594px", + "transform-style": "flat", + "transition-behavior": "normal", + "transition-delay": "0s", + "transition-duration": "0s", + "transition-property": "all", + "transition-timing-function": "ease", + "translate": "none", + "unicode-bidi": "isolate", + "user-select": "auto", + "vector-effect": "none", + "vertical-align": "baseline", + "view-timeline-axis": "block", + "view-timeline-inset": "auto", + "view-timeline-name": "none", + "view-transition-class": "none", + "view-transition-group": "normal", + "view-transition-name": "none", + "visibility": "visible", + "white-space-collapse": "collapse", + "widows": "2", + "width": "638px", + "will-change": "auto", + "word-break": "normal", + "word-spacing": "0px", + "writing-mode": "horizontal-tb", + "x": "0px", + "y": "0px", + "z-index": "auto", + "zoom": "1", + "-webkit-border-horizontal-spacing": "0px", + "-webkit-border-image": "none", + "-webkit-border-vertical-spacing": "0px", + "-webkit-box-align": "stretch", + "-webkit-box-decoration-break": "slice", + "-webkit-box-direction": "normal", + "-webkit-box-flex": "0", + "-webkit-box-ordinal-group": "1", + "-webkit-box-orient": "horizontal", + "-webkit-box-pack": "start", + "-webkit-box-reflect": "none", + "-webkit-font-smoothing": "auto", + "-webkit-line-break": "auto", + "-webkit-line-clamp": "none", + "-webkit-locale": "\"en\"", + "-webkit-mask-box-image": "none", + "-webkit-mask-box-image-outset": "0", + "-webkit-mask-box-image-repeat": "stretch", + "-webkit-mask-box-image-slice": "0 fill", + "-webkit-mask-box-image-source": "none", + "-webkit-mask-box-image-width": "auto", + "-webkit-rtl-ordering": "logical", + "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.18)", + "-webkit-text-combine": "none", + "-webkit-text-decorations-in-effect": "none", + "-webkit-text-fill-color": "rgb(0, 0, 0)", + "-webkit-text-orientation": "vertical-right", + "-webkit-text-security": "none", + "-webkit-text-stroke-color": "rgb(0, 0, 0)", + "-webkit-text-stroke-width": "0px", + "-webkit-user-drag": "auto", + "-webkit-user-modify": "read-only", + "-webkit-writing-mode": "horizontal-tb", + "--bg-gray": "rgb(82, 86, 89)", + "--text-gray": "rgb(51, 51, 51)", + "--accent-blue": "#0066cc", + "--sidebar-gray": "#d1d4d2", + "--black-bar": "#2b2b2b", + "--border-gray": "#dddddd", + "--paper-white": "#ffffff", + "--text-dark": "rgb(0, 0, 0)" + } + } +} \ No newline at end of file diff --git a/tests/screenshots/new-full-rendered.png b/tests/screenshots/new-full-rendered.png new file mode 100644 index 0000000..964dd6b Binary files /dev/null and b/tests/screenshots/new-full-rendered.png differ diff --git a/tests/screenshots/new-fullpage.png b/tests/screenshots/new-fullpage.png new file mode 100644 index 0000000..1914c71 Binary files /dev/null and b/tests/screenshots/new-fullpage.png differ diff --git a/tests/screenshots/new-header.png b/tests/screenshots/new-header.png new file mode 100644 index 0000000..8e9b949 Binary files /dev/null and b/tests/screenshots/new-header.png differ diff --git a/tests/screenshots/new-sidebar.png b/tests/screenshots/new-sidebar.png new file mode 100644 index 0000000..aefd15a Binary files /dev/null and b/tests/screenshots/new-sidebar.png differ diff --git a/tests/screenshots/old-full-rendered.png b/tests/screenshots/old-full-rendered.png new file mode 100644 index 0000000..5acdc21 Binary files /dev/null and b/tests/screenshots/old-full-rendered.png differ diff --git a/tests/screenshots/old-fullpage.png b/tests/screenshots/old-fullpage.png new file mode 100644 index 0000000..5acdc21 Binary files /dev/null and b/tests/screenshots/old-fullpage.png differ diff --git a/tests/screenshots/sidebar-comparison.json b/tests/screenshots/sidebar-comparison.json new file mode 100644 index 0000000..ff7120b --- /dev/null +++ b/tests/screenshots/sidebar-comparison.json @@ -0,0 +1,9 @@ +{ + "old": {}, + "new": { + "backgroundColor": "rgb(209, 212, 210)", + "padding": "32px 24px", + "width": "300px", + "minWidth": "auto" + } +} \ No newline at end of file diff --git a/tests/screenshots/typography-comparison.json b/tests/screenshots/typography-comparison.json new file mode 100644 index 0000000..0821b3a --- /dev/null +++ b/tests/screenshots/typography-comparison.json @@ -0,0 +1,37 @@ +{ + "old": {}, + "new": { + "name": { + "fontFamily": "Quicksand, sans-serif", + "fontSize": "35.2px", + "fontWeight": "400", + "lineHeight": "38.72px", + "color": "rgb(0, 0, 0)", + "letterSpacing": "normal" + }, + "sidebarTitle": { + "fontFamily": "Quicksand, sans-serif", + "fontSize": "18.72px", + "fontWeight": "500", + "lineHeight": "22.464px", + "color": "rgb(51, 51, 51)", + "letterSpacing": "normal" + }, + "sectionTitle": { + "fontFamily": "Quicksand, sans-serif", + "fontSize": "20.8px", + "fontWeight": "500", + "lineHeight": "24.96px", + "color": "rgb(51, 51, 51)", + "letterSpacing": "normal" + }, + "badge": { + "fontFamily": "Quicksand, \"Source Sans Pro\", -apple-system, system-ui, sans-serif", + "fontSize": "14.4px", + "fontWeight": "400", + "lineHeight": "21.6px", + "color": "rgb(204, 204, 204)", + "letterSpacing": "normal" + } + } +} \ No newline at end of file diff --git a/tests/visual-comparison.spec.js b/tests/visual-comparison.spec.js new file mode 100644 index 0000000..30883a1 --- /dev/null +++ b/tests/visual-comparison.spec.js @@ -0,0 +1,353 @@ +/** + * Visual Comparison Test Suite + * Compares new Go+HTMX CV (localhost:1999) vs old React CV (localhost:3000) + */ + +const { test, expect } = require('@playwright/test'); +const fs = require('fs'); +const path = require('path'); + +const OLD_SITE = 'http://localhost:3000'; +const NEW_SITE = 'http://localhost:1999'; +const SCREENSHOTS_DIR = path.join(__dirname, 'screenshots'); + +// Ensure screenshots directory exists +if (!fs.existsSync(SCREENSHOTS_DIR)) { + fs.mkdirSync(SCREENSHOTS_DIR, { recursive: true }); +} + +test.describe('Visual Comparison: New vs Old CV', () => { + + test('Full page screenshots', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + // Load both sites + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + // Take full page screenshots + await pageOld.screenshot({ + path: path.join(SCREENSHOTS_DIR, 'old-fullpage.png'), + fullPage: true + }); + await pageNew.screenshot({ + path: path.join(SCREENSHOTS_DIR, 'new-fullpage.png'), + fullPage: true + }); + + console.log('✓ Full page screenshots saved'); + + await contextOld.close(); + await contextNew.close(); + }); + + test('Header section comparison', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + // Screenshot header sections + const headerOld = await pageOld.locator('.cv-title-badges-header, [class*="header"]').first(); + const headerNew = await pageNew.locator('.cv-title-badges-header').first(); + + if (await headerOld.count() > 0) { + await headerOld.screenshot({ path: path.join(SCREENSHOTS_DIR, 'old-header.png') }); + } + if (await headerNew.count() > 0) { + await headerNew.screenshot({ path: path.join(SCREENSHOTS_DIR, 'new-header.png') }); + } + + console.log('✓ Header screenshots saved'); + + await contextOld.close(); + await contextNew.close(); + }); + + test('Badge measurements comparison', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + // Measure badge elements + const measurements = { + old: {}, + new: {} + }; + + // New site badge measurements + const badgeNew = pageNew.locator('.title-badge').first(); + if (await badgeNew.count() > 0) { + const box = await badgeNew.boundingBox(); + const styles = await badgeNew.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + height: computed.height, + padding: computed.padding, + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + borderRadius: computed.borderRadius, + display: computed.display, + alignItems: computed.alignItems + }; + }); + measurements.new.badge = { box, styles }; + } + + // Old site badge measurements + const badgeOld = pageOld.locator('.title-badge, [class*="badge"]').first(); + if (await badgeOld.count() > 0) { + const box = await badgeOld.boundingBox(); + const styles = await badgeOld.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + height: computed.height, + padding: computed.padding, + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + color: computed.color, + backgroundColor: computed.backgroundColor, + borderRadius: computed.borderRadius, + display: computed.display, + alignItems: computed.alignItems + }; + }); + measurements.old.badge = { box, styles }; + } + + // Save measurements + fs.writeFileSync( + path.join(SCREENSHOTS_DIR, 'badge-measurements.json'), + JSON.stringify(measurements, null, 2) + ); + + console.log('✓ Badge measurements saved'); + console.log('\nBadge Comparison:'); + console.log('OLD:', JSON.stringify(measurements.old.badge?.styles, null, 2)); + console.log('NEW:', JSON.stringify(measurements.new.badge?.styles, null, 2)); + + await contextOld.close(); + await contextNew.close(); + }); + + test('Typography comparison', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + const typography = { + old: {}, + new: {} + }; + + // Selectors to compare + const selectors = { + name: '.cv-name', + sidebarTitle: '.sidebar-title', + sectionTitle: '.section-title', + badge: '.title-badge' + }; + + // Measure new site typography + for (const [key, selector] of Object.entries(selectors)) { + const element = pageNew.locator(selector).first(); + if (await element.count() > 0) { + typography.new[key] = await element.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + fontFamily: computed.fontFamily, + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + lineHeight: computed.lineHeight, + color: computed.color, + letterSpacing: computed.letterSpacing + }; + }); + } + } + + // Measure old site typography + for (const [key, selector] of Object.entries(selectors)) { + const element = pageOld.locator(selector).first(); + if (await element.count() > 0) { + typography.old[key] = await element.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + fontFamily: computed.fontFamily, + fontSize: computed.fontSize, + fontWeight: computed.fontWeight, + lineHeight: computed.lineHeight, + color: computed.color, + letterSpacing: computed.letterSpacing + }; + }); + } + } + + // Save typography comparison + fs.writeFileSync( + path.join(SCREENSHOTS_DIR, 'typography-comparison.json'), + JSON.stringify(typography, null, 2) + ); + + console.log('✓ Typography comparison saved'); + console.log('\nTypography Comparison:'); + console.log('OLD:', JSON.stringify(typography.old, null, 2)); + console.log('NEW:', JSON.stringify(typography.new, null, 2)); + + await contextOld.close(); + await contextNew.close(); + }); + + test('Sidebar comparison', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + // Screenshot sidebars + const sidebarOld = pageOld.locator('.cv-sidebar, [class*="sidebar"]').first(); + const sidebarNew = pageNew.locator('.cv-sidebar').first(); + + if (await sidebarOld.count() > 0) { + await sidebarOld.screenshot({ path: path.join(SCREENSHOTS_DIR, 'old-sidebar.png') }); + } + if (await sidebarNew.count() > 0) { + await sidebarNew.screenshot({ path: path.join(SCREENSHOTS_DIR, 'new-sidebar.png') }); + } + + // Measure sidebar styles + const sidebarComparison = { + old: {}, + new: {} + }; + + if (await sidebarNew.count() > 0) { + sidebarComparison.new = await sidebarNew.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + backgroundColor: computed.backgroundColor, + padding: computed.padding, + width: computed.width, + minWidth: computed.minWidth + }; + }); + } + + if (await sidebarOld.count() > 0) { + sidebarComparison.old = await sidebarOld.evaluate(el => { + const computed = window.getComputedStyle(el); + return { + backgroundColor: computed.backgroundColor, + padding: computed.padding, + width: computed.width, + minWidth: computed.minWidth + }; + }); + } + + fs.writeFileSync( + path.join(SCREENSHOTS_DIR, 'sidebar-comparison.json'), + JSON.stringify(sidebarComparison, null, 2) + ); + + console.log('✓ Sidebar comparison saved'); + console.log('\nSidebar Comparison:'); + console.log('OLD:', JSON.stringify(sidebarComparison.old, null, 2)); + console.log('NEW:', JSON.stringify(sidebarComparison.new, null, 2)); + + await contextOld.close(); + await contextNew.close(); + }); + + test('Critical elements style extraction', async ({ browser }) => { + const contextOld = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + const contextNew = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); + + const pageOld = await contextOld.newPage(); + const pageNew = await contextNew.newPage(); + + await pageOld.goto(OLD_SITE, { waitUntil: 'networkidle' }); + await pageNew.goto(NEW_SITE, { waitUntil: 'networkidle' }); + + const criticalElements = [ + '.cv-title-badges-header', + '.title-badge', + '.badge-separator', + '.sidebar-title', + '.section-title', + '.cv-name' + ]; + + const styleComparison = { + old: {}, + new: {} + }; + + // Extract from new site + for (const selector of criticalElements) { + const element = pageNew.locator(selector).first(); + if (await element.count() > 0) { + styleComparison.new[selector] = await element.evaluate(el => { + const computed = window.getComputedStyle(el); + const styles = {}; + for (let i = 0; i < computed.length; i++) { + const prop = computed[i]; + styles[prop] = computed.getPropertyValue(prop); + } + return styles; + }); + } + } + + // Extract from old site + for (const selector of criticalElements) { + const element = pageOld.locator(selector).first(); + if (await element.count() > 0) { + styleComparison.old[selector] = await element.evaluate(el => { + const computed = window.getComputedStyle(el); + const styles = {}; + for (let i = 0; i < computed.length; i++) { + const prop = computed[i]; + styles[prop] = computed.getPropertyValue(prop); + } + return styles; + }); + } + } + + fs.writeFileSync( + path.join(SCREENSHOTS_DIR, 'critical-elements-full-styles.json'), + JSON.stringify(styleComparison, null, 2) + ); + + console.log('✓ Critical elements styles extracted'); + + await contextOld.close(); + await contextNew.close(); + }); +});