-
{{ home.content.intro.heading | escape }} {{ home.content.intro.emphasis | escape }}
-
{{ home.content.intro.lead | escape }}
+
{{ home.content.intro.lead | escape }}
+
{{ home.content.intro.heading | escape }} {{ home.content.intro.emphasis | escape }}
+ {% include "components/magazine-picture.html", image: home.content.intro.image %}
diff --git a/_includes/home/services.html b/_includes/home/services.html
index c2932f2..7bbd093 100644
--- a/_includes/home/services.html
+++ b/_includes/home/services.html
@@ -1,6 +1,6 @@
{% for service in home.content.services.items %}
- {% include "components/service-card.html", service: service %}
+ {% include "components/service-card.html", service: service, number: forloop.index %}
{% endfor %}
diff --git a/_includes/sections/hero.html b/_includes/sections/hero.html
index 0f23f79..46f53ed 100644
--- a/_includes/sections/hero.html
+++ b/_includes/sections/hero.html
@@ -2,7 +2,8 @@
{{ eyebrow }}
{{ heading }}
- {{ lead }}
+ {{ lead }}{% if image %}
+ {% include "components/magazine-picture.html", image: image %}{% endif %}
{% if summary != empty %}
{% if variant == 'ai' %}
{{ summary }}
{% else %}{{ summary }}{% endif %}
{% endif %}
diff --git a/_includes/styles/magazine.scss b/_includes/styles/magazine.scss
new file mode 100644
index 0000000..2c35653
--- /dev/null
+++ b/_includes/styles/magazine.scss
@@ -0,0 +1,178 @@
+/* Verkstadsmagasinet: scoped to the homepage and opted-in section pages.
+ Existing content, navigation and other page families keep their own styles. */
+.magazine-page {
+ --magazine-serif: Georgia, "Times New Roman", serif;
+ --magazine-gap: 28px;
+ font-weight: 400;
+
+ :is(h1, h2, h3):not(.eyebrow) {
+ font-family: var(--magazine-serif);
+ font-weight: 700;
+ letter-spacing: -.035em;
+ text-wrap: pretty;
+ }
+
+ > .page-hero {
+ padding-top: 56px;
+ padding-bottom: 0;
+ }
+
+ > .page-hero > .shell {
+ display: block;
+ }
+
+ .page-hero h1 {
+ max-width: 1150px;
+ font-size: clamp(44px, 5.5vw, 76px);
+ line-height: 1.08;
+ letter-spacing: -.045em;
+ }
+
+ .page-hero h1 span { color: inherit; }
+
+ .page-hero .page-lead {
+ max-width: 930px;
+ padding-left: 0;
+ border: 0;
+ color: var(--ink);
+ font-size: clamp(20px, 2.1vw, 28px);
+ line-height: 1.4;
+ }
+
+ > .page-hero > .shell > .magazine-picture {
+ margin-top: 32px;
+ }
+
+ > .page-hero > .shell > .hero-summary {
+ max-width: 820px;
+ margin-top: 28px;
+ }
+
+ > .page-hero > .shell > .hero-actions {
+ margin-top: 24px;
+ margin-bottom: 24px;
+ }
+
+ .home-service-grid {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: var(--magazine-gap);
+ border: 0;
+ }
+
+ .home-service-grid .service-card {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0;
+ padding: 0 0 24px;
+ border: 0;
+ border-bottom: 1px solid var(--line);
+ }
+
+ .service-card-picture {
+ overflow: hidden;
+ margin-bottom: 22px;
+ background: var(--neutral);
+ }
+
+ .service-card-picture img {
+ width: 100%;
+ aspect-ratio: 1 / 1;
+ object-fit: cover;
+ object-position: 55% center;
+ transition: transform .35s ease;
+ }
+
+ .service-card:is(:hover, :focus-visible) img { transform: scale(1.035); }
+
+ .service-card-number {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ margin-bottom: 12px;
+ color: var(--muted);
+ font-size: var(--text-sm);
+ font-variant-numeric: tabular-nums;
+ }
+
+ .service-card-number::after {
+ content: "";
+ width: 28px;
+ height: 2px;
+ background: var(--orange);
+ }
+
+ .service-card h2 { font-size: clamp(23px, 2vw, 28px); line-height: 1.15; }
+ .service-card p { margin-top: 16px; font-size: var(--text-base); }
+
+ .focus-section > .shell > .section-heading {
+ display: grid;
+ grid-template-columns: 220px minmax(0, 1fr);
+ gap: 40px;
+ margin: 0 0 44px;
+ padding-top: 4px;
+ }
+
+ .focus-section .focus-intro { font-size: var(--text-base); }
+ .focus-label { margin-bottom: 24px; }
+
+ .home-latest { margin-top: 56px; }
+ .home-latest-grid { gap: var(--magazine-gap); }
+ .home-latest-card {
+ grid-template-columns: 110px minmax(0, 1fr);
+ gap: 18px;
+ min-height: 0;
+ border: 0;
+ border-radius: 0;
+ overflow: visible;
+ transition: none;
+ }
+ .home-latest-card:hover { transform: none; }
+ .home-latest-card img { height: 150px; min-height: 0; }
+ .home-latest-card > div { padding: 0; }
+ .home-latest-card h3 { font-size: 21px; line-height: 1.2; hyphens: none; overflow-wrap: anywhere; }
+ .home-latest-card:is(:hover, :focus-visible) h3 {
+ text-decoration: underline;
+ text-decoration-color: var(--orange);
+ text-underline-offset: .2em;
+ }
+ .home-latest-card p { font-size: var(--text-sm); line-height: 1.5; }
+
+ .section-heading h2 { font-size: clamp(30px, 3.4vw, 44px); }
+ .join-grid h2 { font-size: clamp(28px, 3vw, 38px); }
+
+ .focus-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 32px var(--magazine-gap);
+ border: 0;
+ }
+ .focus-grid article {
+ min-height: 0;
+ padding: 24px 0 0;
+ border: 0;
+ border-top: 1px solid var(--line);
+ }
+ .focus-grid h3, .step-grid h3 { font-size: 26px; }
+ .focus-grid p { font-size: var(--text-base); }
+ .step-grid { gap: var(--magazine-gap); }
+ .step-grid article {
+ border-radius: 0;
+ padding: 24px 0 0;
+ border-top: 2px solid var(--orange);
+ background: transparent;
+ }
+ .soft-section, .join-section { background: #f5f4f1; }
+}
+
+.magazine-picture {
+ width: 100%;
+ padding-bottom: 16px;
+ border-bottom: 1px solid var(--orange);
+}
+.magazine-picture img {
+ width: 100%;
+ height: auto;
+ aspect-ratio: 1916 / 700;
+ object-fit: cover;
+ object-position: center 60%;
+}
diff --git a/_includes/styles/responsive.scss b/_includes/styles/responsive.scss
index 17faf27..0db766f 100644
--- a/_includes/styles/responsive.scss
+++ b/_includes/styles/responsive.scss
@@ -60,6 +60,62 @@
.article-shell { padding-top: 45px; }
.back-link { margin-bottom: 45px; }
.article-body iframe { min-height: 260px; }
- .footer-top { grid-template-columns: 1fr; }
- .footer-bottom { gap: 20px; }
+ .site-footer { padding: 32px 0 20px; }
+ .footer-top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 20px; }
+ .footer-top > div:first-child { grid-column: 1 / -1; }
+ .footer-top img { width: 120px; margin-bottom: 0; }
+ .footer-links { min-width: 0; gap: 0; }
+ .footer-links > span { margin-bottom: 8px; }
+ .footer-links a { display: flex; align-items: center; min-height: 44px; overflow-wrap: anywhere; }
+ .footer-links p { margin: 8px 0 0; }
+ .footer-social { grid-column: 1 / -1; width: auto; flex-direction: row; flex-wrap: wrap; gap: 0 24px; }
+ .footer-social > span { flex-basis: 100%; }
+ .footer-social a { justify-content: flex-start; }
+ .footer-bottom { flex-wrap: wrap; gap: 8px 20px; margin-top: 24px; padding-top: 16px; }
+}
+
+/* Editorial pilot: keep image crops and text readable before four columns fit. */
+@media (max-width: 1100px) {
+ .magazine-page .home-service-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+ .magazine-page .service-card-picture img { aspect-ratio: 3 / 2; }
+ .magazine-page .home-latest-grid { grid-template-columns: 1fr; }
+ .magazine-page .home-latest-card { grid-template-columns: 150px minmax(0, 1fr); }
+ .magazine-page .focus-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+}
+
+@media (max-width: 640px) {
+ .magazine-page { --magazine-gap: 24px; }
+ .magazine-page > .page-hero { padding-top: 36px; }
+ .magazine-page .page-hero h1 { font-size: clamp(36px, 9.7vw, 52px); }
+ .magazine-page .page-hero .page-lead { font-size: 20px; }
+ .magazine-page > .page-hero > .shell > .magazine-picture { margin-top: 24px; }
+ .magazine-picture img { aspect-ratio: 3 / 2; object-position: 70% center; }
+ .magazine-page .focus-section > .shell > .section-heading { grid-template-columns: 1fr; gap: 0; margin-bottom: 32px; }
+ .magazine-page .home-service-grid { grid-template-columns: 1fr; }
+ .magazine-page .home-service-grid .service-card {
+ display: grid;
+ grid-template-columns: 112px minmax(0, 1fr);
+ column-gap: 18px;
+ align-items: start;
+ }
+ .magazine-page .service-card-picture { grid-column: 1; grid-row: 1 / 4; margin-bottom: 0; }
+ .magazine-page .service-card-picture img { aspect-ratio: 1 / 1; }
+ .magazine-page .service-card-number, .magazine-page .service-card-heading, .magazine-page .service-card p { grid-column: 2; }
+ .magazine-page .service-card h2 { font-size: 23px; overflow-wrap: anywhere; }
+ .magazine-page .service-card p { font-size: var(--text-sm); margin-top: 12px; }
+ .magazine-page .home-latest { margin-top: 40px; }
+ .magazine-page .home-latest-card { grid-template-columns: 100px minmax(0, 1fr); gap: 16px; }
+ .magazine-page .home-latest-card img { height: 132px; }
+ .magazine-page .home-latest-card h3 { font-size: 21px; }
+ .magazine-page .focus-grid { grid-template-columns: 1fr; }
+ .magazine-page .focus-grid h3, .magazine-page .step-grid h3 { font-size: 25px; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .magazine-page .service-card img { transition: none; }
+ .magazine-page .service-card:is(:hover, :focus-visible) img { transform: none; }
+}
+
+@media print {
+ .magazine-picture, .magazine-page .service-card-picture { display: none; }
}
diff --git a/_layouts/sections.html b/_layouts/sections.html
index fd38800..38fbb3c 100644
--- a/_layouts/sections.html
+++ b/_layouts/sections.html
@@ -1,6 +1,6 @@
---
layout: default
---
-
+
{{ content }}
diff --git a/assets/img/ai-labbet/hero.webp b/assets/img/ai-labbet/hero.webp
new file mode 100644
index 0000000..19eb305
Binary files /dev/null and b/assets/img/ai-labbet/hero.webp differ
diff --git a/assets/img/home-hero.webp b/assets/img/home-hero.webp
new file mode 100644
index 0000000..5baa19d
Binary files /dev/null and b/assets/img/home-hero.webp differ
diff --git a/assets/img/systemutveckling/hero.webp b/assets/img/systemutveckling/hero.webp
new file mode 100644
index 0000000..33450ca
Binary files /dev/null and b/assets/img/systemutveckling/hero.webp differ
diff --git a/assets/img/teknikgranskning/hero.webp b/assets/img/teknikgranskning/hero.webp
new file mode 100644
index 0000000..389002e
Binary files /dev/null and b/assets/img/teknikgranskning/hero.webp differ
diff --git a/assets/site.scss b/assets/site.scss
index c907f65..bb9abc9 100644
--- a/assets/site.scss
+++ b/assets/site.scss
@@ -13,4 +13,5 @@
@use "styles/prism";
@use "styles/footer";
@use "styles/section-spacing";
+@use "styles/magazine";
@use "styles/responsive";
diff --git a/scripts/markdown-sections.mjs b/scripts/markdown-sections.mjs
index 5e7efa1..e35adb8 100644
--- a/scripts/markdown-sections.mjs
+++ b/scripts/markdown-sections.mjs
@@ -108,6 +108,13 @@ export function createSectionRenderer(md, renderTemplate) {
template = 'hero';
Object.assign(data, header(blocks, 'h1'));
if (!data.heading) throw new Error('A hero needs a # heading.');
+ const imageIndex = blocks.findIndex(block => {
+ const tokens = inlineTokens(block);
+ return block[0].type === 'paragraph_open' && tokens.length === 1 && tokens[0].type === 'image';
+ });
+ if (imageIndex !== -1) {
+ data.image = inlineTokens(blocks.splice(imageIndex, 1)[0])[0].attrGet('src');
+ }
data.links = links(blocks);
data.lead = paragraph(blocks.shift(), 'page-lead');
data.summary = variant === 'ai' ? render(blocks) : blocks.map(block => paragraph(block, 'hero-summary')).join('');
diff --git a/scripts/markdown-sections.test.mjs b/scripts/markdown-sections.test.mjs
index bd7f932..ca6df7a 100644
--- a/scripts/markdown-sections.test.mjs
+++ b/scripts/markdown-sections.test.mjs
@@ -58,3 +58,25 @@ test('incorrect block names and variants give clear errors', async () => {
await assert.rejects(render('Text', 'focus', 'stakced'), /Unknown focus variant: stakced/);
await assert.rejects(render('Ingen rubrik', 'hero'), /hero needs a # heading/);
});
+
+test('a standalone hero image keeps the summary and trailing contact links intact', async () => {
+ for (const imageFirst of [true, false]) {
+ const image = '';
+ const link = '[reception@athega.se](mailto:reception@athega.se)';
+ const tail = imageFirst ? `${image}\n\n${link}` : `${link}\n\n${image}`;
+ const html = await render(`Systemutveckling\n\n# En *rubrik*\n\nIngress.\n\nSammanfattning med **betoning**.\n\n${tail}`, 'hero');
+ assert.equal((html.match(/
Sammanfattning med betoning<\/strong>/);
+ assert.match(html, /class="hero-actions"/);
+ assert.match(html, /href="mailto:reception@athega.se" class="text-link"/);
+ assert.ok(html.indexOf('class="magazine-picture"') < html.indexOf('class="hero-summary"'));
+ }
+});
+
+test('an inline hero image remains part of its paragraph', async () => {
+ const html = await render('# Rubrik\n\nIngress.\n\nSe  i sammanhang.', 'hero');
+ assert.doesNotMatch(html, /magazine-picture/);
+ assert.match(html, /class="hero-summary">Se
i sammanhang/);
+});
diff --git a/systemutveckling/index.md b/systemutveckling/index.md
index 1ad53ae..0fb2f82 100644
--- a/systemutveckling/index.md
+++ b/systemutveckling/index.md
@@ -1,5 +1,6 @@
---
layout: sections
+presentation: magazine
title: Systemutveckling
description: >-
Seniora systemutvecklare som hjälper er att utveckla, modernisera och förvalta verksamhetskritiska
@@ -16,6 +17,8 @@ Vi hjälper er att utveckla, modernisera och förvalta system som är viktiga f
Athegas konsulter går in som en del av laget. Vi kombinerar lång erfarenhet med nyfikenhet på bättre verktyg och arbetssätt, men väljer alltid teknik utifrån problemet, människorna och vad som ska fungera över tid.
+
+
[Prata systemutveckling med oss – reception@athega.se](mailto:reception@athega.se?subject=Systemutveckling)
{% endsection %}