Author SHA1 Message Date
Linus OlofssonandClaude Opus 5.5 c760e11c4c No services: /tjanster, booking steps, offers, galleries and downloads removed everywhere
Linus 2026-11-06: he offers no services; the site has posters and collaborations only. /tjanster went live with the
move to Cleura (it came with the SEO pull request #1) and was redirected to the start page in Caddy the same morning.

- tjanster.astro deleted; Tjänster out of the menu and the 404 page.
- Start page: "Vill du boka en fotografering?" -> "Vill du ha en bild på väggen?" (Se posters); "Så bokar du" ->
  "Posters och samarbeten"; description without "Boka via kundportalen".
- Portfolio intro points to the posters; privacy page: orders of posters and collaborations instead of bookings.
- JSON-LD: Organization instead of ProfessionalService, no ReserveAction, offer catalog, price range or service area.
- llms.txt: no prices, booking, booking steps, services page or booking FAQ; faq.ts keeps only the type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 05:31:20 +01:00
imagesbyolofsson d841cf98b5 chore(portfolio): sync 2026-11-06 2026-11-06 04:23:58 +00:00
23 changed files with 22 additions and 247 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 KiB

+2 -24
View File
@@ -12,7 +12,7 @@ export interface Props {
description: string; description: string;
path?: string; path?: string;
pageType?: 'WebPage' | 'AboutPage' | 'ContactPage' | 'CollectionPage'; pageType?: 'WebPage' | 'AboutPage' | 'ContactPage' | 'CollectionPage';
/** Namn i brödsmulan för undersidor, t.ex. "Tjänster". */ /** Namn i brödsmulan för undersidor, t.ex. "Portfolio". */
breadcrumb?: string; breadcrumb?: string;
faq?: FaqItem[]; faq?: FaqItem[];
/** Absolut URL till sidans huvudbild (og:image). */ /** Absolut URL till sidans huvudbild (og:image). */
@@ -80,7 +80,7 @@ const graph: Record<string, unknown>[] = [
sameAs: [business.social.linkedin, business.social.lightroom], sameAs: [business.social.linkedin, business.social.lightroom],
}, },
{ {
'@type': 'ProfessionalService', '@type': 'Organization',
'@id': ids.business, '@id': ids.business,
name: business.brand, name: business.brand,
url: `${site}/`, url: `${site}/`,
@@ -89,31 +89,9 @@ const graph: Record<string, unknown>[] = [
telephone: business.phone, telephone: business.phone,
image: imageUrl, image: imageUrl,
address, address,
areaServed: business.serviceArea,
priceRange: business.priceRange,
founder: { '@id': ids.person }, founder: { '@id': ids.person },
employee: { '@id': ids.person }, employee: { '@id': ids.person },
sameAs: [business.social.instagram.url, business.social.facebook, business.social.flickr, business.social.lightroom], sameAs: [business.social.instagram.url, business.social.facebook, business.social.flickr, business.social.lightroom],
potentialAction: {
'@type': 'ReserveAction',
name: 'Skicka en bokningsförfrågan',
target: business.portal.bookingUrl,
},
hasOfferCatalog: {
'@type': 'OfferCatalog',
name: 'Fotografering',
itemListElement: business.genres.map((g) => ({
'@type': 'Offer',
priceCurrency: business.priceFromSek != null ? 'SEK' : null,
price: business.priceFromSek,
itemOffered: {
'@type': 'Service',
name: g.name,
description: g.description,
provider: { '@id': ids.business },
},
})),
},
}, },
]; ];
+2 -60
View File
@@ -1,63 +1,5 @@
// src/data/faq.ts // src/data/faq.ts
// Vanliga frågor för /tjanster. Samma text används på sidan och i FAQPage-JSON-LD. // Typ för vanliga frågor (FAQPage-JSON-LD). Frågorna om bokning, offert och gallerier togs bort 2026-11-06:
// Svaren byggs ENBART av fakta i business.ts. Okända fakta (null) ger ett // Linus erbjuder inga tjänster, bara posters och samarbeten.
// "kontakta mig"-svar i stället för en gissning.
import { business, basedIn, formatSek, genreList } from './business';
export type FaqItem = { question: string; answer: string }; export type FaqItem = { question: string; answer: string };
function areaAnswer(): string {
if (business.serviceArea) {
return `Jag utgår från ${basedIn()} och tar uppdrag i ${business.serviceArea}. Hör av dig om du är osäker på om jag kan komma till dig.`;
}
return `Jag är baserad i ${basedIn()}. Kontakta mig så stämmer vi av om jag kan fotografera där du befinner dig.`;
}
function priceAnswer(): string {
const from = formatSek(business.priceFromSek);
if (from) {
return `En fotografering kostar från ${from}. Det slutliga priset beror på uppdraget och står i offerten du får efter din förfrågan.`;
}
return 'Priset beror på uppdraget. Kontakta mig eller skicka en förfrågan i kundportalen, så får du en offert för just det du vill ha fotograferat.';
}
function deliveryAnswer(): string {
const base = 'Du får bilderna i ett privat galleri i kundportalen. När betalningen är klar kan du ladda ner originalfilerna i full upplösning.';
if (business.deliveryTime) return `${base} Normal leveranstid är ${business.deliveryTime}.`;
return base;
}
export const faq: FaqItem[] = [
{
question: 'Vad fotograferar du?',
answer: `Jag fotograferar ${genreList()}.`,
},
{
question: 'Var finns du och var kan du fotografera?',
answer: areaAnswer(),
},
{
question: 'Vad kostar en fotografering?',
answer: priceAnswer(),
},
{
question: 'Hur bokar jag en fotografering?',
answer: `Skicka en förfrågan i kundportalen (${business.portal.bookingUrl}). Jag återkommer med en offert, och när du har godkänt den bokar vi in fotograferingen.`,
},
{
question: 'Hur får jag mina bilder?',
answer: deliveryAnswer(),
},
{
question: 'Vilken utrustning använder du?',
answer: `Jag fotograferar med en ${business.camera} och redigerar i ${business.editing}.`,
},
{
question: 'Har dina bilder uppmärksammats?',
answer: business.recognition,
},
{
question: 'Hur kontaktar jag dig?',
answer: `Mejla ${business.email} eller skicka ett meddelande på Instagram (${business.social.instagram.handle}).`,
},
];
+1 -2
View File
@@ -13,7 +13,7 @@ export interface Props {
title: string; title: string;
/** Unik svensk meta description, ca 120–160 tecken. */ /** Unik svensk meta description, ca 120–160 tecken. */
description: string; description: string;
/** Kanonisk sökväg, t.ex. "/tjanster". Utelämnas = härleds från URL:en. */ /** Kanonisk sökväg, t.ex. "/portfolio". Utelämnas = härleds från URL:en. */
path?: string; path?: string;
image?: ImageMetadata; image?: ImageMetadata;
imageAlt?: string; imageAlt?: string;
@@ -46,7 +46,6 @@ const ogHeight = Number(og.attributes.height) || undefined;
const nav = [ const nav = [
{ href: '/portfolio', label: 'Portfolio' }, { href: '/portfolio', label: 'Portfolio' },
{ href: '/posters', label: 'Posters' }, { href: '/posters', label: 'Posters' },
{ href: '/tjanster', label: 'Tjänster' },
{ href: '/about', label: 'Om mig' }, { href: '/about', label: 'Om mig' },
{ href: '/contact', label: 'Kontakt' }, { href: '/contact', label: 'Kontakt' },
]; ];
+1 -1
View File
@@ -1,5 +1,5 @@
// src/lib/url.ts // src/lib/url.ts
// Gör om en byggsökväg till kanonisk form: "/", "/about", "/tjanster". // Gör om en byggsökväg till kanonisk form: "/", "/about", "/portfolio".
// Klarar både build.format "file" (/about.html) och "directory" (/about/). // Klarar både build.format "file" (/about.html) och "directory" (/about/).
export function normalizePath(p: string): string { export function normalizePath(p: string): string {
let out = p.replace(/\/index\.html$/, '/').replace(/\.html$/, ''); let out = p.replace(/\/index\.html$/, '/').replace(/\.html$/, '');
+1 -2
View File
@@ -7,14 +7,13 @@ const links = [
{ href: '/', label: 'Startsidan' }, { href: '/', label: 'Startsidan' },
{ href: '/portfolio', label: 'Portfolio' }, { href: '/portfolio', label: 'Portfolio' },
{ href: '/posters', label: 'Posters' }, { href: '/posters', label: 'Posters' },
{ href: '/tjanster', label: 'Tjänster och bokning' },
{ href: '/contact', label: 'Kontakt' }, { href: '/contact', label: 'Kontakt' },
]; ];
--- ---
<MainLayout <MainLayout
title="Sidan hittades inte | Images by Olofsson" title="Sidan hittades inte | Images by Olofsson"
description="Sidan du letade efter finns inte. Gå till startsidan, portfolion eller tjänsterna hos fotograf Linus Olofsson." description="Sidan du letade efter finns inte. Gå till startsidan, portfolion eller posters av fotograf Linus Olofsson."
noindex noindex
> >
<WaveBackground opacity="opacity-60" /> <WaveBackground opacity="opacity-60" />
+12 -16
View File
@@ -8,7 +8,7 @@ import { business, basedIn, genreList } from '../data/business';
<MainLayout <MainLayout
title="Images by Olofsson – fotograf Linus Olofsson i Sverige" title="Images by Olofsson – fotograf Linus Olofsson i Sverige"
description={`Fotograf Linus Olofsson (Images by Olofsson) i ${basedIn()}: porträtt, natur och djur, stad, makro, norrsken och familjefester. Boka via kundportalen.`} description={`Fotograf Linus Olofsson (Images by Olofsson) i ${basedIn()}: porträtt, natur och djur, stad, makro, norrsken och familjefester. Fotografierna finns som posters.`}
path="/" path="/"
> >
@@ -86,16 +86,16 @@ import { business, basedIn, genreList } from '../data/business';
</div> </div>
<div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl"> <div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl">
<h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Vill du boka en fotografering?</h2> <h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Vill du ha en bild på väggen?</h2>
<a href="/tjanster" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105"> <a href="/posters" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105">
Tjänster och bokning Se posters
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<!-- Fakta om vem, vad, var och bokning: läsbar text för besökare, sökmotorer och AI-assistenter. --> <!-- Fakta om vem, vad och var: läsbar text för besökare, sökmotorer och AI-assistenter. -->
<section id="om-images-by-olofsson" class="relative z-30 bg-neutral-900 border-t border-white/10 py-16 md:py-24"> <section id="om-images-by-olofsson" class="relative z-30 bg-neutral-900 border-t border-white/10 py-16 md:py-24">
<div class="container mx-auto px-4 max-w-5xl grid gap-12 md:grid-cols-2"> <div class="container mx-auto px-4 max-w-5xl grid gap-12 md:grid-cols-2">
<div class="space-y-5 text-gray-300 text-lg leading-relaxed"> <div class="space-y-5 text-gray-300 text-lg leading-relaxed">
@@ -116,18 +116,14 @@ import { business, basedIn, genreList } from '../data/business';
</div> </div>
<div class="space-y-5"> <div class="space-y-5">
<h2 class="text-3xl md:text-4xl font-bold text-white">Så bokar du</h2> <h2 class="text-3xl md:text-4xl font-bold text-white">Posters och samarbeten</h2>
<ol class="space-y-4 text-gray-300"> <p class="text-gray-300 text-lg leading-relaxed">
{business.bookingSteps.map((step, i) => ( Fotografierna finns som posters: välj motiv, storlek och material. Vill du skapa något tillsammans,
<li class="flex gap-4"> eller synas genom reklam eller sponsring, hör av dig om ett samarbete.
<span class="shrink-0 w-8 h-8 rounded-full border border-white/30 flex items-center justify-center text-sm font-bold text-white">{i + 1}</span> </p>
<span><strong class="text-white">{step.title}.</strong> {step.text}</span>
</li>
))}
</ol>
<div class="flex flex-wrap gap-4 pt-2"> <div class="flex flex-wrap gap-4 pt-2">
<a href={business.portal.bookingUrl} class="inline-block px-6 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan</a> <a href="/posters" class="inline-block px-6 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Se posters</a>
<a href="/tjanster" class="inline-block px-6 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Vanliga frågor</a> <a href="/contact" class="inline-block px-6 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Samarbeten</a>
</div> </div>
</div> </div>
</div> </div>
+1 -13
View File
@@ -2,15 +2,13 @@
// Byggs från src/data/business.ts så att fakta bara finns på ett ställe. // Byggs från src/data/business.ts så att fakta bara finns på ett ställe.
// Okända fakta (null) skrivs som "lämnas på förfrågan", aldrig som gissningar. // Okända fakta (null) skrivs som "lämnas på förfrågan", aldrig som gissningar.
import type { APIRoute } from 'astro'; import type { APIRoute } from 'astro';
import { business, basedIn, formatSek, genreList } from '../data/business'; import { business, basedIn, genreList } from '../data/business';
import { faq } from '../data/faq';
export const prerender = true; export const prerender = true;
export const GET: APIRoute = ({ site }) => { export const GET: APIRoute = ({ site }) => {
const base = site ?? new URL(business.url); const base = site ?? new URL(business.url);
const url = (p: string) => new URL(p, base).toString(); const url = (p: string) => new URL(p, base).toString();
const price = formatSek(business.priceFromSek);
const lines: (string | null)[] = [ const lines: (string | null)[] = [
`# ${business.brand}`, `# ${business.brand}`,
@@ -22,31 +20,21 @@ export const GET: APIRoute = ({ site }) => {
`- Fotograf: ${business.person.name}`, `- Fotograf: ${business.person.name}`,
`- Namn/varumärke: ${business.brand}`, `- Namn/varumärke: ${business.brand}`,
`- Baserad i: ${basedIn()}`, `- Baserad i: ${basedIn()}`,
business.serviceArea ? `- Tar uppdrag i: ${business.serviceArea}` : '- Upptagningsområde: stäms av vid förfrågan',
price ? `- Pris från: ${price}` : '- Priser: lämnas som offert efter förfrågan',
business.deliveryTime ? `- Leveranstid: ${business.deliveryTime}` : null,
business.phone ? `- Telefon: ${business.phone}` : null, business.phone ? `- Telefon: ${business.phone}` : null,
`- E-post: ${business.email}`, `- E-post: ${business.email}`,
`- Instagram: ${business.social.instagram.handle} (${business.social.instagram.url})`, `- Instagram: ${business.social.instagram.handle} (${business.social.instagram.url})`,
`- Facebook: ${business.social.facebook}`, `- Facebook: ${business.social.facebook}`,
`- Kamera: ${business.camera}`, `- Kamera: ${business.camera}`,
`- Redigering: ${business.editing}`, `- Redigering: ${business.editing}`,
`- Bokning: ${business.portal.bookingUrl}`,
`- Bokningsgång: ${business.bookingSteps.map((s) => s.title.toLowerCase()).join(' → ')}`,
'', '',
'## Sidor', '## Sidor',
'', '',
`- [Startsida](${url('/')}): vem ${business.person.name} är och vad han fotograferar`, `- [Startsida](${url('/')}): vem ${business.person.name} är och vad han fotograferar`,
`- [Tjänster och vanliga frågor](${url('/tjanster')}): vad du kan boka, hur bokningen går till och svar på vanliga frågor`,
`- [Portfolio](${url('/portfolio')}): urval av fotografier`, `- [Portfolio](${url('/portfolio')}): urval av fotografier`,
`- [Om mig](${url('/about')}): ${business.person.name}, bakgrund och utrustning`, `- [Om mig](${url('/about')}): ${business.person.name}, bakgrund och utrustning`,
`- [Posters](${url('/posters')}): fotografier som posters, välj storlek och material`, `- [Posters](${url('/posters')}): fotografier som posters, välj storlek och material`,
`- [Kontakt och samarbeten](${url('/contact')}): samarbeten, reklam och sponsring`, `- [Kontakt och samarbeten](${url('/contact')}): samarbeten, reklam och sponsring`,
'', '',
'## Vanliga frågor',
'',
...faq.map((f) => `- ${f.question} ${f.answer}`),
'',
'## Profiler', '## Profiler',
'', '',
`- [Instagram](${business.social.instagram.url})`, `- [Instagram](${business.social.instagram.url})`,
+1 -1
View File
@@ -131,7 +131,7 @@ const uniqueMonths = [...new Map(allMonths.map(item => [item.name, item])).value
<div class="text-center mb-12"> <div class="text-center mb-12">
<h1 class="text-4xl md:text-6xl font-bold mb-4">Portfolio</h1> <h1 class="text-4xl md:text-6xl font-bold mb-4">Portfolio</h1>
<p class="text-gray-300 max-w-2xl mx-auto">Ett urval av mina bilder i olika stilar – {genreList()}. <p class="text-gray-300 max-w-2xl mx-auto">Ett urval av mina bilder i olika stilar – {genreList()}.
Vill du boka en fotografering? Läs om <a href="/tjanster" class="text-white underline underline-offset-4 hover:text-gray-300">tjänster och bokning</a>.</p> Vill du ha en bild på väggen? Se <a href="/posters" class="text-white underline underline-offset-4 hover:text-gray-300">posters</a>.</p>
</div> </div>
<div class="flex flex-col items-center gap-6 mb-12"> <div class="flex flex-col items-center gap-6 mb-12">
+1 -1
View File
@@ -35,7 +35,7 @@ const link = 'text-white underline hover:text-gray-300';
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Den här webbplatsen</h2> <h2 class="text-2xl font-bold text-white">Den här webbplatsen</h2>
<ul class="list-disc pl-6 space-y-2"> <ul class="list-disc pl-6 space-y-2">
<li>Det finns inga användarkonton och inga kontaktformulär på den här webbplatsen. Bokningar görs i den separata kundportalen.</li> <li>Det finns inga användarkonton och inga kontaktformulär på den här webbplatsen. Beställningar av posters och samarbeten sköts i den separata kundportalen.</li>
<li>Om du mejlar mig används din adress och ditt meddelande bara för att svara dig och delas inte med någon.</li> <li>Om du mejlar mig används din adress och ditt meddelande bara för att svara dig och delas inte med någon.</li>
<li> <li>
Webbplatsen levereras via Cloudflare, som behandlar tekniska uppgifter som din IP-adress för att leverera Webbplatsen levereras via Cloudflare, som behandlar tekniska uppgifter som din IP-adress för att leverera
-127
View File
@@ -1,127 +0,0 @@
---
// src/pages/tjanster.astro
// Vad Linus fotograferar, för vem, var, pris, leverans och hur man bokar + FAQ.
// Allt från src/data/business.ts och src/data/faq.ts – okända fakta visas inte.
import MainLayout from '../layouts/MainLayout.astro';
import WaveBackground from '../components/WaveBackground.astro';
import { business, basedIn, formatSek } from '../data/business';
import { faq } from '../data/faq';
import heroImg from '../assets/images/3d-scroll/img2.jpg';
const priceFrom = formatSek(business.priceFromSek);
const packages = business.packages ?? [];
const portalHost = new URL(business.portal.url).host;
---
<MainLayout
title="Tjänster och bokning – fotografering | Images by Olofsson"
description={`Fotograf Linus Olofsson i ${basedIn()}: porträtt, natur, stad, makro, norrsken och familjefester. Så bokar du via kundportalen, leverans i privat galleri och vanliga frågor.`}
path="/tjanster"
image={heroImg}
imageAlt="Veteranbil med tända strålkastare på en stadsgata i kvällsljus"
breadcrumb="Tjänster"
faq={faq}
>
<WaveBackground opacity="opacity-70" />
<div class="container mx-auto px-4 py-12 md:py-20 relative z-10 max-w-5xl">
<header class="text-center mb-16">
<h1 class="text-4xl md:text-6xl font-bold mb-6">Tjänster och bokning</h1>
<p class="text-gray-300 text-lg md:text-xl leading-relaxed max-w-3xl mx-auto">
Jag heter {business.person.name} och är fotografen bakom {business.brand}, baserad i {basedIn()}.
Här ser du vad jag fotograferar, hur en bokning går till och hur du får dina bilder.
</p>
<div class="flex flex-wrap justify-center gap-4 mt-8">
<a href={business.portal.bookingUrl} class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan</a>
<a href="#vanliga-fragor" class="inline-block px-8 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Vanliga frågor</a>
</div>
</header>
<section aria-labelledby="vad" class="mb-20">
<h2 id="vad" class="text-3xl font-bold text-white mb-8">Det här fotograferar jag</h2>
<ul class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{business.genres.map((g) => (
<li id={g.id} data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 rounded-xl border border-white/10">
<h3 class="text-xl font-bold text-white mb-2">{g.name}</h3>
<p class="text-gray-300">{g.description}</p>
</li>
))}
</ul>
<p class="text-gray-300 mt-6">
Se exempel i min <a href="/portfolio" class="text-white underline underline-offset-4 hover:text-gray-300">portfolio</a>.
Har du något annat i tankarna? Beskriv det i din förfrågan, så återkommer jag med ett förslag.
</p>
</section>
<section aria-labelledby="var-pris" class="mb-20 grid gap-6 md:grid-cols-2">
<div data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 md:p-8 rounded-xl border border-white/10">
<h2 id="var-pris" class="text-2xl font-bold text-white mb-3">Var</h2>
{business.serviceArea ? (
<p class="text-gray-300">Jag utgår från {basedIn()} och tar uppdrag i {business.serviceArea}.</p>
) : (
<p class="text-gray-300">Jag är baserad i {basedIn()}. Kontakta mig så stämmer vi av om jag kan fotografera där du befinner dig.</p>
)}
</div>
<div data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 md:p-8 rounded-xl border border-white/10">
<h2 class="text-2xl font-bold text-white mb-3">Pris</h2>
{priceFrom ? (
<p class="text-gray-300">Fotografering från <strong class="text-white">{priceFrom}</strong>. Det slutliga priset står i offerten.</p>
) : (
<p class="text-gray-300">Priset beror på uppdraget. Kontakta mig eller skicka en förfrågan, så får du en offert för just det du vill ha fotograferat.</p>
)}
{packages.length > 0 && (
<ul class="mt-4 space-y-3">
{packages.map((p) => (
<li class="text-gray-300">
<strong class="text-white">{p.name}</strong>
{formatSek(p.priceSek) && <span> – {formatSek(p.priceSek)}</span>}
{p.includes.length > 0 && <span class="block text-sm text-gray-400">{p.includes.join(', ')}</span>}
</li>
))}
</ul>
)}
</div>
</section>
<section aria-labelledby="boka" class="mb-20">
<h2 id="boka" class="text-3xl font-bold text-white mb-8">Så går en bokning till</h2>
<ol class="space-y-4">
{business.bookingSteps.map((step, i) => (
<li class="flex gap-4 bg-neutral-900/70 backdrop-blur-sm p-5 rounded-xl border border-white/10">
<span class="shrink-0 w-10 h-10 rounded-full border border-white/30 flex items-center justify-center font-bold text-white">{i + 1}</span>
<div>
<h3 class="text-lg font-bold text-white">{step.title}</h3>
<p class="text-gray-300">{step.text}</p>
</div>
</li>
))}
</ol>
<p class="text-gray-300 mt-6">
Leverans: bilderna levereras i ett privat galleri i kundportalen
({portalHost}).{business.deliveryTime && ` Normal leveranstid är ${business.deliveryTime}.`}
</p>
<a href={business.portal.bookingUrl} class="inline-block mt-6 px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan i kundportalen</a>
</section>
<section aria-labelledby="vanliga-fragor" class="mb-12">
<h2 id="vanliga-fragor" class="text-3xl font-bold text-white mb-8">Vanliga frågor</h2>
<div class="space-y-4">
{faq.map((item) => (
<details class="group bg-neutral-900/80 backdrop-blur-sm rounded-xl border border-white/10 p-5 open:border-white/20">
<summary class="cursor-pointer list-none flex justify-between items-center gap-4">
<h3 class="text-lg font-bold text-white">{item.question}</h3>
<span aria-hidden="true" class="text-gray-400 transition-transform group-open:rotate-45 text-2xl leading-none">+</span>
</summary>
<p class="text-gray-300 mt-3">{item.answer}</p>
</details>
))}
</div>
<p class="text-gray-300 mt-8">
Fler frågor? Mejla <a href={`mailto:${business.email}`} class="text-white underline underline-offset-4 hover:text-gray-300">{business.email}</a>
eller skriv på Instagram <a href={business.social.instagram.url} target="_blank" rel="noopener noreferrer" class="text-white underline underline-offset-4 hover:text-gray-300">{business.social.instagram.handle}</a>.
</p>
</section>
</div>
</MainLayout>