Compare commits

..

10 Commits

Author SHA1 Message Date
dm
146e738c09 Kontakt - poprawka nagłowka
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 1m56s
2025-12-21 18:57:46 +01:00
dm
92edbad2c2 Poprawki w konfiguracji 2025-12-21 18:52:49 +01:00
dm
b065db4faf Poprawka w rozszerzeniu pliku highlightUtils 2025-12-21 18:32:32 +01:00
dm
ed513957c3 Ulepszona konfiguracja 2025-12-21 18:26:20 +01:00
dm
12be46d038 Sitemap - przywrócenie 2025-12-21 18:17:14 +01:00
dm
0d967ea6c8 Style inline usuniecie i wstawienie do css 2025-12-21 17:28:47 +01:00
dm
259ee007db Dodanie Title i Description strony do yamli oraz jezeli nie ma seo to do strony 2025-12-21 17:24:09 +01:00
dm
e9f440353d Robot.txt 2025-12-21 15:18:02 +01:00
dm
f91b557efd Mapa zasięgu kontener na listę miejscowości 2025-12-21 14:05:17 +01:00
dm
832ee2e796 Kontakt ukruty dymek, Lista miejscowości wyrównywanie pod mapą 2025-12-21 13:00:32 +01:00
23 changed files with 340 additions and 159 deletions

View File

@@ -17,6 +17,7 @@ export default defineConfig({
build: { build: {
minify: "esbuild", minify: "esbuild",
cssMinify: "esbuild", cssMinify: "esbuild",
chunkSizeWarningLimit: 500,
}, },
}, },
integrations: [ integrations: [

View File

@@ -1,5 +1,6 @@
{ {
"name": "fuz20", "name": "fuz-site",
"type": "module",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {

15
public/robots.txt Normal file
View File

@@ -0,0 +1,15 @@
# robots.txt dla FUZ Adam Rojek
# https://www.fuz.pl/robots.txt
User-agent: *
Allow: /
# Sitemap
Sitemap: https://www.fuz.dariuszm.eu/sitemap.xml
# Crawl-delay (opcjonalnie)
# Crawl-delay: 1
# Zablokuj crawlowanie zbędnych ścieżek (jeśli są)
Disallow: /pages/api/
Disallow: /_astro/

View File

@@ -11,32 +11,4 @@ const sorted = cities.sort((a: string, b: any) => a.localeCompare(b, "pl"));
<span class="fuz-city-item">{city}</span> <span class="fuz-city-item">{city}</span>
))} ))}
</div> </div>
</div> </div>
<style>
.fuz-cities-box {
background: var(--f-background);
color: var(--f-text);
padding: 16px;
}
.fuz-cities-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 12px;
}
.fuz-cities-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
gap: 6px 14px;
font-size: 0.95rem;
line-height: 1.4;
}
.fuz-city-item {
color: var(--f-text);
}
</style>

View File

@@ -102,21 +102,21 @@ const domId = `fuz-map-${Math.random().toString(36).slice(2)}`;
position: { lat, lng: lon } position: { lat, lng: lon }
}); });
if (title || desc) { // if (title || desc) {
const { InfoWindow } = await google.maps.importLibrary("maps"); // const { InfoWindow } = await google.maps.importLibrary("maps");
const info = new InfoWindow({ // const info = new InfoWindow({
content: ` // content: `
<div class="f-info-window"> // <div class="f-info-window">
<div class="f-info-header"> // <div class="f-info-header">
<div class="f-info-city">${title}</div> // <div class="f-info-city">${title}</div>
<div class="f-info-street">${desc}</div> // <div class="f-info-street">${desc}</div>
</div> // </div>
</div> // </div>
` // `
}); // });
info.open({ map, anchor: marker }); // info.open({ map, anchor: marker });
} // }
} }
} catch (error) { } catch (error) {
console.error("Error initializing map:", error); console.error("Error initializing map:", error);

View File

@@ -21,10 +21,10 @@ const sectionImages = import.meta.glob<{ default: ImageMetadata }>(
const sectionImage = section.image ? findSectionImage(sectionImages, section.image) : null; const sectionImage = section.image ? findSectionImage(sectionImages, section.image) : null;
const isAboveFold = index === 0; const isAboveFold = index === 0;
// Konfiguracja wyświetlania // Konfiguracja wyświetlania
const showTitle = section.showTitle !== false; // domyślnie true const showTitle = section.showTitle !== false; // domyślnie true
// Formatowanie listy miejscowości jako string // Formatowanie listy miejscowości jako string
const citiesText = cities.join(", "); const citiesText = cities.join(", ");
--- ---
@@ -66,33 +66,6 @@ const citiesText = cities.join(", ");
</a> </a>
</p> </p>
)} )}
<!-- {
section.button && (
<div class="f-section-nav mt-6">
<a href={section.button.url}
class="btn btn-primary"
title={section.button.title}
>
{section.button.text}
</a>
</div>
)
} -->
</div> </div>
</div> </div>
</section> </section>
<!-- <style>
.f-cities-paragraph {
margin-top: 1.5rem;
font-size: 1rem;
line-height: 1.8;
color: var(--f-text, #212529);
}
:global(.dark) .f-cities-paragraph {
color: var(--f-text-dark, #f7fafc);
}
</style> -->

View File

@@ -1,6 +1,8 @@
# tytuł dokumentu jednoczesnie tytułem strony <title></title>
title: "Polityka Prywatności" title: "Polityka Prywatności"
# opis wstawiany w <meta name="description" content=""
description: Polityka prywatności, opisuje zasady ochrony Twoich danych osobowych.
visible: true visible: true
intro: Polityka prywatności, opisuje zasady ochrony Twoich danych osobowych.
content: | content: |
## §1. Informacje podstawowe. ## §1. Informacje podstawowe.

View File

@@ -1,6 +1,6 @@
title: "Promocja świąteczna" title: "Promocja świąteczna"
description: Przykładowo gdybysmy dodali promocję do dokumentów
visible: true visible: true
intro: Przykładowo gdybysmy dodali promocję do dokumentów
content: | content: |
Jeśli kupujesz w sklepach internetowych, prawdopodobnie co pewien czas natykasz się na opisy, które nie zachęcają do zakupów. Jeśli kupujesz w sklepach internetowych, prawdopodobnie co pewien czas natykasz się na opisy, które nie zachęcają do zakupów.
Do najczęściej powtarzanych błędów opisów produktów należą: Do najczęściej powtarzanych błędów opisów produktów należą:

View File

@@ -1,6 +1,6 @@
page: page:
title: "FUZ Adam Rojek - Internet Światłowodowy Wyszków | Szybki i Stabilny" title: "FUZ Adam Rojek - Internet Światłowodowy Wyszków"
description: "Internet światłowodowy w Wyszkowie i okolicach. Lokalny operator z doświadczeniem - stabilne łącze, profesjonalny serwis, konkurencyjne ceny. Sprawdź dostępność!" description: "Internet światłowodowy w Wyszkowie i okolicach. Lokalny operator z doświadczeniem - stabilne łącze, profesjonalny serwis, konkurencyjne ceny."
image: "/og/home-og.png" image: "/og/home-og.png"
url: "/" url: "/"
keywords: keywords:

View File

@@ -1,3 +1,5 @@
title: Możliwości telewizji JAMBOX
description: Poznaj funkcje i udogodnienia dostępne na dekoderach telewizji JAMBOX.
sections: sections:
- title: CatchUp - Archiwum TV - title: CatchUp - Archiwum TV
image: https://www.jambox.pl/sites/default/files/jambox-kyanit-catchup1.png image: https://www.jambox.pl/sites/default/files/jambox-kyanit-catchup1.png

View File

@@ -1,7 +1,7 @@
import { useMemo } from "preact/hooks"; import { useMemo } from "preact/hooks";
import { marked } from "marked"; import { marked } from "marked";
import { useLocalSearch } from "../../hooks/useLocalSearch.js"; import { useLocalSearch } from "../../hooks/useLocalSearch.js";
import { highlightText, highlightHtml } from "../../lib/highlightUtils.js"; import { highlightText, highlightHtml } from "../../lib/highlightUtils.jsx";
import "../../styles/jambox-search.css"; import "../../styles/jambox-search.css";
/** /**
@@ -46,6 +46,7 @@ export default function JamboxMozliwosciSearch({ items = [] }) {
<div className="f-chsearch__top"> <div className="f-chsearch__top">
<div className="f-chsearch__inputwrap"> <div className="f-chsearch__inputwrap">
<input <input
name="search"
className="f-chsearch__input" className="f-chsearch__input"
type="search" type="search"
value={search.query} value={search.query}

View File

@@ -52,6 +52,7 @@ const jsonExtra = meta.extraSchema ? JSON.stringify(meta.extraSchema) : null;
/> />
<link rel="canonical" href={meta.canonical} /> <link rel="canonical" href={meta.canonical} />
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml" />
<!-- OpenGraph --> <!-- OpenGraph -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />

View File

@@ -11,13 +11,44 @@ import Cookie from "../islands/Cookie.jsx";
import rawCookie from "../content/site/cookie.yaml?raw"; import rawCookie from "../content/site/cookie.yaml?raw";
const cookieCfg = yaml.parse(rawCookie); const cookieCfg = yaml.parse(rawCookie);
const { seo } = Astro.props;
// ✅ Pobierz wszystkie możliwe props
const {
seo, // Pełny obiekt SEO (stary sposób)
title, // Indywidualny title (nowy sposób)
description, // Indywidualny description (nowy sposób)
image, // Opcjonalny image
keywords, // Opcjonalne keywords
url, // Opcjonalny url
} = Astro.props;
// ✅ PRIORYTET: title/description → seo → undefined
let finalSeo;
// Jeśli mamy indywidualne pola (title lub description) - użyj ich
if (title || description) {
finalSeo = {
page: {
title,
description,
image,
keywords,
url,
},
};
}
// Jeśli nie ma indywidualnych, ale jest seo object - użyj go
else if (seo) {
finalSeo = seo;
}
// Jeśli nic nie ma - undefined (użyje global defaults z BaseHead)
else {
finalSeo = undefined;
}
--- ---
<html lang="pl" class="scroll-smooth"> <html lang="pl" class="scroll-smooth">
<head> <BaseHead seo={finalSeo} />
<BaseHead seo={seo} />
</head>
<body class="min-h-screen flex flex-col"> <body class="min-h-screen flex flex-col">
<Header /> <Header />
@@ -32,4 +63,4 @@ const { seo } = Astro.props;
<ThemeToggle client:idle /> <ThemeToggle client:idle />
</div> </div>
</body> </body>
</html> </html>

View File

@@ -395,4 +395,91 @@ export function getRequiredEnv(key: string): string {
} }
return value; return value;
}
// ==================== SITEMAP HELPERS ====================
export type SitemapUrl = {
loc: string;
lastmod?: string;
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
priority?: number;
};
/**
* Generuje sitemap XML z listy URL-i
* @param urls - Tablica URL-i do sitemap
* @returns String z XML sitemap
*
* @example
* const urls = [
* { loc: 'https://example.com/', priority: 1.0, changefreq: 'daily' },
* { loc: 'https://example.com/about', priority: 0.8, changefreq: 'monthly' }
* ];
* const xml = generateSitemapXml(urls);
*/
export function generateSitemapXml(urls: SitemapUrl[]): string {
const urlEntries = urls.map(url => {
const parts = [
' <url>',
` <loc>${url.loc}</loc>`,
];
if (url.lastmod) {
parts.push(` <lastmod>${url.lastmod}</lastmod>`);
}
if (url.changefreq) {
parts.push(` <changefreq>${url.changefreq}</changefreq>`);
}
if (url.priority !== undefined) {
parts.push(` <priority>${url.priority.toFixed(1)}</priority>`);
}
parts.push(' </url>');
return parts.join('\n');
}).join('\n');
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urlEntries}
</urlset>`;
}
/**
* Automatyczne określenie changefreq na podstawie ścieżki URL
* @param path - Ścieżka URL (np. "/internet-swiatlowodowy")
* @returns Częstotliwość zmian
*
* @example
* inferChangeFreq('/') // => 'daily'
* inferChangeFreq('/dokumenty/regulamin') // => 'yearly'
*/
export function inferChangeFreq(path: string): SitemapUrl['changefreq'] {
if (path === '/') return 'daily';
if (path.includes('/internet-') || path.includes('/telefon')) return 'weekly';
if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 'monthly';
if (path.includes('/dokumenty')) return 'yearly';
if (path.includes('/premium')) return 'monthly';
return 'weekly';
}
/**
* Automatyczne określenie priority na podstawie ścieżki URL
* @param path - Ścieżka URL
* @returns Priorytet (0.0 - 1.0)
*
* @example
* inferPriority('/') // => 1.0
* inferPriority('/dokumenty/polityka-prywatnosci') // => 0.5
*/
export function inferPriority(path: string): number {
if (path === '/') return 1.0;
if (path.includes('/internet-') || path.includes('/telefon')) return 0.9;
if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 0.8;
if (path.includes('/premium')) return 0.7;
if (path.includes('/telewizja-mozliwosci')) return 0.7;
if (path.includes('/dokumenty')) return 0.5;
return 0.7;
} }

View File

@@ -4,14 +4,15 @@ import yaml from "js-yaml";
export type DocYaml = { export type DocYaml = {
title: string; title: string;
description: string;
visible?: boolean; visible?: boolean;
intro?: string; content: string;
content: string;
}; };
export type DocEntry = DocYaml & { export type DocEntry = DocYaml & {
slug: string; slug: string;
file: string; file: string;
description: string;
}; };
const DOCS_DIR = path.join(process.cwd(), "src", "content", "document"); const DOCS_DIR = path.join(process.cwd(), "src", "content", "document");
@@ -34,13 +35,14 @@ export function listDocuments(): DocEntry[] {
if (!data.title || typeof data.title !== "string") continue; if (!data.title || typeof data.title !== "string") continue;
if (!data.content || typeof data.content !== "string") continue; if (!data.content || typeof data.content !== "string") continue;
if (!data.description || typeof data.description !== "string") continue;
items.push({ items.push({
slug, slug,
file, file,
title: data.title, title: data.title,
description: data.description,
visible: data.visible ?? false, visible: data.visible ?? false,
intro: data.intro ?? "",
content: data.content, content: data.content,
}); });
} }
@@ -60,14 +62,15 @@ export function getDocumentBySlug(slug: string): DocEntry | null {
if (!data.title || typeof data.title !== "string") return null; if (!data.title || typeof data.title !== "string") return null;
if (!data.content || typeof data.content !== "string") return null; if (!data.content || typeof data.content !== "string") return null;
if (!data.description || typeof data.description !== "string") continue;
return { return {
slug, slug,
file, file,
title: data.title, title: data.title,
visible: data.visible ?? false, visible: data.visible ?? false,
intro: data.intro ?? "",
content: data.content, content: data.content,
description: data.description,
}; };
} }

View File

@@ -15,7 +15,7 @@ if (!doc || doc.visible !== true) {
const html = marked.parse(doc.content); const html = marked.parse(doc.content);
--- ---
<DefaultLayout title={doc.title}> <DefaultLayout title={doc.title} description={doc.description}>
<section class="f-section"> <section class="f-section">
<div class="f-section-grid-single"> <div class="f-section-grid-single">
<a href="/dokumenty" class="f-document-link"> <a href="/dokumenty" class="f-document-link">

View File

@@ -12,6 +12,8 @@ type YamlSection = {
}; };
type YamlData = { type YamlData = {
title?: string;
description?: string;
sections?: YamlSection[]; sections?: YamlSection[];
}; };
@@ -22,10 +24,16 @@ let items: Array<{
content: string; content: string;
}> = []; }> = [];
let pageTitle = "";
let pageDescription = "";
let err = ""; let err = "";
try { try {
const data = loadYaml<YamlData>("./src/content/internet-telewizja/telewizja-mozliwosci.yaml"); const data = loadYaml<YamlData>(
"./src/content/internet-telewizja/telewizja-mozliwosci.yaml",
);
pageTitle = data?.title || pageTitle;
pageDescription = data?.description || pageDescription;
const sections = safeArray<YamlSection>(data?.sections); const sections = safeArray<YamlSection>(data?.sections);
items = sections items = sections
@@ -42,7 +50,7 @@ try {
} }
--- ---
<DefaultLayout title="Możliwości JAMBOX"> <DefaultLayout title={pageTitle} description={pageDescription}>
<section class="f-section" id="top"> <section class="f-section" id="top">
<div class="f-section-grid-single"> <div class="f-section-grid-single">
<h1 class="f-section-title">Możliwości JAMBOX</h1> <h1 class="f-section-title">Możliwości JAMBOX</h1>
@@ -63,4 +71,4 @@ try {
) )
} }
</section> </section>
</DefaultLayout> </DefaultLayout>

View File

@@ -42,18 +42,21 @@ const form = data.form;
<DefaultLayout seo={seo}> <DefaultLayout seo={seo}>
<section class="f-section"> <section class="f-section">
<!-- ✅ Zmieniona struktura - osobne bloki zamiast grida -->
<div class="f-contact-grid"> <div class="f-contact-grid">
{/* row 1: tytuły */}
<h1 class="f-section-title m-0">{data.title}</h1> {/* Lewa kolumna: Kontakt */}
<h1 class="f-section-title m-0">{data.contactFormTitle}</h1> <div class="f-contact-column">
<h1 class="f-section-title">{data.title}</h1>
{/* row 2: treść */} <div class="f-contact-item">
<div class="f-contact-item"> <Markdown text={data.description} />
<Markdown text={data.description} /> </div>
</div> </div>
<div id="form"> {/* Prawa kolumna: Formularz */}
<div class="f-contact-column" id="form">
<h2 class="f-section-title">{data.contactFormTitle}</h2>
<form id="contactForm" class="f-contact-form"> <form id="contactForm" class="f-contact-form">
<div class="f-contact-form-inner"> <div class="f-contact-form-inner">
<input <input
@@ -135,6 +138,7 @@ const form = data.form;
</button> </button>
</form> </form>
</div> </div>
</div> </div>
<div class="mt-10"> <div class="mt-10">
@@ -278,4 +282,4 @@ const form = data.form;
}); });
}); });
</script> </script>
</DefaultLayout> </DefaultLayout>

View File

@@ -28,7 +28,7 @@ const seo = loadYaml("./src/content/mapa-zasiegu/seo.yaml");
class="w-full md:w-[340px] bg-[var(--f-background)] text-[var(--f-text)] class="w-full md:w-[340px] bg-[var(--f-background)] text-[var(--f-text)]
pt-6 px-6 flex flex-col gap-6 overflow-y-auto z-40" pt-6 px-6 flex flex-col gap-6 overflow-y-auto z-40"
> >
<h3 class="text-3xl">Sprawdź dostępność usług</h3> <h1 class="text-3xl">Sprawdź dostępność usług</h1>
<p class="text-sm"> <p class="text-sm">
Wybierz swoją miejscowość i ulicę oraz numer budynku, aby sprawdzić Wybierz swoją miejscowość i ulicę oraz numer budynku, aby sprawdzić
dostępność usług światłowodowych FUZ. dostępność usług światłowodowych FUZ.
@@ -49,7 +49,9 @@ const seo = loadYaml("./src/content/mapa-zasiegu/seo.yaml");
/> />
</div> </div>
</section> </section>
<SectionRenderer src="./src/content/site/area-section.yaml" /> <div class="container md:pl-16">
<SectionRenderer src="./src/content/site/area-section.yaml" />
</div>
<script is:inline> <script is:inline>
let fiberLayer = null; let fiberLayer = null;

View File

@@ -1,49 +0,0 @@
import { globby } from 'globby';
export async function GET() {
const base = "https://www.fuz.pl";
// Pobieramy wszystkie pliki .astro
const files = await globby([
"src/pages/**/*.astro",
"!src/pages/_*.astro", // pomiń pliki zaczynające się od _
"!src/pages/**/[...*", // pomiń catch-all
"!src/pages/**/[**", // pomiń dynamiczne parametry
"!src/pages/sitemap.xml.js", // pomiń samą sitemapę
"!src/pages/api/**" // pomiń API endpoints
]);
// Konwersja ścieżek plikowych → URL-e
const urls = files.map((file) => {
let url = file
.replace("src/pages", "")
.replace(".astro", "");
// obsługa index: /index.astro → /
if (url.endsWith("/index")) {
url = url.replace("/index", "");
}
return url;
});
const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls
.map((url) => {
return `
<url>
<loc>${base}${url}</loc>
<changefreq>weekly</changefreq>
<priority>${url === "/" ? "1.0" : "0.8"}</priority>
</url>`;
})
.join("")}
</urlset>`;
return new Response(body, {
headers: {
"Content-Type": "application/xml",
},
});
}

100
src/pages/sitemap.xml.ts Normal file
View File

@@ -0,0 +1,100 @@
import type { APIRoute } from 'astro';
import {
getEnv,
generateSitemapXml,
inferChangeFreq,
inferPriority,
type SitemapUrl
} from '../lib/astro-helpers';
import { listDocuments } from '../lib/documents';
/**
* Dynamiczny sitemap generator
* GET /sitemap.xml
*/
export const GET: APIRoute = async ({ site }) => {
const base = site?.toString().replace(/\/$/, '') ||
getEnv('PUBLIC_SITE_URL') ||
"https://www.fuz.pl";
const now = new Date().toISOString();
const urls: SitemapUrl[] = [];
// ========================================
// STATYCZNE STRONY
// ========================================
const staticPages = [
'/',
'/internet-swiatlowodowy',
'/internet-telewizja',
'/telefon',
'/mapa-zasiegu',
'/kontakt',
'/dokumenty',
'/premium',
'/telewizja-mozliwosci',
];
staticPages.forEach(path => {
urls.push({
loc: `${base}${path}`,
lastmod: now,
changefreq: inferChangeFreq(path),
priority: inferPriority(path),
});
});
// ========================================
// DYNAMICZNE STRONY: Dokumenty
// ========================================
try {
const docs = listDocuments();
docs
.filter(d => d.visible === true)
.forEach(d => {
const path = `/dokumenty/${d.slug}`;
urls.push({
loc: `${base}${path}`,
lastmod: now,
changefreq: 'yearly',
priority: 0.5,
});
});
} catch (e) {
console.warn('⚠️ Sitemap: Could not load documents:', e);
}
// ========================================
// DYNAMICZNE STRONY: Premium packages (opcjonalnie)
// ========================================
// TODO: Jeśli masz dynamiczne pakiety premium, dodaj tutaj:
/*
try {
const packages = await loadPremiumPackages();
packages.forEach(p => {
urls.push({
loc: `${base}/premium/${p.tid}`,
lastmod: now,
changefreq: 'monthly',
priority: 0.7,
});
});
} catch (e) {
console.warn('⚠️ Sitemap: Could not load premium packages:', e);
}
*/
// ========================================
// GENERUJ XML
// ========================================
const sitemap = generateSitemapXml(urls);
return new Response(sitemap, {
status: 200,
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600', // 1h cache
},
});
};

View File

@@ -31,7 +31,7 @@
} }
*/ */
/* Pulsująca obwódka budynku */ /* Pulsująca obwódka budynku */
.pulse-marker { .pulse-marker {
width: 22px; width: 22px;
@@ -110,14 +110,41 @@
} }
.gm-style-iw-c { .gm-style-iw-c {
background: var(--f-background) !important; background: var(--f-background) !important;
border-radius: 14px !important; border-radius: 14px !important;
box-shadow: 0 4px 18px rgba(0,0,0,0.12) !important; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12) !important;
padding: 0 !important; padding: 0 !important;
} }
.gm-style-iw-d { .gm-style-iw-d {
overflow: visible !important; overflow: visible !important;
padding: 0 !important; padding: 0 !important;
background: transparent !important; background: transparent !important;
}
.fuz-cities-box {
background: var(--f-background);
color: var(--f-text);
padding: 16px;
}
.fuz-cities-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 12px;
}
.fuz-cities-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
gap: 6px 14px;
font-size: 0.95rem;
line-height: 1.4;
}
.fuz-city-item {
color: var(--f-text);
} }