Compare commits
14 Commits
a5989b03b1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
ddcfc8d8d2
|
|||
|
dac44e1b12
|
|||
|
5eb34a0c59
|
|||
|
ef40d25e6a
|
|||
|
718165aa23
|
|||
|
c15adf8e3c
|
|||
|
72f0eab718
|
|||
|
beffd5f4e8
|
|||
|
0c4823d263
|
|||
|
c912cde7f5
|
|||
|
c8d7c168c8
|
|||
|
a2242809b2
|
|||
|
4d43018773
|
|||
|
1f8e5c4c3e
|
@@ -20,13 +20,17 @@ steps:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
commands:
|
commands:
|
||||||
- set -e
|
- set -e
|
||||||
|
- apk add --no-cache jq
|
||||||
|
- APP_VERSION=$(jq -r .version package.json | tr -d '\r\n' | sed 's/^v//')
|
||||||
- echo "=== Building Docker image ==="
|
- echo "=== Building Docker image ==="
|
||||||
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
||||||
- 'echo "Registry repo: $REGISTRY_REPO"'
|
- 'echo "Registry repo: $REGISTRY_REPO"'
|
||||||
|
- 'echo "App version: $APP_VERSION"'
|
||||||
- |
|
- |
|
||||||
docker build \
|
docker build \
|
||||||
--tag $REGISTRY_REPO:${CI_COMMIT_SHA} \
|
--tag "$REGISTRY_REPO:$CI_COMMIT_SHA" \
|
||||||
--tag $REGISTRY_REPO:latest \
|
--tag "$REGISTRY_REPO:latest" \
|
||||||
|
--tag "$REGISTRY_REPO:$APP_VERSION" \
|
||||||
--label "git.commit=${CI_COMMIT_SHA}" \
|
--label "git.commit=${CI_COMMIT_SHA}" \
|
||||||
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
||||||
.
|
.
|
||||||
@@ -82,15 +86,19 @@ steps:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
commands:
|
commands:
|
||||||
- set -e
|
- set -e
|
||||||
|
- apk add --no-cache jq
|
||||||
|
- APP_VERSION=$(jq -r .version package.json | tr -d '\r\n' | sed 's/^v//')
|
||||||
- echo "=== Pushing to registry ==="
|
- echo "=== Pushing to registry ==="
|
||||||
- 'echo "Registry: $REGISTRY_URL"'
|
- 'echo "Registry: $REGISTRY_URL"'
|
||||||
- 'echo "Repository: $REGISTRY_REPO"'
|
- 'echo "Repository: $REGISTRY_REPO"'
|
||||||
|
- 'echo "App version: $APP_VERSION"'
|
||||||
- |
|
- |
|
||||||
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" \
|
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" \
|
||||||
-u "$REGISTRY_USERNAME" \
|
-u "$REGISTRY_USERNAME" \
|
||||||
--password-stdin
|
--password-stdin
|
||||||
- docker push $REGISTRY_REPO:${CI_COMMIT_SHA}
|
- 'docker push $REGISTRY_REPO:$CI_COMMIT_SHA'
|
||||||
- docker push $REGISTRY_REPO:latest
|
- 'docker push $REGISTRY_REPO:latest'
|
||||||
|
- 'docker push $REGISTRY_REPO:$APP_VERSION'
|
||||||
- echo "✓ Images pushed successfully"
|
- echo "✓ Images pushed successfully"
|
||||||
depends_on:
|
depends_on:
|
||||||
- 'Docker image build'
|
- 'Docker image build'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mifi-ventures-landing",
|
"name": "mifi-ventures-landing",
|
||||||
"version": "3.0.0",
|
"version": "4.0.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "https://git.mifi.dev/mifi-ventures/landing.git",
|
"repository": "https://git.mifi.dev/mifi-ventures/landing.git",
|
||||||
"packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268",
|
"packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268",
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"format": "prettier --write \"src/**/*.{ts,js,svelte,css,json}\"",
|
"format": "prettier --write \"src/**/*.{ts,js,svelte,css,json}\" \"static/**/*.{css,html,js}\"",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"lint:css": "stylelint \"src/**/*.css\" \"src/**/*.svelte\"",
|
"lint:css": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" \"static/**/*.css\"",
|
||||||
"lint:css:fix": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" --fix",
|
"lint:css:fix": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" \"static/**/*.css\" --fix",
|
||||||
"preview": "serve dist -p 4173",
|
"preview": "serve dist -p 4173",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:unit": "vitest run",
|
"test:unit": "vitest run",
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ docker run --rm \
|
|||||||
npx serve dist -p 4173 &
|
npx serve dist -p 4173 &
|
||||||
sleep 2
|
sleep 2
|
||||||
pnpm exec playwright test
|
pnpm exec playwright test
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ if [ -n "$CI" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if command -v docker >/dev/null 2>&1; then
|
if command -v docker >/dev/null 2>&1; then
|
||||||
exec bash "$(dirname "$0")/run-e2e-in-docker.sh"
|
bash "$(dirname "$0")/run-e2e-in-docker.sh"
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# No Docker: run in current environment (e.g. devcontainer; same image as CI)
|
# No Docker: run in current environment (e.g. devcontainer; same image as CI)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ if command -v docker >/dev/null 2>&1; then
|
|||||||
sleep 2
|
sleep 2
|
||||||
pnpm exec playwright test --update-snapshots
|
pnpm exec playwright test --update-snapshots
|
||||||
'
|
'
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
else
|
else
|
||||||
echo "Updating snapshots in the current environment (matches CI when using the devcontainer)."
|
echo "Updating snapshots in the current environment (matches CI when using the devcontainer)."
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
49
src/app.css
@@ -131,6 +131,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
Local Font Faces
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
Base Styles
|
Base Styles
|
||||||
======================================== */
|
======================================== */
|
||||||
@@ -178,6 +222,11 @@ body {
|
|||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong,
|
||||||
|
b {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
Skip Link (Accessibility)
|
Skip Link (Accessibility)
|
||||||
======================================== */
|
======================================== */
|
||||||
|
|||||||
@@ -67,11 +67,13 @@ export const privacyPolicy = {
|
|||||||
id: 'analytics-and-tracking',
|
id: 'analytics-and-tracking',
|
||||||
heading: 'Analytics and Tracking Technologies',
|
heading: 'Analytics and Tracking Technologies',
|
||||||
body: [
|
body: [
|
||||||
'We use third-party analytics and advertising tools to understand how visitors use this website and to improve our services.',
|
'We use a mix of first-party and third-party analytics tools to understand how visitors use this website and to improve our services.',
|
||||||
'We partner with Microsoft Clarity and Microsoft Advertising to capture how you use and interact with our website through behavioral metrics, heatmaps, and session replay to improve and market our products and services. Website usage data is captured using first- and third-party cookies and similar tracking technologies to determine the popularity of content and online activity. We also use this information for site optimization, security and fraud detection, and advertising.',
|
'We use Umami as a first-party analytics tool to measure aggregate usage of this site for internal reporting and performance insights; Umami data is not sold or shared for third-party advertising.',
|
||||||
|
'We partner with Microsoft Clarity and Microsoft Advertising to capture how you use and interact with our website through behavioral metrics, heatmaps, and session replay to improve and market our products and services. Website usage data is captured using first- and third-party cookies and similar tracking technologies to determine the popularity of content and online activity. We also use this information for site optimization, security and fraud detection, and advertising. These third-party tools only run if you consent to non-essential analytics via our cookie banner.',
|
||||||
'For more information about how Microsoft collects and uses your data, see the Microsoft Privacy Statement: https://www.microsoft.com/privacy/privacystatement.',
|
'For more information about how Microsoft collects and uses your data, see the Microsoft Privacy Statement: https://www.microsoft.com/privacy/privacystatement.',
|
||||||
'We also use Google Analytics to collect information about website usage, such as pages visited, time on site, and browser and device information. Google Analytics uses cookies and similar technologies to help us analyze how visitors use the site and to compile aggregated statistics.',
|
'We also use Google Analytics (only if you consent) to collect information about website usage, such as pages visited, time on site, and browser and device information. Google Analytics uses cookies and similar technologies to help us analyze how visitors use the site and to compile aggregated statistics.',
|
||||||
'You can learn more about how Google handles data in Google Analytics at: https://policies.google.com/privacy and https://policies.google.com/technologies/partner-sites.',
|
'You can learn more about how Google handles data in Google Analytics at: https://policies.google.com/privacy and https://policies.google.com/technologies/partner-sites.',
|
||||||
|
'We store your analytics preference (for example, whether you accepted or rejected non-essential analytics) in a small piece of first-party device storage so we can remember your choice on future visits.',
|
||||||
],
|
],
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
@@ -197,6 +199,7 @@ export const privacyPolicy = {
|
|||||||
heading: 'Your Rights',
|
heading: 'Your Rights',
|
||||||
body: [
|
body: [
|
||||||
'Depending on your jurisdiction, you may have the right to: request access to personal data; request correction or deletion of data; withdraw consent for communications.',
|
'Depending on your jurisdiction, you may have the right to: request access to personal data; request correction or deletion of data; withdraw consent for communications.',
|
||||||
|
'If you are located in a region with specific data protection laws (such as the European Economic Area or the United Kingdom), you may have additional rights under those laws; we will handle such requests in line with applicable legal requirements.',
|
||||||
'Requests may be submitted using the contact information below.',
|
'Requests may be submitted using the contact information below.',
|
||||||
],
|
],
|
||||||
list: [
|
list: [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Terms of Service content for mifi Ventures. Used by /terms-of-service.
|
* Terms of Service content for mifi Ventures. Used by /terms-of-service.
|
||||||
* Last updated: March 5, 2026. OpenPhone / A2P messaging compliance.
|
* Last updated: March 12, 2026. OpenPhone / A2P messaging compliance; data protection positioning.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface LegalSection {
|
export interface LegalSection {
|
||||||
@@ -12,7 +12,7 @@ export interface LegalSection {
|
|||||||
|
|
||||||
export const termsOfService = {
|
export const termsOfService = {
|
||||||
title: 'Terms of Service',
|
title: 'Terms of Service',
|
||||||
lastUpdated: 'March 5, 2026',
|
lastUpdated: 'March 12, 2026',
|
||||||
intro: [
|
intro: [
|
||||||
'These Terms of Service govern the use of the website operated by mifi Ventures LLC ("mifi Ventures", "we", "our", or "us").',
|
'These Terms of Service govern the use of the website operated by mifi Ventures LLC ("mifi Ventures", "we", "our", or "us").',
|
||||||
'By accessing or using this website, you agree to these terms. If you do not agree, you should not use this website.',
|
'By accessing or using this website, you agree to these terms. If you do not agree, you should not use this website.',
|
||||||
@@ -71,6 +71,14 @@ export const termsOfService = {
|
|||||||
'This website may reference or integrate with third-party platforms or services. mifi Ventures is not responsible for the privacy practices or content of external services.',
|
'This website may reference or integrate with third-party platforms or services. mifi Ventures is not responsible for the privacy practices or content of external services.',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'data-protection-and-privacy',
|
||||||
|
heading: 'Data Protection and Privacy',
|
||||||
|
body: [
|
||||||
|
'Your use of this website is also subject to our Privacy Policy, which explains what information we collect, how it is used, and your choices. By using this website, you acknowledge that you have reviewed the Privacy Policy.',
|
||||||
|
'mifi Ventures is based in the United States and primarily serves U.S.-based clients. However, if you are located in a region with specific data protection laws (such as the European Economic Area or the United Kingdom), we will handle personal data in accordance with applicable data protection requirements to the extent they apply and as described in the Privacy Policy.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'limitation-of-liability',
|
id: 'limitation-of-liability',
|
||||||
heading: 'Limitation of Liability',
|
heading: 'Limitation of Liability',
|
||||||
@@ -78,6 +86,14 @@ export const termsOfService = {
|
|||||||
'To the fullest extent permitted by law, mifi Ventures LLC shall not be liable for indirect, incidental, or consequential damages arising from use of this website or related services.',
|
'To the fullest extent permitted by law, mifi Ventures LLC shall not be liable for indirect, incidental, or consequential damages arising from use of this website or related services.',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'governing-law',
|
||||||
|
heading: 'Governing Law and Jurisdiction',
|
||||||
|
body: [
|
||||||
|
'These Terms of Service are governed by the laws of the Commonwealth of Massachusetts and applicable federal law of the United States, without regard to conflict of law principles.',
|
||||||
|
'Any disputes arising out of or relating to these terms or your use of this website shall be brought exclusively in the state or federal courts located in Massachusetts, except where applicable data protection laws provide you with mandatory rights to bring claims in another jurisdiction.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'changes',
|
id: 'changes',
|
||||||
heading: 'Changes to These Terms',
|
heading: 'Changes to These Terms',
|
||||||
|
|||||||
@@ -47,13 +47,6 @@
|
|||||||
type="font/woff2"
|
type="font/woff2"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
|
||||||
as="font"
|
|
||||||
type="font/woff2"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
@@ -61,13 +54,6 @@
|
|||||||
type="font/woff2"
|
type="font/woff2"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/assets/fonts/inter-v20-latin-italic.woff2"
|
|
||||||
as="font"
|
|
||||||
type="font/woff2"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
href="/assets/fonts/inter-v20-latin-500.woff2"
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
|||||||
@@ -50,7 +50,9 @@
|
|||||||
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
||||||
{#each section.body as para}
|
{#each section.body as para}
|
||||||
<p>
|
<p>
|
||||||
{#if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
{#if section.id === 'contact' && para === 'mifi Ventures LLC'}
|
||||||
|
<strong>{para}</strong>
|
||||||
|
{:else if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
||||||
<a href="mailto:legal@mifi.ventures"
|
<a href="mailto:legal@mifi.ventures"
|
||||||
>legal@mifi.ventures</a
|
>legal@mifi.ventures</a
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
||||||
{#each section.body as para}
|
{#each section.body as para}
|
||||||
<p>
|
<p>
|
||||||
{#if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
{#if section.id === 'contact' && para === 'mifi Ventures LLC'}
|
||||||
|
<strong>{para}</strong>
|
||||||
|
{:else if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
||||||
<a href="mailto:legal@mifi.ventures"
|
<a href="mailto:legal@mifi.ventures"
|
||||||
>legal@mifi.ventures</a
|
>legal@mifi.ventures</a
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,20 +1,66 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>404 Not Found — mifi Ventures</title>
|
<link
|
||||||
<meta name="theme-color" content="#0052cc" media="(prefers-color-scheme: light)">
|
rel="preload"
|
||||||
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)">
|
href="/assets/fonts/fraunces-v38-latin-600.woff2"
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
as="font"
|
||||||
<link rel="stylesheet" href="/assets/error-pages.css">
|
type="font/woff2"
|
||||||
</head>
|
crossorigin="anonymous"
|
||||||
<body class="error-page">
|
/>
|
||||||
<main>
|
<link
|
||||||
<div class="emoji" aria-hidden="true">🔍</div>
|
rel="preload"
|
||||||
<h1>404 Not Found</h1>
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
<p>This page went off to find itself. We’re not sure it’s coming back.</p>
|
as="font"
|
||||||
<p><a href="/">Back to mifi Ventures →</a></p>
|
type="font/woff2"
|
||||||
</main>
|
crossorigin="anonymous"
|
||||||
</body>
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-600.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<title>404 Not Found — mifi Ventures</title>
|
||||||
|
<meta
|
||||||
|
name="theme-color"
|
||||||
|
content="#0052cc"
|
||||||
|
media="(prefers-color-scheme: light)"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="stylesheet" href="/assets/error-pages.css" />
|
||||||
|
</head>
|
||||||
|
<body class="error-page">
|
||||||
|
<main>
|
||||||
|
<div class="emoji" aria-hidden="true">🔍</div>
|
||||||
|
<h1 data-testid="404-title">404 Not Found</h1>
|
||||||
|
<p>This page went off to find itself. We’re not sure it’s coming back.</p>
|
||||||
|
<p><a href="/">Back to mifi Ventures →</a></p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,20 +1,66 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>410 Gone — mifi Ventures</title>
|
<link
|
||||||
<meta name="theme-color" content="#0052cc" media="(prefers-color-scheme: light)">
|
rel="preload"
|
||||||
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)">
|
href="/assets/fonts/fraunces-v38-latin-600.woff2"
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
as="font"
|
||||||
<link rel="stylesheet" href="/assets/error-pages.css">
|
type="font/woff2"
|
||||||
</head>
|
crossorigin="anonymous"
|
||||||
<body class="error-page">
|
/>
|
||||||
<main>
|
<link
|
||||||
<div class="emoji" aria-hidden="true">👋</div>
|
rel="preload"
|
||||||
<h1>410 Gone</h1>
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
<p>This page has left the building. We’ve moved on—and so should you.</p>
|
as="font"
|
||||||
<p><a href="/">Back to mifi Ventures →</a></p>
|
type="font/woff2"
|
||||||
</main>
|
crossorigin="anonymous"
|
||||||
</body>
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-600.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<title>410 Gone — mifi Ventures</title>
|
||||||
|
<meta
|
||||||
|
name="theme-color"
|
||||||
|
content="#0052cc"
|
||||||
|
media="(prefers-color-scheme: light)"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="stylesheet" href="/assets/error-pages.css" />
|
||||||
|
</head>
|
||||||
|
<body class="error-page">
|
||||||
|
<main>
|
||||||
|
<div class="emoji" aria-hidden="true">👋</div>
|
||||||
|
<h1 data-testid="410-title">410 Gone</h1>
|
||||||
|
<p>This page has left the building. We’ve moved on—and so should you.</p>
|
||||||
|
<p><a href="/">Back to mifi Ventures →</a></p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -32,28 +32,47 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Local fonts — same paths as +layout.svelte preloads */
|
/* Local fonts — same paths as +layout.svelte preloads */
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: Inter;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: Inter;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Fraunces';
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
/* Error page layout */
|
/* Error page layout */
|
||||||
.error-page {
|
.error-page {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -67,15 +86,18 @@
|
|||||||
color: var(--ep-text);
|
color: var(--ep-text);
|
||||||
background-color: var(--ep-bg-alt);
|
background-color: var(--ep-bg-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page main {
|
.error-page main {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2rem 1.5rem;
|
padding: 2rem 1.5rem;
|
||||||
max-width: 28rem;
|
max-width: 28rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page .emoji {
|
.error-page .emoji {
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page h1 {
|
.error-page h1 {
|
||||||
font-family: var(--ep-font-heading);
|
font-family: var(--ep-font-heading);
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@@ -83,19 +105,23 @@
|
|||||||
margin: 0 0 0.75rem;
|
margin: 0 0 0.75rem;
|
||||||
color: var(--ep-text);
|
color: var(--ep-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page p {
|
.error-page p {
|
||||||
margin: 0 0 1.5rem;
|
margin: 0 0 1.5rem;
|
||||||
color: var(--ep-text-secondary);
|
color: var(--ep-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a {
|
.error-page a {
|
||||||
color: var(--ep-primary);
|
color: var(--ep-primary);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a:hover {
|
.error-page a:hover {
|
||||||
color: var(--ep-primary-hover);
|
color: var(--ep-primary-hover);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a:focus-visible {
|
.error-page a:focus-visible {
|
||||||
outline: 2px solid var(--ep-primary);
|
outline: 2px solid var(--ep-primary);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
|
|||||||
@@ -11,6 +11,43 @@
|
|||||||
var BANNER_VISIBLE_CLASS = 'is-visible';
|
var BANNER_VISIBLE_CLASS = 'is-visible';
|
||||||
var hasLoadedThirdParty = false;
|
var hasLoadedThirdParty = false;
|
||||||
|
|
||||||
|
// Trusted Types support (for CSP `require-trusted-types-for 'script'`)
|
||||||
|
// Clarity's tag script looks up window.trustedTypePolicies[policyName] to load its inner script;
|
||||||
|
// we must expose the policy there for Safari (and other browsers) to avoid TT violations.
|
||||||
|
var ttPolicy = null;
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
window.trustedTypes &&
|
||||||
|
typeof window.trustedTypes.createPolicy === 'function'
|
||||||
|
) {
|
||||||
|
ttPolicy = window.trustedTypes.createPolicy('mifi-ventures-policy', {
|
||||||
|
createScriptURL: function (url) {
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ttPolicy && !window.trustedTypePolicies) {
|
||||||
|
window.trustedTypePolicies = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ttPolicy) {
|
||||||
|
window.trustedTypePolicies['mifi-ventures-policy'] = ttPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
ttPolicy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setScriptSrc(el, url) {
|
||||||
|
if (!el) return;
|
||||||
|
if (ttPolicy) {
|
||||||
|
// When Trusted Types are enforced, wrap URLs via our policy
|
||||||
|
el.src = ttPolicy.createScriptURL(url);
|
||||||
|
} else {
|
||||||
|
el.src = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadThirdPartyAnalytics() {
|
function loadThirdPartyAnalytics() {
|
||||||
if (hasLoadedThirdParty) return;
|
if (hasLoadedThirdParty) return;
|
||||||
hasLoadedThirdParty = true;
|
hasLoadedThirdParty = true;
|
||||||
@@ -19,14 +56,16 @@
|
|||||||
try {
|
try {
|
||||||
var gtagScript = document.createElement('script');
|
var gtagScript = document.createElement('script');
|
||||||
gtagScript.async = true;
|
gtagScript.async = true;
|
||||||
gtagScript.src =
|
setScriptSrc(
|
||||||
'https://www.googletagmanager.com/gtag/js?id=G-36F29PDKRT';
|
gtagScript,
|
||||||
|
'https://www.googletagmanager.com/gtag/js?id=G-36F29PDKRT',
|
||||||
|
);
|
||||||
|
|
||||||
gtagScript.onload = function () {
|
gtagScript.onload = function () {
|
||||||
// Load the existing ga-init.js helper once gtag is ready
|
// Load the existing ga-init.js helper once gtag is ready
|
||||||
var gaInit = document.createElement('script');
|
var gaInit = document.createElement('script');
|
||||||
gaInit.defer = true;
|
gaInit.defer = true;
|
||||||
gaInit.src = '/assets/js/ga-init.js';
|
setScriptSrc(gaInit, '/assets/js/ga-init.js');
|
||||||
document.head.appendChild(gaInit);
|
document.head.appendChild(gaInit);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,12 +75,29 @@
|
|||||||
console.error('Failed to load Google Analytics', e);
|
console.error('Failed to load Google Analytics', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Microsoft Clarity
|
// Microsoft Clarity – use the official loader snippet so that
|
||||||
|
// window.clarity is defined before the tag script runs.
|
||||||
try {
|
try {
|
||||||
var clarityScript = document.createElement('script');
|
(function (c, l, a, r, i, t, y) {
|
||||||
clarityScript.defer = true;
|
c[a] =
|
||||||
clarityScript.src = 'https://www.clarity.ms/tag/vuo5q3yf79?ref=bwt';
|
c[a] ||
|
||||||
document.head.appendChild(clarityScript);
|
function () {
|
||||||
|
(c[a].q = c[a].q || []).push(arguments);
|
||||||
|
};
|
||||||
|
t = l.createElement(r);
|
||||||
|
t.async = 1;
|
||||||
|
setScriptSrc(
|
||||||
|
t,
|
||||||
|
`https://www.clarity.ms/tag/${i}?trustedTypes=mifi-ventures-policy`,
|
||||||
|
);
|
||||||
|
y = l.getElementsByTagName(r)[0];
|
||||||
|
y.parentNode.insertBefore(t, y);
|
||||||
|
})(window, document, 'clarity', 'script', 'vuo5q3yf79');
|
||||||
|
|
||||||
|
window.clarity('consentv2', {
|
||||||
|
ad_Storage: 'granted',
|
||||||
|
analytics_Storage: 'granted',
|
||||||
|
});
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
console.error('Failed to load Microsoft Clarity', e2);
|
console.error('Failed to load Microsoft Clarity', e2);
|
||||||
}
|
}
|
||||||
@@ -110,4 +166,3 @@
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
var el = document.getElementById('copyright-year');
|
var el = document.getElementById('copyright-year');
|
||||||
if (el) el.textContent = new Date().getFullYear();
|
if (el) el.textContent = new Date().getFullYear();
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){ window.dataLayer.push(arguments); }
|
function gtag() {
|
||||||
|
window.dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
gtag("js", new Date());
|
gtag('js', new Date());
|
||||||
gtag("config", "G-36F29PDKRT", {
|
gtag('config', 'G-36F29PDKRT', {
|
||||||
// optional, but often helpful:
|
// optional, but often helpful:
|
||||||
anonymize_ip: true,
|
anonymize_ip: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
const MOBILE_BREAKPOINT_PX = 768;
|
const MOBILE_BREAKPOINT_PX = 768;
|
||||||
|
|
||||||
/** All focusable elements inside the menu (links). */
|
/** All focusable elements inside the menu (links). */
|
||||||
const getMenuFocusables = (menu) =>
|
const getMenuFocusables = (menu) => menu.querySelectorAll('a[href]');
|
||||||
menu.querySelectorAll('a[href]');
|
|
||||||
|
|
||||||
const mobileMenuHelper = () => {
|
const mobileMenuHelper = () => {
|
||||||
const mobileMenu = document.getElementById('nav-menu');
|
const mobileMenu = document.getElementById('nav-menu');
|
||||||
@@ -15,10 +14,7 @@ const mobileMenuHelper = () => {
|
|||||||
const syncMenuAriaHidden = () => {
|
const syncMenuAriaHidden = () => {
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
const hidden = !mobileMenuToggle.checked;
|
const hidden = !mobileMenuToggle.checked;
|
||||||
mobileMenu.setAttribute(
|
mobileMenu.setAttribute('aria-hidden', hidden ? 'true' : 'false');
|
||||||
'aria-hidden',
|
|
||||||
hidden ? 'true' : 'false',
|
|
||||||
);
|
|
||||||
// inert removes the subtree from the a11y tree and makes descendants non-focusable
|
// inert removes the subtree from the a11y tree and makes descendants non-focusable
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
mobileMenu.setAttribute('inert', '');
|
mobileMenu.setAttribute('inert', '');
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
// Umami: safe track (no-op if script blocked or not loaded)
|
// Umami: safe track (no-op if script blocked or not loaded)
|
||||||
function umamiTrack(name, data) {
|
function umamiTrack(name, data) {
|
||||||
if (
|
if (typeof window.umami !== 'undefined' && typeof window.umami.track === 'function') {
|
||||||
typeof window.umami !== 'undefined' &&
|
|
||||||
typeof window.umami.track === 'function'
|
|
||||||
) {
|
|
||||||
if (data != null) window.umami.track(name, data);
|
if (data != null) window.umami.track(name, data);
|
||||||
else window.umami.track(name);
|
else window.umami.track(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ describe('cookie-consent.js', () => {
|
|||||||
dom = createBannerDOM();
|
dom = createBannerDOM();
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
});
|
});
|
||||||
@@ -62,7 +61,6 @@ describe('cookie-consent.js', () => {
|
|||||||
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
|
|
||||||
@@ -82,7 +80,6 @@ describe('cookie-consent.js', () => {
|
|||||||
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
|
|
||||||
|
|||||||
@@ -140,4 +140,16 @@ test.describe('visual regression', () => {
|
|||||||
await expect(page.locator('#cookie-banner')).not.toBeVisible();
|
await expect(page.locator('#cookie-banner')).not.toBeVisible();
|
||||||
await expect(page).toHaveScreenshot('terms-of-service.png', { fullPage: true });
|
await expect(page).toHaveScreenshot('terms-of-service.png', { fullPage: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('404 page matches snapshot', async ({ page }) => {
|
||||||
|
await page.goto('/404');
|
||||||
|
await expect(page).toHaveTitle(/404 | mifi Ventures/);
|
||||||
|
await expect(page).toHaveScreenshot('404.png', { fullPage: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('410 page matches snapshot', async ({ page }) => {
|
||||||
|
await page.goto('/410');
|
||||||
|
await expect(page).toHaveTitle(/410 | mifi Ventures/);
|
||||||
|
await expect(page).toHaveScreenshot('410.png', { fullPage: true });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
BIN
tests/visual.spec.ts-snapshots/404-chromium-desktop-linux.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
tests/visual.spec.ts-snapshots/404-chromium-mobile-linux.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
tests/visual.spec.ts-snapshots/410-chromium-desktop-linux.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
tests/visual.spec.ts-snapshots/410-chromium-mobile-linux.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 554 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 571 KiB After Width: | Height: | Size: 611 KiB |
|
Before Width: | Height: | Size: 704 KiB After Width: | Height: | Size: 566 KiB |
|
Before Width: | Height: | Size: 715 KiB After Width: | Height: | Size: 845 KiB |
|
Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 297 KiB |
|
Before Width: | Height: | Size: 398 KiB After Width: | Height: | Size: 430 KiB |
|
Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 583 KiB |
|
Before Width: | Height: | Size: 817 KiB After Width: | Height: | Size: 872 KiB |
|
Before Width: | Height: | Size: 927 KiB After Width: | Height: | Size: 683 KiB |
|
Before Width: | Height: | Size: 941 KiB After Width: | Height: | Size: 1011 KiB |
|
Before Width: | Height: | Size: 703 KiB After Width: | Height: | Size: 544 KiB |
|
Before Width: | Height: | Size: 695 KiB After Width: | Height: | Size: 748 KiB |
|
Before Width: | Height: | Size: 886 KiB After Width: | Height: | Size: 635 KiB |
|
Before Width: | Height: | Size: 891 KiB After Width: | Height: | Size: 961 KiB |
|
Before Width: | Height: | Size: 367 KiB After Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 374 KiB After Width: | Height: | Size: 532 KiB |