/* ─────────────────────────────────────────────────────────────
   TFK — Trelleborgs Företagarklubb
   Global stylesheet and design-system tokens
   ─────────────────────────────────────────────────────────── */

/* ---------- Design tokens ---------- */
:root {
  /* OKLCH colour scaffold — generated by tools/palette/generate.mjs
     (culori). Each token is a locked perceived-lightness + chroma at a
     ramp hue, gamut-mapped by chroma reduction; the brand #1385C4
     (L 0.59 / C 0.133 / H 241) anchors the primary stop, so every colour
     reads as one family. Mirrors lib/presentation/shared/portal_theme.dart.
     See docs/design-system.md for the stop ladder + how to regenerate. */

  /* Brand (hue 241) — primary is ΔOKLCH ~0.0005 from #1385C4 */
  --color-primary:        #1185C4;
  --color-primary-dark:   #006EA5;
  --color-secondary:      #3A94CF;
  --color-accent:         #A8D4F5;
  --color-accent-soft:    #E3F3FF;
  --color-section-bg:     #E0F1FF;
  --color-dark:           #1A2D3E;

  /* Neutrals (hue 245, low chroma — a faint cool tint, not dead grey) */
  --color-bg:             #FFFFFF;
  --color-text:           #1F2C36;
  --color-text-muted:     #5A6A77;
  --color-text-inverse:   #FFFFFF;
  --color-border:         #E1EBF4;

  /* Status (success hue 156, warning 66, error 27 — same L/C ladder) */
  --color-success:        #047D49;
  --color-success-soft:   #E2F7E9;
  --color-warning:        #996019;
  --color-warning-soft:   #FFF0E2;
  --color-error:          #BD423A;
  --color-error-soft:     #FFEDEB;

  /* Neutral "waiting / not done yet" — pending, draft, waitlisted.
     Deliberately not warning: nothing is wrong in those states. */
  --color-notice:         #57626B;
  --color-notice-soft:    #EAEDF1;

  /* Typography */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, "Helvetica Neue", Arial, sans-serif;
  --fw-regular: 400;
  --fw-medium:  500;
  --fw-semibold: 600;
  --fw-bold:    700;

  /* Layout */
  /* 80rem är 1 280 px upp till ett 1 600 px brett fönster. Sedan växer
     ramen med texten (se html nedan), och från ungefär 2 200 px följer
     den fönstret, 62,5 % av bredden: 1 600 px vid 2 560, högst 90rem.
     Med fasta 1 280 px fyllde innehållet halva bredden på en stor skärm. */
  --container-max: clamp(80rem, 62.5vw, 90rem);

  /* Total höjd som den klistrade .site-header upptar: containerns
     min-height plus dess 1 px kantlinje. Allt annat som klistras
     måste offsetta med den här — annars glider det in under
     headern. Ändras höjden ska den ändras här, inte på två ställen. */
  --header-height: 73px;
  --radius-sm:   8px;
  --radius-md:   16px;
  --radius-lg:   24px;
  --radius-pill: 9999px;

  /* Shadows — navy-tinted, two-layer (close contact + ambient lift).
     Deepened from the original near-flat values so cards read as
     elevated surfaces, not outlined rectangles. */
  --shadow-card: 0 1px 3px rgba(22, 45, 62, 0.05),
                 0 10px 28px rgba(22, 45, 62, 0.09);
  --shadow-card-hover: 0 2px 4px rgba(22, 45, 62, 0.07),
                       0 16px 36px rgba(22, 45, 62, 0.13);

  /* Brand gradients — reused on primary CTA button and banner */
  --gradient-primary: linear-gradient(135deg,
                        #006EA5  0%,
                        #1185C4 45%,
                        #3A94CF 100%);
  --gradient-primary-hover: linear-gradient(135deg,
                              #005B89  0%,
                              #006EA5 45%,
                              #117FBB 100%);

  /* Subtle surface gradients — low-contrast, used on large surfaces for
     gentle depth (never flashy). Kept in sync with PortalTokens. */
  /* Raised panels: white → barely-there blue tint (kept very faint). */
  --gradient-surface: linear-gradient(180deg, #FFFFFF 0%, #FAFCFE 100%);
  /* Muted section bands: faint brand wash fading to near-white. */
  --gradient-muted: linear-gradient(180deg, #E8F3FD 0%, #F7FBFE 100%);
  /* Light hero bands (kalender / nyheter): soft diagonal brand wash. */
  --gradient-hero-soft: linear-gradient(160deg,
                          #E7F2FF 0%, #F2F9FE 55%, #FFFFFF 100%);

  /* Rörelse — en mjuk inbromsning utan översving (inga studsar, se
     design-system.md → Motion). Används av allt som glider in. */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* Re-assert the HTML5 `hidden` attribute over any custom display rule
   (e.g. flex / grid). Without this, an element with `display: grid`
   stays visible even when `hidden` is set, which broke the guest
   form's reveal logic. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Texten är 16 px upp till ett 1 600 px brett fönster och växer sedan
     en pixel per 480 px, till 18 px vid 2 560. Allt som mäts i rem växer
     med: rubriker, knapptext, textspalternas bredd och ramen. På en stor
     skärm såg sidan annars ut som en liten sida mitt i mycket luft.
     Procenten utgår från webbläsarens egen textstorlek, så en besökare
     som ställt in större text får fortfarande det. */
  font-size: clamp(100%, calc(100% + (100vw - 1600px) / 480), 112.5%);
  /* Samma orsak som kalenderwidgetens offset: .site-header är klistrad
     och täcker de översta 73 px. Utan detta landar varje hopp till ett
     ankare (#cookies, #personuppgifter, #styrelse …) med rubriken dold
     bakom headern. De 16 px extra ger rubriken luft istället för att
     klistra den mot underkanten. */
  scroll-padding-top: calc(var(--header-height) + 16px);
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: var(--fw-regular);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Sidfoten ska ligga mot fönstrets underkant även när sidan är kort
     (en medlemssida utan beskrivning, gästformulärets startläge) —
     annars slutade den mitt på skärmen med en vit yta under. <main>
     tar upp det som blir över; header och footer behåller sin höjd. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

main { flex: 1 0 auto; }

img, svg { display: block; max-width: 100%; height: auto; }

a {
  color: var(--color-primary);
  text-decoration: none;
  transition: color 0.15s ease;
}
a:hover { color: var(--color-primary-dark); }

h1, h2, h3, h4 {
  margin: 0 0 0.5em;
  font-weight: var(--fw-bold);
  line-height: 1.2;
  color: var(--color-text);
}

p { margin: 0 0 1em; }

ul { list-style: none; margin: 0; padding: 0; }

button { font: inherit; cursor: pointer; border: none; background: none; }

/* ---------- Layout helpers ---------- */
.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 5rem 0;
}

.section-muted {
  background: var(--gradient-muted);
}
/* Två tonade band i rad gav en synlig skarv: det första tonar ut mot
   vitt, nästa börjar om i blått. På startsidan händer det så fort det
   finns nyheter — nyhetsbandet och partnerbandet efter det är båda
   tonade. Följer ett tonat band direkt på ett synligt tonat band blir
   det andra vitt; utan nyheter (dolda) behåller partnerbandet sin ton. */
.section-muted:not([hidden]) + .section-muted {
  background: var(--color-bg);
}

.section-header {
  text-align: center;
  margin-bottom: 48px;
}

.section-header h2 {
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  margin-bottom: 12px;
}

.section-header p {
  color: var(--color-text-muted);
  font-size: 1.05rem;
  max-width: 40rem;
  margin: 0 auto;
}

.eyebrow {
  display: inline-block;
  font-size: 0.78rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: 8px;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 28px;
  border-radius: var(--radius-pill);
  font-weight: var(--fw-semibold);
  font-size: 0.95rem;
  line-height: 1;
  transition: background 0.15s ease, color 0.15s ease,
              border-color 0.15s ease, box-shadow 0.15s ease,
              transform 0.15s ease;
  border: 2px solid transparent;
  white-space: nowrap;
}

.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn-primary {
  position: relative;
  isolation: isolate;
  background: var(--gradient-primary);
  color: var(--color-text-inverse);
  box-shadow: 0 4px 12px rgba(19, 133, 196, 0.28);
}
/* En gradient kan inte övergå i en annan, så hover-tonen bytte på en
   bildruta. Den ligger nu i ett eget lager under texten som tonas in.
   inset: -2px täcker även knappens genomskinliga kant. */
.btn-primary::before {
  content: '';
  position: absolute;
  inset: -2px;
  z-index: -1;
  border-radius: inherit;
  background: var(--gradient-primary-hover);
  opacity: 0;
  transition: opacity 0.15s ease;
}
.btn-primary:hover {
  color: var(--color-text-inverse);
  box-shadow: 0 6px 18px rgba(19, 133, 196, 0.36);
}
.btn-primary:hover::before { opacity: 1; }

.btn-secondary {
  background: rgba(255, 255, 255, 0.16);
  color: var(--color-text-inverse);
  border-color: rgba(255, 255, 255, 0.40);
  backdrop-filter: blur(8px);
}
.btn-secondary:hover {
  background: rgba(255, 255, 255, 0.28);
  color: var(--color-text-inverse);
}

.btn-outline {
  background: transparent;
  color: var(--color-primary);
  border-color: var(--color-primary);
}
.btn-outline:hover {
  background: var(--color-primary);
  color: var(--color-text-inverse);
}

.btn-ghost-light {
  background: transparent;
  color: var(--color-text-inverse);
  border-color: rgba(255, 255, 255, 0.70);
}
.btn-ghost-light:hover {
  background: rgba(255, 255, 255, 0.14);
  color: var(--color-text-inverse);
}

.btn-white {
  background: var(--color-bg);
  color: var(--color-primary);
}
.btn-white:hover {
  background: #F3F8FC;
  color: var(--color-primary-dark);
}

/* ---------- Header / navigation ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--color-border);
  transition: box-shadow 0.2s ease;
}
/* När sidan scrollats (main.js) lyfter headern med en svag skugga, så
   det syns att innehållet glider in under den. */
.site-header.is-scrolled {
  box-shadow: 0 6px 24px rgba(22, 45, 62, 0.07);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  /* = var(--header-height) minus den 1 px kantlinje som ligger på
     .site-header själv. Håll dem ihop via tokenen. */
  min-height: calc(var(--header-height) - 1px);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.brand img { width: 56px; height: 56px; object-fit: contain; }
.brand-footer img,
.brand-footer .brand-fallback { width: 96px; height: 96px; }
.brand-fallback {
  width: 56px; height: 56px;
  border-radius: 10px;
  background: var(--color-primary);
  color: var(--color-text-inverse);
  display: grid; place-items: center;
  font-weight: var(--fw-bold);
  font-size: 0.9rem;
  letter-spacing: 0.06em;
}

.primary-nav {
  display: flex;
  align-items: center;
  /* Raden rymmer åtta länkar (578 px), logga (56), knappen Logga in
     (123), två mellanrum i containern och dess utfyllnad — 852 px plus
     sju länkmellanrum. Med fasta 28 px gick det inte ihop under ca
     1 050 px: "Bli medlem" och "Om TFK" bröts på två rader, även på en
     liggande iPad. Mellanrummet krymper nu med fönstret, (100vw − 880)/7,
     så raden alltid har ~28 px till godo, och under 960 px tar
     menyknappen över (se media-frågan längre ned). */
  gap: clamp(12px, calc((100vw - 880px) / 7), 28px);
}

.primary-nav a {
  color: var(--color-text);
  font-weight: var(--fw-medium);
  font-size: 0.95rem;
  padding: 8px 0;
  position: relative;
}
.primary-nav a[aria-current="page"] {
  color: var(--color-primary);
}
.primary-nav a:hover { color: var(--color-primary); }
/* En linje som växer in från vänster vid hover och står kvar under den
   aktuella sidan — färgen ensam var en svag markering. Döljs i
   mobilpanelen, där raderna redan har skiljelinjer. */
.primary-nav a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 3px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.2s var(--ease-out);
}
.primary-nav a:hover::after,
.primary-nav a[aria-current="page"]::after {
  transform: scaleX(1);
}

.header-cta {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  border-radius: 10px;
  align-items: center;
  justify-content: center;
  color: var(--color-text);
  transition: background 0.15s ease;
}
/* Tonad när menyn är öppen. Hover bara där det finns en pekare — på en
   pekskärm fastnar :hover efter trycket och knappen såg öppen ut även
   när menyn stängts. */
.site-header[data-nav-open="true"] .nav-toggle { background: var(--color-accent-soft); }
@media (hover: hover) {
  .nav-toggle:hover { background: var(--color-accent-soft); }
}
/* De tre strecken blir ett kryss när menyn är öppen. fill-box gör att
   varje streck vrids kring sin egen mitt. */
.nav-toggle line {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.2s var(--ease-out), opacity 0.15s ease;
}
.site-header[data-nav-open="true"] .nav-toggle line:nth-child(1) {
  transform: translateY(5px) rotate(45deg);
}
.site-header[data-nav-open="true"] .nav-toggle line:nth-child(2) {
  opacity: 0;
}
.site-header[data-nav-open="true"] .nav-toggle line:nth-child(3) {
  transform: translateY(-5px) rotate(-45deg);
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  /* Växer med bredden på stora skärmar, högst 82 % av fönstrets höjd.
     Bilden är 3:2 och täcker rutan, så en låg ruta i ett brett fönster
     visar bara en smal remsa av den: vid 2 560 px var den 680 px hög,
     och drakens huvud föll utanför. */
  min-height: clamp(640px, 40vw, 82vh);
  color: var(--color-text-inverse);
  background-color: #0C2638;
  /* Hero image: vattentornet + dragon sculpture in morning mist.
     Tower sits left-of-centre, dragon silhouette right-of-centre,
     mist-lit sky at top. Gradient darkens the left where hero copy
     lives, fades to near-transparent on the right so the dragon
     reads clean. Bilden är förankrad 20 % uppifrån, inte i mitten:
     huvudet sitter i bildens övre femtedel, och det som skärs bort
     när rutan är bredare än bilden ska vara drakens nedre del. */
  background-image:
    linear-gradient(90deg,
      rgba(10, 28, 46, 0.78) 0%,
      rgba(10, 28, 46, 0.45) 40%,
      rgba(10, 28, 46, 0.08) 75%,
      rgba(10, 28, 46, 0) 100%),
    url("../images/trelleborg-drake.jpg");
  background-position: center, 50% 20%;
  background-size: cover, cover;
  background-repeat: no-repeat, no-repeat;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.hero .container {
  position: relative;
  z-index: 1;
  padding-top: 72px;
  padding-bottom: 72px;
}

.hero-content { max-width: 45rem; }

.hero h1 {
  font-size: clamp(2.25rem, 5vw, 3.75rem);
  line-height: 1.08;
  color: var(--color-text-inverse);
  margin-bottom: 20px;
}
.hero h1 .accent { color: var(--color-accent); }

.hero-lead {
  font-size: 1.05rem;
  color: rgba(255, 255, 255, 0.92);
  max-width: 35rem;
  margin-bottom: 32px;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 40px;
}

.hero-stat {
  display: inline-flex;
  flex-direction: column;
  padding: 18px 24px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.30);
  backdrop-filter: blur(14px);
  border-radius: var(--radius-md);
}
.hero-stat .num {
  font-size: 1.75rem;
  font-weight: var(--fw-bold);
  color: var(--color-accent);
  line-height: 1.1;
}
.hero-stat .lbl {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.88);
  margin-top: 4px;
}

/* ---------- Medlemskap: det här får du som medlem ----------
   Tre spalter — Träffas, Synas, Påverka — som var och en slutar i en
   länk dit förmånen finns. Ersatte tre värdekort med ikonrutor och
   allmänna formuleringar, som lyfte vid hover men inte ledde någonstans.
   Inga kortramar: en tunn linje ovanför bär strukturen, och bara
   länken reagerar på hover. */
.benefits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 48px;
}

.benefit {
  display: flex;
  flex-direction: column;
  padding-top: 24px;
  border-top: 2px solid var(--color-accent);
}

/* Samma uppsättning som .eyebrow, ett steg mindre luft under. */
.benefit-kicker {
  font-size: 0.78rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: 8px;
}

.benefit h3 {
  font-size: 1.25rem;
  margin: 0 0 10px;
}

.benefit p {
  color: var(--color-text-muted);
  margin: 0 0 18px;
}

/* Länkarna i linje i alla tre spalterna, oavsett textens längd, och
   bara så breda som sin text (annars sträcks de över hela spalten). */
.benefit-link {
  margin-top: auto;
  align-self: flex-start;
}

@media (max-width: 768px) {
  .benefits {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

/* ---------- Roots (Trelleborg imagery) ---------- */
.roots-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

/* Fotona är inga länkar, så de lyfter inte som ett klickbart kort — i
   stället zoomar bilden sakta inom ramen medan fotografens namn glider
   fram (se Image credit captions). */
.roots-photo {
  position: relative;
  margin: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  aspect-ratio: 3 / 2;
  transition: box-shadow 0.25s ease;
}

.roots-photo:hover {
  box-shadow: var(--shadow-card-hover);
}

.roots-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.7s var(--ease-out);
}
.roots-photo:hover img { transform: scale(1.04); }

/* ---------- Events section ---------- */
.events-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 40px;
  flex-wrap: wrap;
}
.events-title h2 {
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  margin: 0;
}
.events-link,
.benefit-link {
  font-weight: var(--fw-semibold);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.events-link svg,
.benefit-link svg { transition: transform 0.2s var(--ease-out); }
.events-link:hover svg,
.benefit-link:hover svg { transform: translateX(3px); }

.events-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 24px;
}

.event-card {
  position: relative;
  display: grid;
  grid-template-columns: 40% 1fr;
  background: var(--color-bg);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.event-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-card-hover);
}

/* Hela kortet är klickbart. Kortet lyfte vid hover men bara knappen var
   en länk; nu täcker rubriklänkens ::after kortet (samma mönster som
   partnerkorten) och knappen ligger ovanpå som en egen länk till samma
   sida, med sin tydligare text. */
.event-card-link { color: inherit; }
.event-card-link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
}
.event-card:hover .event-card-link { color: var(--color-primary-dark); }
.event-card .btn {
  position: relative;
  z-index: 1;
}

.event-image {
  position: relative;
  overflow: hidden;
  background: #D5E4EF center / cover no-repeat;
  min-height: 240px;
}
/* Bilden zoomar sakta in när kortet hovras. Bakgrunden ärvs till ett
   eget lager som skalas inom rutan — själva rutan växer inte ut i
   kortet. */
.event-image::before {
  content: '';
  position: absolute;
  inset: 0;
  background: inherit;
  transition: transform 0.6s var(--ease-out);
}
.event-card:hover .event-image::before { transform: scale(1.04); }

.event-body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.event-tag {
  align-self: flex-start;
  display: inline-block;
  padding: 4px 12px;
  background: var(--color-accent);
  color: var(--color-primary-dark);
  font-size: 0.72rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.1em;
  border-radius: var(--radius-pill);
  text-transform: uppercase;
}

.event-card h3 {
  font-size: 1.2rem;
  margin: 4px 0;
  line-height: 1.3;
}

.event-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--color-text-muted);
  font-size: 0.92rem;
  margin: 0;
}
.event-meta svg { width: 16px; height: 16px; flex-shrink: 0; }

.event-card .btn {
  margin-top: auto;
  align-self: stretch;
}

/* Truncated description on the card — snippet of free-form text from
   the admin event editor. Slightly muted so the title + date stay the
   primary visual hierarchy. Capped at 3 lines via -webkit-line-clamp
   as a belt-and-braces alongside the JS char-truncation, so a very
   long no-space string can't bust the card layout. */
.event-description {
  margin: 4px 0 0;
  color: var(--color-text-muted);
  font-size: 0.92rem;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Members-only variant — neutral palette so the audience signal reads
   as "informational" rather than "primary CTA". The accent-coloured
   default tag is for the open-to-guests case which is what we want to
   visually surface. */
.event-tag-muted {
  background: var(--color-section-bg);
  color: var(--color-text-muted);
}

/* Rutan för evenemang och nyheter utan bild: samma varumärkesgradient som
   inloggningssidan, och datumet stort i mitten (events.js, news.js) så att
   rutan bär information i stället för att stå tom. Båda evenemangen på
   prod saknade bild när det här kom till (2026-10-01). Portalen ritar
   samma ruta (TfkEventDateCover, PortalTokens.coverPlaceholderGradient)
   — ändras den ena, ändra den andra. */
.event-image-placeholder {
  display: grid;
  place-items: center;
  background: linear-gradient(135deg,
    var(--color-accent-soft) 0%,
    var(--color-accent) 100%);
}
/* Månad överst, dagen stort under — som ett kalenderblad, men direkt på
   tonen i stället för ett kort i kortet. Året bara när det inte är i år.
   Mot gradientens mitt ger dagen i primary-dark 4,2:1 (stor text, krav
   3:1) och etiketten i textfärg 10:1. position: relative lägger datumet
   över zoomlagret (.event-image::before). */
.event-date {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 4px;
}
.event-date-month {
  font-size: 0.8rem;
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-text);
}
.event-date-day {
  font-size: 4rem;
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--color-primary-dark);
}

/* ---------- /kalender — calendar page states ---------- */

.calendar-hero {
  padding: 64px 0 40px;
  background: var(--gradient-hero-soft);
}
.calendar-hero h1 {
  font-size: clamp(2rem, 4vw, 2.75rem);
  margin: 8px 0 16px;
}
.calendar-hero p {
  max-width: 45rem;
  color: var(--color-text-muted);
  margin: 0;
  line-height: 1.6;
}

/* Two-column layout: month calendar on the left rail, events list on
   the right. Collapses to single column under 880px (calendar stacks
   above the list). */
.calendar-layout {
  display: grid;
  grid-template-columns: minmax(280px, 320px) 1fr;
  gap: 40px;
  align-items: start;
}
@media (max-width: 880px) {
  .calendar-layout {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  /* Staplat kommer evenemangen först: med månadskalendern överst började
     första evenemanget under skärmkanten på en mobil (964 px ned), och
     kalendern visar mest tomma dagar — ett tiotal träffar om året. Den
     följer nu under listan; väljer man en dag där scrollar events.js
     upp till listan, som är den som ändras. */
  .calendar-layout > .events-list { order: -1; }
}

/* Force single-column events grid on /kalender — auto-fit would put
   two cards side-by-side at >760px right-column widths, which reads
   cramped next to the calendar. One card per row keeps the
   description snippet readable. */
.events-grid-stacked {
  grid-template-columns: 1fr;
}
/* I den breda staplade listan blev en knapp i full bredd en 500–700 px
   lång pill som dominerade kortet. Här får den sin naturliga bredd; på
   startsidans smalare kort, och i mobilens enkolumn, fyller den raden. */
@media (min-width: 769px) {
  .events-grid-stacked .event-card .btn { align-self: flex-start; }
}

/* ── Listverktyg: sök, filter, räknare, fler, inga träffar ──
   Delas av /medlemmar och /nyheter, så att de två listorna beter sig och
   ser likadana ut. Sökfältet och filtret står sida vid sida på bred skärm
   och under varandra i mobilen. */
.list-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
}
.list-search {
  flex: 1 1 280px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  background: var(--color-bg);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition: border-color 120ms ease;
}
.list-search:focus-within { border-color: var(--color-primary); }
.list-search svg { color: var(--color-text-muted); flex: none; }
.list-search input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  padding: 13px 0;
  font-size: 1rem;
  font-family: inherit;
  color: var(--color-text);
  min-width: 0;
}
.list-search-clear {
  border: none; background: none; cursor: pointer;
  color: var(--color-text-muted); padding: 4px; display: inline-flex;
  border-radius: 999px;
}
.list-search-clear:hover { color: var(--color-text); }
.list-filter-wrap { flex: 0 1 240px; display: flex; }
.list-filter {
  flex: 1;
  appearance: none;
  -webkit-appearance: none;
  padding: 13px 40px 13px 16px;
  font-size: 1rem;
  font-family: inherit;
  color: var(--color-text);
  background-color: var(--color-bg);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235A6A77' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
.list-filter:focus { outline: none; border-color: var(--color-primary); }
/* När verktygsraden bryts hamnade filtret ensamt på sin rad, 240 px
   brett under ett sökfält i full bredd. */
@media (max-width: 640px) {
  .list-filter-wrap { flex-basis: 100%; }
}
.list-count {
  font-size: 0.9rem;
  color: var(--color-text-muted);
  margin: 0 0 24px;
}
.list-count-skeleton { width: 180px; height: 14px; margin: 4px 0 28px; }
.list-empty {
  text-align: center;
  padding: 56px 20px;
}
.list-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 72px; height: 72px;
  border-radius: 999px;
  background: var(--color-accent-soft);
  color: var(--color-primary);
  margin-bottom: 16px;
}
.list-empty h2 {
  font-size: 1.3rem;
  color: var(--color-text);
  margin: 0 0 8px;
}
.list-empty p {
  color: var(--color-text-muted);
  margin: 0 auto;
  max-width: 26.25rem;
}
.list-empty .btn { margin-top: 20px; }
.list-more {
  display: flex;
  justify-content: center;
  margin-top: 28px;
}
.list-more-btn {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-primary);
  background: var(--color-bg);
  border: 1.5px solid var(--color-primary);
  border-radius: var(--radius-pill, 999px);
  padding: 12px 30px;
  transition: background 120ms ease, color 120ms ease;
}
.list-more-btn:hover { background: var(--color-primary); color: #fff; }

/* ── Nyhetslistan ──
   Den senaste nyheten stort överst (det breda evenemangskortet), sedan
   ett rutnät med tre kort i bredd, två på surfplatta och ett i mobilen.
   Typknapparna filtrerar på vad rubriken säger att nyheten är. */
.news-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 16px;
}
.news-type {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  padding: 7px 14px;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--color-accent-soft);
  color: var(--color-primary-dark);
  transition: background 120ms ease, color 120ms ease;
}
.news-type:not([aria-pressed="true"]):hover { background: var(--color-accent); }
/* primary-dark, inte primary: vit text på primary är 4,1:1, under kravet
   4,5:1 för text i den här storleken. */
.news-type[aria-pressed="true"] { background: var(--color-primary-dark); color: var(--color-text-inverse); }
.news-type-count { margin-left: 6px; font-weight: 500; opacity: 0.8; }
.news-feature { margin-bottom: 32px; grid-template-columns: 55% 1fr; }
.news-feature .event-image { min-height: 340px; }
.news-feature h3 { font-size: 1.6rem; }
@media (min-width: 769px) {
  .news-feature .btn { align-self: flex-start; }
}
@media (max-width: 768px) {
  .news-feature { grid-template-columns: 1fr; }
  .news-feature .event-image { min-height: 0; aspect-ratio: 16 / 9; }
}
.news-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
@media (max-width: 960px) {
  .news-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .news-grid { grid-template-columns: minmax(0, 1fr); }
}
/* Samma kort som evenemangen men stående: bilden överst, och hela kortet
   klickbart genom rubriklänkens ::after. Skuggan djupnar vid hover i
   stället för att kortet lyfter. */
.news-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: box-shadow 0.2s ease;
}
.news-card:hover { box-shadow: var(--shadow-card-hover); }
.news-card:hover .event-image::before { transform: scale(1.04); }
.news-card .event-image { aspect-ratio: 16 / 9; min-height: 0; }
.news-card-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  padding: 18px 20px 20px;
}
.news-card-date { margin: 0; font-size: 0.85rem; color: var(--color-text-muted); }
.news-card h3 { margin: 0; font-size: 1.1rem; line-height: 1.3; }
.news-card-link { color: inherit; transition: color 0.15s ease; }
.news-card-link::after { content: ''; position: absolute; inset: 0; }
.news-card:hover .news-card-link { color: var(--color-primary-dark); }
.news-card-excerpt {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.news-card-more {
  margin-top: auto;
  padding-top: 6px;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-primary);
}
.news-card-skeleton { pointer-events: none; }
.news-card-skeleton .event-image { border-radius: 0; }

/* ── Calendar widget ── */

.calendar-widget {
  background: var(--color-bg);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
  padding: 20px;
  position: sticky;
  /* Klistra under headern, inte bakom den. Med enbart `top: 24px`
     hamnade widgetens överkant 49 px in under den klistrade headern,
     så månadsrubriken och månadspilarna täcktes vid scroll. */
  top: calc(var(--header-height) + 24px);
}
@media (max-width: 880px) {
  .calendar-widget {
    position: static;
  }
}

.cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 16px;
}
.cal-month-label {
  margin: 0;
  font-size: 1.1rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text);
  text-align: center;
  flex: 1;
}
.cal-nav {
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.cal-nav:hover {
  background: var(--color-accent-soft);
  color: var(--color-primary-dark);
  border-color: var(--color-accent);
}
.cal-nav:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  margin-bottom: 6px;
}
.cal-weekdays span {
  text-align: center;
  font-size: 0.72rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-muted);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 4px 0;
}

.cal-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.cal-day {
  aspect-ratio: 1;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 0.9rem;
  color: var(--color-text);
  cursor: pointer;
  display: grid;
  place-items: center;
  position: relative;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.cal-day-empty {
  cursor: default;
  pointer-events: none;
}
.cal-day:disabled {
  color: var(--color-text-muted);
  cursor: default;
  opacity: 0.45;
}
.cal-day-has-event {
  color: var(--color-primary-dark);
  font-weight: var(--fw-semibold);
}
/* Indicator dot under the day number when an event falls on that
   date. Sits below the digit so it doesn't compete visually. */
.cal-day-has-event::after {
  content: '';
  position: absolute;
  bottom: 5px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-primary);
}
.cal-day-has-event:not(:disabled):hover {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
}
.cal-day-today:not(.cal-day-selected) {
  border-color: var(--color-primary);
}
.cal-day-selected {
  background: var(--color-primary);
  color: var(--color-text-inverse);
  font-weight: var(--fw-bold);
}
.cal-day-selected::after {
  background: var(--color-text-inverse);
}
.cal-day:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Månaden ritas direkt (events.js); tills evenemangen är hämtade pulserar
   dagarna som ett skelett, i stället för en tom ruta och "…" som rubrik. */
.calendar-widget[aria-busy="true"] .cal-days {
  animation: tfk-skeleton-pulse 1.6s ease-in-out infinite;
}

.cal-legend {
  margin: 16px 0 0;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}
.cal-legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
  display: inline-block;
}

.cal-clear {
  margin-top: 12px;
  width: 100%;
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font: inherit;
  font-size: 0.9rem;
  font-weight: var(--fw-medium);
  color: var(--color-primary-dark);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.cal-clear:hover {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
}

/* Staplat (≤ 880 px) går kalendern över hela bredden, och kvadratiska
   dagrutor blev 48 px höga på en mobil och över 100 px på en surfplatta.
   Låga rutor och lite tätare kanter: 373 px i stället för 430 på en
   mobil. Står efter grundreglerna ovan så att de vinner. */
@media (max-width: 880px) {
  .calendar-widget { padding: 14px 16px; }
  .cal-header { margin-bottom: 8px; }
  .cal-day { aspect-ratio: auto; height: 38px; }
  .cal-legend { margin-top: 8px; }
}

/* ── Filter banner above the events list ── */

.events-filter-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 16px;
  margin-bottom: 20px;
  background: var(--color-accent-soft);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-sm);
}
.events-filter-eyebrow {
  display: block;
  font-size: 0.72rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-primary-dark);
  margin-bottom: 2px;
}
.events-filter-banner strong {
  color: var(--color-text);
  font-size: 0.95rem;
  font-weight: var(--fw-semibold);
}
.events-filter-clear {
  background: transparent;
  border: none;
  color: var(--color-primary-dark);
  font: inherit;
  font-size: 0.9rem;
  font-weight: var(--fw-semibold);
  cursor: pointer;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
}
.events-filter-clear:hover {
  background: var(--color-bg);
}

/* Laddningsläget på /kalender och /nyheter: två skelettkort i listans
   form (se Laddningsskelett längre ned) i stället för en spinner. */
.events-loading {
  display: grid;
  gap: 24px;
}

.events-empty,
.events-error {
  display: grid;
  justify-items: start;
  gap: 14px;
  padding: 40px 0;
  max-width: 40rem;
}
.events-empty h2,
.events-error h2 {
  font-size: 1.5rem;
  margin: 0;
}
.events-empty p,
.events-error p {
  margin: 0;
  color: var(--color-text-muted);
  line-height: 1.55;
}

/* ---------- Homepage events fallbacks ---------- */

/* Före hämtningen står två skelettkort i rutnätet (index.html); de håller
   sektionens höjd så sidan nedanför inte hoppar när korten kommer, och
   events.js ersätter dem med replaceChildren. */

.events-homepage-empty {
  grid-column: 1 / -1;
  display: grid;
  justify-items: start;
  gap: 14px;
  padding: 32px;
  background: var(--color-accent-soft);
  border-radius: var(--radius-md);
}
.events-homepage-empty p {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 1rem;
}

/* ---------- Partners marquee ----------
   Doubled track translates by exactly -50% to seamlessly loop.
   Per-item margin-right (rather than flex `gap`) keeps the rhythm
   identical at the wrap-around point — with `gap`, the missing
   trailing space before item 1 produces a visible jolt at -50%. */
.partners-marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right,
    transparent 0%, #000 8%, #000 92%, transparent 100%);
          mask-image: linear-gradient(to right,
    transparent 0%, #000 8%, #000 92%, transparent 100%);
}
.partners-track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  width: max-content;
  animation: partners-marquee-scroll 60s linear infinite;
  will-change: transform;
}
.partners-marquee:hover .partners-track,
.partners-marquee:focus-within .partners-track {
  animation-play-state: paused;
}
.partner-logo {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 80px;
  margin-right: 96px;
}
.partner-logo img {
  height: 56px;
  width: auto;
  flex: 0 0 auto;
  display: block;
}
/* Logotyperna är länkar till partnerns sida (sedan PR #106). Bandet
   stannar vid hover; den logotyp pekaren står på växer lite. */
.partner-logo a {
  display: block;
  transition: transform 0.2s var(--ease-out);
}
.partner-logo a:hover { transform: scale(1.06); }
@keyframes partners-marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .partners-track {
    animation: none !important;
    transform: none !important;
  }
}

/* ---------- CTA banner ---------- */
.cta-banner-wrap { padding: 40px 0 96px; }
.cta-banner {
  position: relative;
  border-radius: var(--radius-lg);
  padding: 72px 32px;
  text-align: center;
  color: var(--color-text-inverse);
  /* Soft top-left light glow layered over the brand gradient for a bit
     of dimensionality — sits behind the text (background layer). */
  background:
    radial-gradient(120% 130% at 16% 8%,
      rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0) 55%),
    var(--gradient-primary);
  box-shadow: 0 18px 44px rgba(19, 133, 196, 0.30);
  overflow: hidden;
}
.cta-banner h2 {
  color: var(--color-text-inverse);
  font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  max-width: 45rem;
  margin: 0 auto 16px;
}
.cta-banner p {
  max-width: 35rem;
  margin: 0 auto 32px;
  color: rgba(255, 255, 255, 0.92);
}
.cta-actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
}

/* ---------- Footer ---------- */
.site-footer {
  background: var(--color-dark);
  color: rgba(255, 255, 255, 0.82);
  padding: 64px 0 24px;
}

.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 40px;
  margin-bottom: 40px;
}

.footer-brand { max-width: 23.75rem; }
.footer-brand .brand { margin-bottom: 16px; }
.footer-brand p {
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.92rem;
  margin: 0;
}

.footer-col h4 {
  color: var(--color-text-inverse);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.footer-col ul li { margin-bottom: 10px; }
.footer-col a {
  color: rgba(255, 255, 255, 0.78);
  font-size: 0.95rem;
}
.footer-col a:hover { color: var(--color-text-inverse); }

.social-links {
  display: inline-flex;
  gap: 12px;
}
.social-links a {
  width: 40px; height: 40px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.10);
  display: grid; place-items: center;
  color: var(--color-text-inverse);
  transition: background 0.15s ease;
}
.social-links a:hover { background: rgba(255, 255, 255, 0.20); }
.social-links svg { width: 18px; height: 18px; }

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.10);
  padding-top: 20px;
  text-align: center;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.56);
}

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }

  /* Menyknappen tar över vid samma steg som portalens sidomeny
     (breakpointXl). Tidigare först vid 768 px, vilket lämnade
     769–1 050 px med en meny som bröts på två rader. */
  .nav-toggle { display: inline-flex; }

  .primary-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 12px 24px 20px;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    box-shadow: 0 12px 32px rgba(16, 42, 67, 0.08);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
  }
  .primary-nav a {
    padding: 12px 0;
    border-bottom: 1px solid var(--color-border);
  }
  .primary-nav a:last-child { border-bottom: none; }
  .primary-nav a::after { display: none; }

  .site-header[data-nav-open="true"] .primary-nav {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
}

@media (max-width: 768px) {
  .section { padding: 56px 0; }
  .cta-banner-wrap { padding: 24px 0 64px; }
  .cta-banner { padding: 56px 20px; }

  .event-card { grid-template-columns: 1fr; }
  .event-image { min-height: 180px; }

  .hero { min-height: 540px; }
}

@media (max-width: 480px) {
  .container { padding: 0 18px; }
  /* Menypanelens länkar i linje med loggan, som följer containerns 18 px. */
  .primary-nav { padding-left: 18px; padding-right: 18px; }
  .hero-actions .btn { flex: 1 1 auto; }
  .header-cta .btn { padding: 10px 18px; font-size: 0.9rem; }
  .brand img, .brand-fallback { width: 44px; height: 44px; }
  .brand-footer img, .brand-footer .brand-fallback { width: 72px; height: 72px; }
  .footer-grid { grid-template-columns: 1fr; }
}

/* ---------- Accessibility ---------- */
:focus-visible {
  outline: 3px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    /* En oändlig animation på 0,01 ms flimrar i stället för att stå
       still — spinnrar och laddningsskelett står stilla med en körning. */
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
}

/* ---------- Rörelse ----------
   Tre sorters rörelse, alla korta och utan studs (--ease-out):
     1. Hjälten på startsidan glider upp när sidan laddas.
     2. Innehåll under skärmkanten glider upp när det når synfältet
        (main.js lägger .reveal och .is-revealed; sidornas skript gör
        samma sak med kort de hämtat).
     3. Lägespaneler — tomt, fel, klart, filter — tonar in när de visas.
   Med "reducera rörelse" står allt stilla: main.js döljer inget, och
   återställningen ovan kortar resten till ingenting. */
@keyframes tfk-rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
@keyframes tfk-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* 1. Rubrik, ingress, knappar, siffran — 80 ms isär, klart efter 0,9 s. */
.hero-content > * {
  animation: tfk-rise 700ms var(--ease-out) backwards;
}
.hero-content > :nth-child(2) { animation-delay: 80ms; }
.hero-content > :nth-child(3) { animation-delay: 160ms; }
.hero-content > :nth-child(4) { animation-delay: 240ms; }

/* 2. `backwards` håller startläget under fördröjningen men släpper
   efteråt, så elementets egna transform (t.ex. kortens hover-lyft)
   gäller som vanligt när animationen är klar. */
.reveal { opacity: 0; }
.reveal.is-revealed {
  opacity: 1;
  animation: tfk-rise 600ms var(--ease-out) backwards;
  animation-delay: var(--reveal-delay, 0ms);
}
@media print {
  .reveal { opacity: 1 !important; animation: none !important; }
}

/* 3. En animation startar om när elementet går från display: none till
   synligt — hidden-attributet räcker som utlösare. */
.events-empty,
.events-error,
.events-filter-banner,
.events-homepage-empty,
.members-empty,
.members-error,
.partners-empty,
.partners-error,
.guest-form-success,
.guest-form-notice,
.guest-form-waitlist-offer,
.guest-form-summary-error,
.apply-form-success,
.apply-form-summary-error {
  animation: tfk-fade-in 300ms var(--ease-out);
}
.field-error { animation: tfk-fade-in 180ms var(--ease-out); }

/* ---------- Laddningsskelett ----------
   Listorna hämtas från Cloud Functions, och en kallstart tar 3–4 s. Under
   tiden visas kortens form i stället för en rad text, så sidan inte hoppar
   när innehållet kommer. Skelettet är aria-hidden; skärmläsare får den
   dolda "Laddar …"-texten i samma role="status". */
@keyframes tfk-skeleton-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
.skeleton {
  display: block;
  background: var(--color-border);
  border-radius: 6px;
  animation: tfk-skeleton-pulse 1.6s ease-in-out infinite;
}
.skeleton-tag    { width: 112px; height: 22px; border-radius: var(--radius-pill); }
.skeleton-title  { width: 70%; height: 18px; }
.skeleton-text   { width: 92%; height: 12px; }
.skeleton-short  { width: 55%; }
.skeleton-button { height: 46px; margin-top: auto; border-radius: var(--radius-pill); }

.event-card-skeleton,
.partner-card-skeleton { pointer-events: none; }
.event-card-skeleton .event-image { border-radius: 0; }
.partner-card-skeleton .skeleton-logo { width: 55%; height: 56px; }

/* ---------- Guest CTA panel (lives inside the events section) ---------- */
.guest-cta-panel {
  margin-top: 32px;
  padding: 28px 32px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 24px;
  border-radius: var(--radius-md);
  background: var(--color-accent-soft);
  border: 1px solid var(--color-border);
}
.guest-cta-panel .guest-cta-copy h3 {
  font-size: 1.15rem;
  margin: 0 0 4px;
}
.guest-cta-panel .guest-cta-copy p {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.95rem;
}
@media (max-width: 640px) {
  .guest-cta-panel {
    grid-template-columns: 1fr;
    text-align: left;
    padding: 24px;
  }
}

/* ---------- Guest registration form page ---------- */
.guest-form-section { padding: 64px 0 96px; }

.guest-form-wrap {
  max-width: 40rem;
  margin: 0 auto;
  background: var(--color-bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 48px clamp(24px, 4vw, 56px);
  border: 1px solid var(--color-border);
}

/* Event-mode (set by guest-form.js when ?eventId=X is present and the
   happy-path event card + form pair is showing): widen the wrap and,
   on desktop, lay the event card and the form side-by-side so the
   visitor sees both without scrolling. Falls back to the default
   single-column at < 900px. Notice / success panels strip the class
   in showOnly() so they never share the grid. */
.guest-form-wrap.event-mode {
  max-width: 68.75rem;
}
@media (min-width: 900px) {
  .guest-form-wrap.event-mode {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 40px;
    align-items: start;
  }
  /* The event card carries its own padding; reset its margin so the
     wrap's padding is the source of vertical rhythm in grid mode. */
  .guest-form-wrap.event-mode .event-header-card {
    margin: 0;
  }
}

.guest-form-header {
  margin-bottom: 32px;
}
.guest-form-header h1 {
  font-size: clamp(1.75rem, 3.5vw, 2.25rem);
  margin: 8px 0 12px;
}
.guest-form-header p {
  color: var(--color-text-muted);
  margin: 0;
}

.guest-form { display: grid; gap: 20px; }

.guest-form-field { display: flex; flex-direction: column; gap: 6px; }

.guest-form-field label {
  font-weight: var(--fw-semibold);
  font-size: 0.95rem;
  color: var(--color-text);
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}

.guest-form-field input {
  font: inherit;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  width: 100%;
}
.guest-form-field input:hover {
  border-color: var(--color-secondary);
}
.guest-form-field input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(19, 133, 196, 0.18);
}
.guest-form-field input.is-invalid,
.guest-form-field input[aria-invalid="true"] {
  border-color: var(--color-error);
}
.guest-form-field input.is-invalid:focus,
.guest-form-field input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px rgba(208, 69, 59, 0.18);
}

.field-hint {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin: 0;
}

.field-error {
  font-size: 0.88rem;
  color: var(--color-error);
  margin: 0;
}

.guest-form-summary-error {
  background: var(--color-error-soft);
  border: 1px solid var(--color-error);
  color: var(--color-error);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: 0.92rem;
  margin: 0;
}

/* Iter-7 waitlist offer panel — surfaces after the server returns
   event_full_waitlist_offer. Accent palette (informational, not
   error) since the visitor still has a forward action available
   (the submit button changes label to "Lägg dig på väntelistan"). */
.guest-form-waitlist-offer {
  background: var(--color-accent-soft);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  margin: 0;
}
.guest-form-waitlist-offer strong {
  display: block;
  color: var(--color-primary-dark);
  font-size: 0.95rem;
  margin-bottom: 4px;
}
.guest-form-waitlist-offer p {
  margin: 0;
  font-size: 0.92rem;
  color: var(--color-text);
  line-height: 1.45;
}

.guest-form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
  flex-wrap: wrap;
}

.guest-form-cancel {
  color: var(--color-text-muted);
  font-weight: var(--fw-medium);
  font-size: 0.95rem;
}
.guest-form-cancel:hover { color: var(--color-text); }

.guest-form-footnote {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin: 0;
}

#guest-form-submit { position: relative; min-width: 180px; }

.guest-form-submit-spinner {
  display: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: var(--color-text-inverse);
  animation: tfk-spinner-rotate 0.7s linear infinite;
}
#guest-form-submit.is-submitting .guest-form-submit-label { opacity: 0.6; }
#guest-form-submit.is-submitting .guest-form-submit-spinner { display: inline-block; }

@keyframes tfk-spinner-rotate {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Success / reused / limit-reached panel — same shape, copy varies. */
.guest-form-success {
  display: grid;
  justify-items: start;
  gap: 16px;
  padding: 8px 0;
}

.guest-form-success-icon {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--color-success-soft);
  color: var(--color-success);
  display: grid;
  place-items: center;
}
.guest-form-success-icon svg { width: 30px; height: 30px; }

.guest-form-success h2 {
  font-size: 1.5rem;
  margin: 0;
}

.guest-form-success p {
  margin: 0;
  color: var(--color-text-muted);
}

/* ---------- Per-event guest form (?eventId=X) ----------
   Reuses .guest-form-wrap / .guest-form / .field-error from the
   generic flow. The event header card, loading spinner, and notice
   panels (members-only / paid / unavailable) are extra surfaces the
   JS swaps in/out depending on the fetched event state. */

.guest-form-loading {
  display: grid;
  justify-items: center;
  gap: 12px;
  padding: 24px 0 12px;
  color: var(--color-text-muted);
  font-size: 0.95rem;
}
.guest-form-loading p { margin: 0; }
.guest-form-loading-spinner {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 3px solid var(--color-accent-soft);
  border-top-color: var(--color-primary);
  animation: tfk-spinner-rotate 0.7s linear infinite;
}

.event-header-card {
  margin: 0 0 28px;
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--color-border);
  background: var(--color-accent-soft);
}

.event-header-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--color-accent);
  overflow: hidden;
}
.event-header-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.event-header-content {
  padding: 24px clamp(20px, 4vw, 32px);
  display: grid;
  gap: 8px;
}
.event-header-content .eyebrow {
  color: var(--color-primary-dark);
  font-weight: var(--fw-semibold);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.event-header-content h1 {
  font-size: clamp(1.5rem, 3vw, 1.875rem);
  margin: 4px 0 0;
  color: var(--color-text);
  line-height: 1.2;
}
.event-header-meta {
  margin: 0;
  color: var(--color-primary-dark);
  font-weight: var(--fw-medium);
  font-size: 0.95rem;
}
.event-header-meta:empty { display: none; }
.event-header-blurb {
  margin: 8px 0 0;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  line-height: 1.55;
}
/* Full event description on the per-event page. Free-form text from
   the admin editor (may include line breaks); white-space: pre-line
   preserves them while still wrapping long paragraphs naturally.
   The wrap carries the divider + spacing so re-rendering the inner
   <div> with / without the -collapsed clamp doesn't double-up
   borders or margins. */
.event-header-description-wrap {
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}
.event-header-description {
  color: var(--color-text);
  font-size: 0.97rem;
  line-height: 1.6;
  white-space: pre-line;
}
/* Clamp toggled by guest-form.js — 6 lines is the breakpoint where
   "this description warrants a Visa mer" kicks in. Short descriptions
   have the class removed entirely after the overflow check so their
   line-height + spacing read identically to never-clamped text. */
.event-header-description-collapsed {
  display: -webkit-box;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.event-header-description-toggle {
  margin-top: 10px;
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: var(--fw-semibold);
  color: var(--color-primary-dark);
  cursor: pointer;
}
.event-header-description-toggle:hover {
  text-decoration: underline;
}
.event-header-description-toggle:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Notice panels — members-only / paid-event / generic unavailable.
   Same shape as .guest-form-success but accent palette instead of
   success so the surface reads as "informational dead end with a
   forward CTA", not "you're done". */
.guest-form-notice {
  display: grid;
  justify-items: start;
  gap: 16px;
  padding: 8px 0;
}
.guest-form-notice-icon {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--color-accent-soft);
  color: var(--color-primary-dark);
  display: grid;
  place-items: center;
}
.guest-form-notice-icon svg { width: 30px; height: 30px; }
.guest-form-notice h2 {
  font-size: 1.5rem;
  margin: 0;
}
.guest-form-notice p {
  margin: 0;
  color: var(--color-text-muted);
  line-height: 1.55;
}
.guest-form-notice-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
  flex-wrap: wrap;
}

/* ---------- Membership application form (/bli-medlem) ----------
   Reuses .field-error / .field-hint utilities from the guest form. */
.apply-form-section { padding: 64px 0 96px; }

.apply-form-wrap {
  max-width: 47.5rem;
  margin: 0 auto;
  background: var(--color-bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 48px clamp(24px, 4vw, 56px);
  border: 1px solid var(--color-border);
}

.apply-form-header { margin-bottom: 32px; }
.apply-form-header h1 {
  font-size: clamp(1.75rem, 3.5vw, 2.25rem);
  margin: 8px 0 12px;
}
.apply-form-header p {
  color: var(--color-text-muted);
  margin: 0;
  line-height: 1.55;
}

.apply-form { display: grid; gap: 28px; }

/* Section spacing: title + hint are tightly grouped, then breathing
   room before the first field. The grid-gap approach used previously
   doubled vertical space because the hint paragraph carried its own
   <p> bottom margin in addition to the section's gap, which read as
   "displaced" between section header and the first input. */
.apply-section {
  border: none;
  margin: 0;
  padding: 24px 0 0;
  border-top: 1px solid var(--color-border);
}
.apply-section:first-of-type {
  border-top: none;
  padding-top: 0;
}

/* En <legend> ritas annars in i fieldsetets övre kantlinje: rubriken
   hamnade på linjen och sektionens 24 px utfyllnad under den, så
   ledtexten kom 50 px ned från rubriken i sektion 2–4 men direkt under i
   sektion 1. Flytad lämnar legend kantlinjen och blir ett vanligt block —
   linjen ovanför, rubrik och ledtext tätt ihop, samma i alla sektioner. */
.apply-section-title {
  float: left;
  width: 100%;
  font-size: 0.95rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text);
  letter-spacing: 0.02em;
  padding: 0;
  margin: 0 0 4px;
}
.apply-section-title + * { clear: both; }

.apply-section-hint {
  margin: 0 0 20px;
  font-size: 0.9rem;
  color: var(--color-text-muted);
  line-height: 1.5;
}

.apply-section > .apply-field,
.apply-section > .apply-grid {
  margin-bottom: 16px;
}
.apply-section > .apply-field:last-child,
.apply-section > .apply-grid:last-child {
  margin-bottom: 0;
}

.apply-grid {
  display: grid;
  gap: 16px;
}
@media (min-width: 640px) {
  .apply-grid-1-1 { grid-template-columns: 1fr 1fr; }
  .apply-grid-2-1 { grid-template-columns: 2fr 1fr; }
  .apply-grid-1-2 { grid-template-columns: 1fr 2fr; }
}

.apply-field { display: flex; flex-direction: column; gap: 6px; }

.apply-field label,
.apply-radio-label {
  font-weight: var(--fw-semibold);
  font-size: 0.95rem;
  color: var(--color-text);
}

.apply-field input {
  font: inherit;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  width: 100%;
}
.apply-field input:hover {
  border-color: var(--color-secondary);
}
.apply-field input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(19, 133, 196, 0.18);
}
.apply-field input.is-invalid,
.apply-field input[aria-invalid="true"] {
  border-color: var(--color-error);
}
.apply-field input.is-invalid:focus,
.apply-field input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px rgba(208, 69, 59, 0.18);
}

/* Subtle green checkmark on validated, non-empty fields. Encoded as a
   data-URI background so we don't need any HTML wrapper around the
   input. Mirrors the portal profile-editor's "filled and correct"
   reassurance (CLAUDE.md). Only shows when JS adds .is-valid — empty
   or invalid inputs render with no icon and no border change. */
.apply-field input.is-valid {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F9E6B' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px 16px;
  padding-right: 40px;
}
.apply-field input.is-valid.is-invalid,
.apply-field input.is-valid[aria-invalid="true"] {
  /* Server-side rejection (e.g. email collision) trumps client-side
     "looks valid" — drop the checkmark so we don't lie to the user. */
  background-image: none;
  padding-right: 14px;
}

.apply-radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 4px;
}

.apply-radio {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--color-border);
  background: var(--color-bg);
  font-size: 0.95rem;
  font-weight: var(--fw-medium);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease,
              color 0.15s ease;
}
.apply-radio:hover {
  border-color: var(--color-secondary);
  color: var(--color-text);
}
.apply-radio input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--color-border);
  margin: 0;
  cursor: pointer;
  position: relative;
}
.apply-radio input[type="radio"]:checked {
  border-color: var(--color-primary);
  background: var(--color-primary);
  box-shadow: inset 0 0 0 3px var(--color-bg);
}
.apply-radio:has(input[type="radio"]:checked) {
  border-color: var(--color-primary);
  color: var(--color-primary-dark);
  background: var(--color-accent-soft);
}

.apply-form-summary-error {
  background: var(--color-error-soft);
  border: 1px solid var(--color-error);
  color: var(--color-error);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: 0.92rem;
  margin: 0;
}

.apply-form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
  flex-wrap: wrap;
}

.apply-form-cancel {
  color: var(--color-text-muted);
  font-weight: var(--fw-medium);
  font-size: 0.95rem;
}
.apply-form-cancel:hover { color: var(--color-text); }

.apply-form-footnote {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin: 0;
}

#apply-form-submit { position: relative; min-width: 200px; }

.apply-form-submit-spinner {
  display: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: var(--color-text-inverse);
  animation: tfk-spinner-rotate 0.7s linear infinite;
}
#apply-form-submit.is-submitting .apply-form-submit-label { opacity: 0.6; }
#apply-form-submit.is-submitting .apply-form-submit-spinner { display: inline-block; }

.apply-form-success {
  display: grid;
  justify-items: start;
  gap: 16px;
  padding: 8px 0;
}

.apply-form-success-icon {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--color-success-soft);
  color: var(--color-success);
  display: grid;
  place-items: center;
}
.apply-form-success-icon svg { width: 30px; height: 30px; }

.apply-form-success h2 {
  font-size: 1.5rem;
  margin: 0;
}

.apply-form-success p {
  margin: 0;
  color: var(--color-text-muted);
}

/* ───────── Samarbetspartners page (iteration 5.5 phase 6) ───────── */

.partners-section {
  background: var(--color-bg);
}

.partners-header {
  max-width: 45rem;
  margin: 0 auto 40px;
  text-align: center;
}

.partners-header h1 {
  margin: 8px 0 12px;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  color: var(--color-dark);
}

.partners-header p {
  margin: 0;
  color: var(--color-text-muted);
  line-height: 1.55;
}

/* Laddningsläget: tre skelettkort i rutnätets form (samarbetspartners.html). */
.partners-status {
  color: var(--color-text-muted);
}

/* Rubriken ovanför är centrerad; med få partners låg korten ändå till
   vänster och resten av raden stod tom. auto-fit slår ihop tomma spår och
   340 px-taket gör att de som finns centreras — räcker korten till en
   hel rad fyller de den som förut. */
.partners-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 340px));
  justify-content: center;
  gap: 20px;
}
@media (max-width: 640px) {
  .partners-grid { grid-template-columns: 1fr; }
}

.partner-card {
  /* Positioning context for .partner-card-stretch::after — the
     invisible overlay that makes the whole card one click target. */
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform 160ms ease, box-shadow 160ms ease,
              border-color 160ms ease;
}

.partner-card-linked:hover,
.partner-card-linked:focus-within {
  transform: translateY(-2px);
  border-color: var(--color-primary);
  box-shadow: 0 8px 24px rgba(16, 42, 67, 0.08);
}

/* Logo area: white background, generous height so wordmarks (the
   typical partner-logo shape) render at a legible size and square
   logos can grow large enough not to feel small. No tint — the card
   border + padding alone provide enough structure, and the tint was
   reading as "placeholder zone". */
.partner-card-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 150px;
  padding: 22px 24px;
}

.partner-card-logo img {
  max-width: 85%;
  max-height: 120px;
  object-fit: contain;
}

.partner-card-logo-fallback {
  /* When no logo exists, render the company initial as a styled
     wordmark — fills the same banner area at a size that reads as
     "this is the brand", not "image failed to load". */
  color: var(--color-primary-dark);
}

.partner-card-logo-fallback span {
  font-size: 3.5rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
}

.partner-card-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px 24px 22px;
  /* Subtle divider between the logo zone and the supporting content —
     re-establishes the visual separation that the tint used to give,
     without the heavier "placeholder zone" feel. */
  border-top: 1px solid var(--color-border);
}

.partner-card-name {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--color-dark);
  line-height: 1.3;
}

.partner-card-name a {
  color: inherit;
  text-decoration: none;
}

/* Stretched-link pattern: the heading anchor projects a transparent
   overlay across the entire card, so a click anywhere follows it —
   without nesting anchors, which is invalid markup. Secondary links
   inside the card opt back above the overlay with position + z-index
   (see .partner-card-more). */
.partner-card-stretch::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Capped at 3 lines so one partner with a 600-char description can't
   blow out the height of its whole grid row (cards stretch to the
   tallest in the row). The full text is one click away on the member's
   public page — see the "Läs mer" link in partners.js. */
.partner-card-description {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Action row: outbound hint (left) + inbound "Läs mer" (right). Wraps
   to two lines on narrow cards rather than crushing either label. */
.partner-card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  margin-top: 4px;
}

/* Sits above the stretched overlay so it stays independently
   clickable — this is the link to the full business description. */
.partner-card-more {
  position: relative;
  z-index: 1;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
}

.partner-card-more:hover,
.partner-card-more:focus-visible {
  text-decoration: underline;
}

.partner-card-link-hint {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--color-primary-dark);
  text-transform: uppercase;
}

.partners-empty,
.partners-error {
  max-width: 32.5rem;
  margin: 32px auto 0;
  padding: 40px 32px;
  background: var(--color-accent-soft);
  border-radius: 12px;
  text-align: center;
  color: var(--color-text);
}

.partners-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 16px;
  background: var(--color-bg);
  color: var(--color-primary);
  margin-bottom: 16px;
}

.partners-empty h2 {
  margin: 0 0 8px;
  font-size: 1.25rem;
  color: var(--color-dark);
}

.partners-empty p {
  margin: 0;
  color: var(--color-text-muted);
  line-height: 1.55;
}

.partners-error {
  background: var(--color-error-soft);
  color: var(--color-error);
}

.partners-error p {
  margin: 0;
}

/* ============================================================
   Policy pages — /integritetspolicy.
   Long-form prose; narrow column for comfortable reading.
   ============================================================ */
.container-narrow {
  max-width: 47.5rem;
  margin: 0 auto;
  padding: 0 24px;
}
/* Samma 18 px som .container under 480 px — regeln ovan kommer senare i
   filen och vann, så texten låg 6 px innanför headerns logga. */
@media (max-width: 480px) {
  .container-narrow { padding: 0 18px; }
}
.policy-page { padding: 64px 0 96px; }
.policy-header { margin-bottom: 40px; }
.policy-header h1 {
  margin: 12px 0 16px;
  font-size: clamp(2rem, 4vw, 2.75rem);
  line-height: 1.15;
  color: var(--color-text);
}
.policy-lead {
  font-size: 1.05rem;
  color: var(--color-text-muted);
  line-height: 1.55;
  margin: 0;
}
.policy-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 24px;
}
.policy-toc a {
  display: inline-block;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--color-accent-soft);
  color: var(--color-primary-dark);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 600;
  transition: background 120ms ease, color 120ms ease;
}
.policy-toc a:hover {
  background: var(--color-accent);
  color: var(--color-text);
}
.policy-body section { margin-bottom: 48px; }
.policy-body h2 {
  margin: 0 0 16px;
  font-size: 1.6rem;
  line-height: 1.25;
  color: var(--color-text);
  padding-bottom: 8px;
  border-bottom: 2px solid var(--color-accent-soft);
}
.policy-body h3 {
  margin: 28px 0 10px;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--color-text);
}
.policy-body p {
  margin: 0 0 16px;
  font-size: 1rem;
  line-height: 1.65;
  color: var(--color-text);
}
.policy-list {
  margin: 0 0 16px;
  padding-left: 0;
  list-style: none;
}
.policy-list li {
  position: relative;
  padding: 14px 16px 14px 20px;
  margin-bottom: 10px;
  background: var(--color-accent-soft);
  border-left: 3px solid var(--color-primary);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--color-text);
}
/* Integritetspolicyns kort: rubriken är situationen eller företaget, och
   etiketterna (Vilka uppgifter, Varför …) står i en egen kolumn bredvid
   texten. Kolumnen blir så bred som avsnittets längsta etikett, så korten
   i ett avsnitt linjerar. Under 640 px hamnar etiketten ovanför. */
.policy-case {
  display: block;
  margin-bottom: 8px;
  font-weight: var(--fw-semibold);
}
.policy-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  /* Den mindre etiketten står på samma baslinje som textens första rad. */
  align-items: baseline;
  gap: 6px 16px;
  margin: 0;
}
.policy-facts dt {
  font-size: 0.88rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-muted);
}
.policy-facts dd { margin: 0; }
@media (max-width: 640px) {
  .policy-facts { grid-template-columns: 1fr; gap: 0; }
  .policy-facts dd + dt { margin-top: 8px; }
}
.policy-bullets {
  margin: 0 0 16px;
  padding-left: 1.25em;
  list-style: disc;
}
.policy-bullets li {
  margin-bottom: 6px;
  line-height: 1.65;
}
.policy-bullets li::marker { color: var(--color-primary); }
.policy-table {
  width: 100%;
  margin: 0 0 20px;
  border-collapse: collapse;
  font-size: 0.98rem;
  line-height: 1.55;
}
.policy-table th,
.policy-table td {
  padding: 10px 16px 10px 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--color-border);
}
.policy-table td { padding-right: 0; }
.policy-table thead th {
  padding-top: 0;
  font-size: 0.88rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-muted);
}
.policy-table tbody th {
  width: 42%;
  font-weight: var(--fw-semibold);
}
.policy-quote {
  margin: 16px 0 24px;
  padding: 14px 18px;
  border-left: 3px solid var(--color-accent);
  background: var(--color-accent-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.policy-quote p { margin: 0; font-size: 0.95rem; color: var(--color-text); }

/* ============================================================
   Image credit captions — bottom-left overlay on the hero (always
   visible, positioned over the dark side of the gradient) and a
   hover-revealed overlay on each Trelleborg figure. Keeps "Foto
   John R. Pickens" present without crowding the photography by
   default; the hint slides in on engagement.
   ============================================================ */
.roots-photo figcaption {
  position: absolute;
  left: 12px;
  bottom: 12px;
  margin: 0;
  padding: 5px 10px;
  border-radius: var(--radius-sm);
  background: rgba(8, 18, 32, 0.55);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  font-size: 0.74rem;
  color: rgba(255, 255, 255, 0.92);
  letter-spacing: 0.02em;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 180ms ease, transform 180ms ease;
  pointer-events: none;
}
.roots-photo:hover figcaption,
.roots-photo:focus-within figcaption {
  opacity: 1;
  transform: translateY(0);
}
/* Touch devices have no real hover — keep the credit visible (but
   still subtle) so mobile users see the attribution. */
@media (hover: none) {
  .roots-photo figcaption {
    opacity: 1;
    transform: none;
  }
}
.hero-credit {
  position: absolute;
  left: 20px;
  bottom: 20px;
  z-index: 2;
  margin: 0;
  font-size: 0.74rem;
  color: rgba(255, 255, 255, 0.88);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
  letter-spacing: 0.02em;
}

/* ============================================================
   Footer policy-link row — used on the two policy pages and any
   future page that adopts the simplified footer.
   ============================================================ */
/* Screen-reader-only text. Every landing page has carried its own copy
   of this rule in an inline <style> block; the server-rendered pages
   (/nyheter/<id>, /medlemmar/<id>) rely on this one, since they share
   their chrome from functions/src/public/_layout.ts and have no local
   block to fall back on. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

.footer-policy-links {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: center;
  margin-bottom: 16px;
  font-size: 0.9rem;
}
/* Raden ligger på den mörka sidfoten. text-muted gav 2,5:1 och den
   aktuella sidans primary 3,4:1 — båda under WCAG:s 4,5. Samma ljusa
   ton som länkarna i startsidans sidfot (.footer-col a) ger 9:1. */
.footer-policy-links a {
  color: rgba(255, 255, 255, 0.78);
  text-decoration: none;
}
.footer-policy-links a:hover { color: var(--color-text-inverse); }
.footer-policy-links a[aria-current="page"] {
  color: var(--color-text-inverse);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Centered social-icon row on the minimal footers (pages without
   the multi-column footer-grid). Reuses .social-links for the
   pill-button styling. */
.footer-social-row {
  text-align: center;
  margin-bottom: 20px;
}

/* ============================================================
   Cookie banner — centred dark-glass card at the bottom of the
   viewport. Injected by js/cookie-banner.js only on first visit.
   Compact (max-width 560 px), so it doesn't dominate; dark
   translucent surface with heavy backdrop blur so it reads as
   system chrome rather than a page section.
   ============================================================ */
.cookie-banner {
  position: fixed;
  bottom: 24px;
  left: 50%;
  z-index: 1000;
  width: calc(100% - 32px);
  max-width: 35rem;
  background: rgba(15, 28, 45, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(8, 18, 32, 0.45),
              0 2px 8px rgba(8, 18, 32, 0.25);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
          backdrop-filter: saturate(180%) blur(22px);
  color: rgba(255, 255, 255, 0.95);
  animation: cookie-banner-enter 320ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.cookie-banner-leaving {
  animation: cookie-banner-leave 220ms ease-in forwards;
}
/* Keyframes have to carry translateX(-50%) on every step or the
   card snaps off-centre during the animation. */
@keyframes cookie-banner-enter {
  from { opacity: 0; transform: translate(-50%, 24px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@keyframes cookie-banner-leave {
  from { opacity: 1; transform: translate(-50%, 0); }
  to   { opacity: 0; transform: translate(-50%, 24px); }
}
.cookie-banner,
.cookie-banner-leaving {
  /* Default static position before/after animation runs. */
  transform: translateX(-50%);
}
.cookie-banner-inner {
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.cookie-banner-text {
  margin: 0;
  flex: 1 1 auto;
  font-size: 0.88rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.92);
}
.cookie-banner-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}
.cookie-banner-link {
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.85rem;
  font-weight: 500;
  text-decoration: none;
  padding: 6px 4px;
  transition: color 120ms ease;
}
.cookie-banner-link:hover {
  color: white;
  text-decoration: underline;
}
.cookie-banner-button {
  appearance: none;
  border: 0;
  background: white;
  color: #0F1C2D;
  font-size: 0.88rem;
  font-weight: 600;
  padding: 9px 18px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
.cookie-banner-button:hover { background: rgba(255, 255, 255, 0.88); }
.cookie-banner-button:active { transform: scale(0.97); }
.cookie-banner-button:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: 3px;
}
/* On narrow phones, drop to a stacked layout so the row doesn't
   crush the text and the actions stay tappable. */
@media (max-width: 480px) {
  .cookie-banner-inner {
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    padding: 16px 18px;
  }
  .cookie-banner-actions { justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .cookie-banner,
  .cookie-banner-leaving {
    animation: none !important;
  }
}
