/* ============================================================
   v18-additions.css — Playtypus: new home-layout options and pinned
   category navigation, added alongside LayoutStyleManifest on the
   Playtyper side (see /mnt/skills or the Playtyper repo for the
   editor/prompt-generator half of this change).

   Load after ui-variants.css (same convention as v14-additions.css) —
   MUST be added to BOTH Playtypus.App/wwwroot/index.html and
   Playtypus.Web/wwwroot/index.html, and to Playtyper's
   preview-bridge.js asset list, or it silently never loads. All three
   are already updated as part of this same change; if you copy this
   file into a different host project, remember the fourth reference.
   ============================================================ */

/* ══════════════════════════════════════════════════════════════
   PINNED CATEGORY TABS  (Ui.CategoryNavPosition = "pinned")
   Reuses .category-tabs/.category-tab/.category-tab--active exactly as
   defined in ui.css for the FilterDrawer — this is only a positioning
   wrapper, not a new visual style, so the two stay visually consistent
   automatically instead of needing to be kept in sync by hand.
   ══════════════════════════════════════════════════════════════ */

.category-tabs-pinned {
  padding: var(--spacing-sm, 8px) var(--spacing-md, 16px) 0;
  margin-bottom: var(--spacing-sm, 8px);
}

.category-tabs-pinned .category-tabs {
  padding-bottom: var(--spacing-sm, 8px);
  border-bottom: 1px solid var(--color-border);
}

/* An "All" pseudo-tab so users can get back to the unfiltered feed
   without opening the drawer — the drawer's own list has no such
   affordance because clearing filters there already has a dedicated
   "Clear filters" button (see AppShell's empty-state). */
.category-tab--all-pseudo {
  font-weight: var(--font-weight-heading, 600);
}

/* ══════════════════════════════════════════════════════════════
   MAP HOME  (Ui.HomeLayout = "map")
   Plots activities that carry a "map" content block via the existing
   playtypusMap JS module (see playtypus-map.js — initMulti, added
   alongside this file). Activities without coordinates are listed
   below, grouped by category, so nothing in the pack becomes
   unreachable just because it lacks a pin.
   ══════════════════════════════════════════════════════════════ */

.map-home__canvas {
  width: 100%;
  height: 46vh; /* dvh fallback for browsers/webviews that don't support it */
  height: 46dvh;
  min-height: 260px;
  max-height: 420px;
  border-radius: var(--border-radius-lg, 18px);
  overflow: hidden;
  background: var(--color-surface-alt, var(--color-surface));
  margin-bottom: var(--spacing-md, 16px);
  /* premium-home.css polish (2026-07-26): subtle inset shadow so the
     canvas reads as "embedded in a card" like the rest of the app,
     rather than a flat rectangle. */
  box-shadow: inset var(--card-shadow, 0 1px 3px rgba(0,0,0,0.12));
}

/* premium-home.css polish (2026-07-26): warm gradient CTA (same technique
   as .card-visual--map) instead of a dashed "form field to fill in" look —
   white text/icon on color instead of grey on transparent. */
.map-home__consent {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm, 8px);
  width: 100%;
  height: 100%;
  border: none;
  border-radius: var(--border-radius-lg, 18px);
  background: linear-gradient(135deg, var(--color-primary-light, #6B65F0), var(--color-primary, #453FE9));
  cursor: pointer;
  color: rgba(255, 255, 255, 0.95);
  font: inherit;
  text-align: center;
  padding: var(--spacing-md, 16px);
  transition: filter 150ms ease;
}

.map-home__consent:hover { filter: brightness(1.08); }

.map-home__consent-icon {
  width: 28px;
  height: 28px;
  color: #fff;
}

.map-home__consent-title {
  color: #fff;
  font-weight: var(--font-weight-heading, 600);
  margin: 0;
}

.map-home__consent-notice { margin: 0; font-size: var(--font-size-sm, 0.875rem); opacity: 0.9; }

/* premium-home.css polish (2026-07-26): matches today-home__empty's
   icon+text+CTA warmth instead of a single line of grey text. */
.map-home__no-pins {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm, 8px);
  height: 100%;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm, 0.875rem);
  text-align: center;
  padding: var(--spacing-md, 16px);
}

.map-home__no-pins-icon { font-size: 2.25rem; }

/* ── Pins-list (activities without coordinates) ──────────────────────────
   premium-home.css polish (2026-07-26): previously bare dashboard-tile
   buttons with no wrapper of their own — reused desktop-grid sizing
   verbatim and had no visual separation from the map above. This wrapper
   gives it its own single-column identity and a clear "more activities"
   heading before the per-category groups start. */
.map-home__pins-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm, 8px);
}

.map-home__pins-heading {
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin: var(--spacing-sm, 8px) 0 0;
  padding-top: var(--spacing-md, 16px);
  border-top: 1px solid var(--color-border);
}

.map-home__pin-tile {
  flex-direction: row;
  justify-content: flex-start;
  text-align: left;
  min-height: 56px;
  width: 100%;
}
.map-home__pin-tile .dashboard-tile__icon { font-size: 1.5rem; }

.map-home__section-title {
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: var(--font-weight-heading, 600);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin: var(--spacing-md, 16px) 0 var(--spacing-sm, 8px);
}

/* premium-home.css polish (2026-07-26): Leaflet injects its own attribution
   control markup at runtime — this can only be styled globally by class,
   not from Razor. Same frosted-glass treatment as premium.css's B3
   (.detail-close-btn) instead of leaving Leaflet's own default styling.
   !important is load-order, not specificity, insurance: leaflet.css is
   fetched and appended to <head> by playtypus-map.js at runtime, so it
   always lands after this stylesheet and would otherwise win the cascade
   at equal specificity regardless of file order in index.html. */
.leaflet-control-attribution {
  background: rgba(0, 0, 0, 0.55) !important;
  color: rgba(255, 255, 255, 0.85) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-radius: var(--radius-sm, 6px);
  padding: 2px 6px !important;
}
.leaflet-control-attribution a { color: rgba(255, 255, 255, 0.95) !important; }

/* ══════════════════════════════════════════════════════════════
   TODAY HOME  (Ui.HomeLayout = "today")
   ══════════════════════════════════════════════════════════════ */

/* premium-home.css polish (2026-07-26): thin eyebrow above the heading,
   same uppercase/letter-spacing pattern as sections-home__row-title/
   dashboard-home__section-title — gives a sense of *which* day this is
   instead of the heading reading as static boilerplate. */
.today-home__date-eyebrow {
  font-size: var(--font-size-xs, 0.75rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin: 0 0 var(--spacing-xs, 4px);
}

.today-home__heading {
  font-size: var(--font-size-lg, 1.125rem);
  font-weight: var(--font-weight-heading, 700);
  margin: 0 0 var(--spacing-xs, 4px);
}

.today-home__subheading {
  color: var(--color-text-muted);
  margin: 0 0 var(--spacing-md, 16px);
  font-size: var(--font-size-sm, 0.875rem);
}

.today-home__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--spacing-sm, 8px);
  padding: var(--spacing-xl, 40px) var(--spacing-md, 16px);
  color: var(--color-text-muted);
  border-radius: var(--border-radius-lg, 18px);
}

.today-home__empty-icon { font-size: 2.25rem; }

/* premium-home.css polish (2026-07-26): the "all done" state previously
   shared the same neutral grey box as "not configured" — same color-mix
   technique as .btn-done so the two empty states read as visibly
   different (one is a good outcome, the other is a config gap). */
.today-home__empty--success {
  color: color-mix(in srgb, var(--color-done, #22c55e) 70%, #000);
  background: color-mix(in srgb, var(--color-done, #22c55e) 10%, transparent);
}

/* premium-home.css polish (2026-07-26): thin colored top border so
   "due today" tiles read as visually distinct from the generic dashboard
   grid they share a base class with. */
.today-home__tile {
  border-top: 3px solid var(--color-primary);
}

/* ══════════════════════════════════════════════════════════════
   MAGAZINE HOME  (Ui.HomeLayout = "magazine")
   ══════════════════════════════════════════════════════════════ */

.magazine-home__hero {
  position: relative;
  display: block;
  width: 100%;
  min-height: 260px;
  border-radius: var(--border-radius-xl, 28px);
  overflow: hidden;
  /* premium-home.css polish (2026-07-26): more breathing room before the
     "More" grid, proportionate to how much the hero dominates the view. */
  margin-bottom: var(--spacing-xl, 32px);
  background: var(--color-primary);
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
  /* premium-home.css polish (2026-07-26): same spring entrance as the
     other five views, via the shared keyframe in premium-home.css. */
  animation: premiumHomeEntrance 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.magazine-home__hero-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* premium-home.css polish (2026-07-26): stronger scrim (was 0.65 at the
   base, now 0.75) plus a subtle radial corner vignette layered on top for
   filmic depth — text legibility over bright photos was the original
   goal, this pushes it from "adequate" to "considered". */
.magazine-home__hero-scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 100% 0%, rgba(0,0,0,0.25) 0%, transparent 55%),
    linear-gradient(180deg, rgba(0,0,0,0.08) 0%, rgba(0,0,0,0.75) 100%);
}

.magazine-home__hero-body {
  position: relative;
  padding: var(--spacing-lg, 24px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 260px;
  color: #fff;
}

/* premium-home.css polish (2026-07-26): a frosted chip background (same
   values as premium.css's B3) instead of relying on text-shadow alone for
   legibility — reads as a deliberate label rather than text floating on
   the photo. */
.magazine-home__hero-eyebrow {
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--font-size-xs, 0.75rem);
  margin: 0 0 var(--spacing-sm, 8px);
  padding: 3px 10px;
  border-radius: var(--border-radius-pill, 999px);
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.magazine-home__hero-title {
  font-size: var(--font-size-xl, 1.375rem);
  font-weight: 700;
  margin: 0 0 var(--spacing-xs, 4px);
  text-shadow: 0 1px 4px rgba(0,0,0,0.4);
}

.magazine-home__hero-desc {
  margin: 0;
  font-size: var(--font-size-sm, 0.875rem);
  opacity: 0.92;
  max-width: 60ch;
}

.magazine-home__rest-title {
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: var(--font-weight-heading, 600);
  color: var(--color-text-muted);
  margin: 0 0 var(--spacing-sm, 8px);
  /* premium-home.css polish (2026-07-26): the hero's own margin-bottom
     already grew (see above) — this adds a touch more on this side of
     the seam too, so the hero doesn't feel like it's crowding the grid
     below it. */
  padding-top: var(--spacing-xs, 4px);
}

/* ══════════════════════════════════════════════════════════════
   SEARCH HOME  (Ui.HomeLayout = "search")
   ══════════════════════════════════════════════════════════════ */

.search-home__field-wrap {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm, 8px);
  padding: var(--spacing-sm, 8px) var(--spacing-md, 16px);
  border: 1.5px solid var(--color-border);
  border-radius: var(--border-radius-lg, 18px);
  background: var(--color-surface);
  margin-bottom: var(--spacing-md, 16px);
}

.search-home__field-wrap {
  transition: box-shadow 180ms ease, border-color 180ms ease;
}
.search-home__field-wrap:focus-within {
  border-color: var(--color-primary);
  /* premium-home.css polish (2026-07-26): a soft lift on focus, not just
     a border-color swap — matches how focus/hover reads everywhere else
     in the app. */
  box-shadow: var(--card-shadow-hover);
}

.search-home__field {
  flex: 1;
  border: none;
  outline: none;
  background: none;
  font: inherit;
  color: var(--color-text);
  min-width: 0;
}

.search-home__icon { color: var(--color-text-muted); flex-shrink: 0; }

.search-home__shortcuts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs, 6px);
  margin-bottom: var(--spacing-lg, 24px);
}

.search-home__shortcut {
  padding: var(--spacing-xs, 6px) var(--spacing-sm, 10px);
  border-radius: var(--border-radius-pill, 999px);
  border: 1px solid var(--color-border);
  background: var(--color-surface-alt, var(--color-surface));
  font-size: var(--font-size-sm, 0.875rem);
  cursor: pointer;
  color: var(--color-text);
}

/* premium-home.css polish (2026-07-26): lift/press physics come from the
   shared .premium-hover-lift class (see SearchHomeView.razor markup) —
   only the border-color swap is specific enough to this element to stay
   here. */
.search-home__shortcut:hover { border-color: var(--color-primary); }

.search-home__hint {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm, 0.875rem);
  text-align: center;
  padding: var(--spacing-lg, 24px) 0;
}

/* premium-home.css polish (2026-07-26): the activity count reads as
   boilerplate grey text otherwise — bolding just the number (not the
   whole sentence) needed its own wrapping span, see SearchHomeView.razor. */
.search-home__hint-count {
  font-weight: 800;
  color: var(--color-text);
}

/* ══════════════════════════════════════════════════════════════
   DATA SOURCE SEARCH HOME  (Ui.HomeLayout = "search"/"liveData" +
   Ui.EffectiveSearchDataViewRefs — see DataSourceSearchHomeView.razor)
   2026-08-20, datakälle-strategin: kort/detalj-integration.

   Den gamla live-data-home__*-klassuppsättningen (LiveDataHomeView.razor.css,
   nu borttagen tillsammans med filen) var en helt fristående yta, aldrig
   kopplad mot premium-home.css — precis det strategidokumentet pekade ut
   som avvikelsen att åtgärda (se §1.2). De genuint delade elementen
   (sökfält, hint-text) återanvänder därför SEARCH HOME-klasserna rakt av
   ovan istället för att klonas här; bara det som faktiskt är nytt
   (geo-knapp, platsresultat, vald-plats-header, flikväxlare) får egna
   klasser, i samma --spacing-*/--color-*/--border-radius-*-skala som
   resten av den här filen.
   ══════════════════════════════════════════════════════════════ */

.data-source-search-home__geo-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs, 6px);
  padding: var(--spacing-xs, 6px) var(--spacing-sm, 10px);
  margin-bottom: var(--spacing-md, 16px);
  border-radius: var(--border-radius-pill, 999px);
  border: 1px solid var(--color-border);
  background: var(--color-surface-alt, var(--color-surface));
  font-size: var(--font-size-sm, 0.875rem);
  color: var(--color-text);
  cursor: pointer;
}
.data-source-search-home__geo-btn:hover { border-color: var(--color-primary); }
.data-source-search-home__geo-btn:disabled { opacity: 0.6; cursor: default; }

.data-source-search-home__place-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs, 6px);
}

.data-source-search-home__place-result {
  width: 100%;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--spacing-sm, 8px);
  padding: var(--spacing-sm, 8px) var(--spacing-md, 16px);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius-lg, 18px);
  background: var(--color-surface);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}

.data-source-search-home__place-name { font-weight: 600; }
.data-source-search-home__place-muni {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm, 0.875rem);
  flex-shrink: 0;
}

.data-source-search-home__selected {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm, 8px);
  padding: var(--spacing-sm, 8px) var(--spacing-md, 16px);
  margin-bottom: var(--spacing-md, 16px);
  border-radius: var(--border-radius-lg, 18px);
  background: var(--color-surface-alt, var(--color-surface));
  font-weight: 600;
  color: var(--color-text);
}

.data-source-search-home__change-btn {
  padding: var(--spacing-xs, 6px) var(--spacing-sm, 10px);
  border-radius: var(--border-radius-pill, 999px);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: 400;
  color: var(--color-text);
  cursor: pointer;
}
.data-source-search-home__change-btn:hover { border-color: var(--color-primary); }

.data-source-search-home__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs, 6px);
  margin-bottom: var(--spacing-md, 16px);
}

.data-source-search-home__tab {
  padding: var(--spacing-xs, 6px) var(--spacing-md, 16px);
  border-radius: var(--border-radius-pill, 999px);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  font-size: var(--font-size-sm, 0.875rem);
  color: var(--color-text);
  cursor: pointer;
}
.data-source-search-home__tab:hover { border-color: var(--color-primary); }
.data-source-search-home__tab--active {
  border-color: var(--color-primary);
  background: var(--color-primary);
  color: var(--color-text-on-primary);
  font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════
   SECTIONED HOME  (Ui.HomeLayout = "sections")
   One horizontally-scrolling row per category, "shelf" style.
   ══════════════════════════════════════════════════════════════ */

.sections-home__row { margin-bottom: var(--spacing-lg, 24px); }

.sections-home__row-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 var(--spacing-md, 16px);
  margin-bottom: var(--spacing-sm, 8px);
}

.sections-home__row-title {
  font-size: var(--font-size-md, 1rem);
  font-weight: var(--font-weight-heading, 700);
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--spacing-xs, 6px);
}

/* premium-home.css polish (2026-07-26): the catch-all "Other" row (no
   emoji, no real category identity) previously looked like just another
   category — a muted heading reads it correctly as a fallback bucket. */
.sections-home__row-title--muted {
  color: var(--color-text-muted);
}

.sections-home__row-more {
  font-size: var(--font-size-sm, 0.875rem);
  color: var(--color-primary);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  font: inherit;
}

/* premium-home.css polish (2026-07-26): the count reads as metadata
   rather than filler when it carries a bit more visual weight than the
   "See all" label around it. */
.sections-home__row-more-count {
  font-weight: 800;
}

.sections-home__row-scroll {
  overflow-x: auto;
  padding: 0 var(--spacing-md, 16px) var(--spacing-xs, 4px);
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  /* premium-home.css polish (2026-07-26): matches the row's own side
     padding so scroll-snap never leaves the first card half-clipped
     against the viewport edge. */
  scroll-padding-left: var(--spacing-md, 16px);
}

.sections-home__row-scroll::-webkit-scrollbar { display: none; }

/* SectionedHomeView reuses ActivityListRenderer's normal "card" output
   (.activity-grid full of .activity-card) unchanged — this turns that one
   grid into a horizontal shelf purely in CSS, so every card variant
   (locked/quiz/favourite/wall/etc.) keeps working with zero duplicated
   Razor logic. */
.sections-home__row-scroll .activity-grid {
  display: flex;
  gap: var(--spacing-sm, 8px);
}

.sections-home__row-scroll .activity-card {
  flex: 0 0 auto;
  width: 220px;
  scroll-snap-align: start;
}

@media (min-width: 640px) {
  .sections-home__row-scroll .activity-card { width: 260px; }
}

/* ══════════════════════════════════════════════════════════════
   LIVE DATA BLOCK (2026-08-21, v19) — saknade CSS helt sedan
   datakälle-strategins leverans 2026-08-20: LiveDataBlock.razor och
   ScalarDataBlock.razor renderade redan de här klasserna, men ingen
   stilmall fanns för dem någonstans i projektet (grep gav noll
   träffar) — de såg ut som ostylad HTML var de än användes:
   ActivityDetail:s inbakade liveData-block, den gamla LiveDataHomeView,
   och nu även — det här var vad som fick det upptäckt — det nya
   dataResult-kortets inline-expansion (se DataResultCardVariant.razor
   längre ner i den här filen). Återanvänder samma design-tokens som
   .activity-card/.profile-card, så det ser ut som "samma app", inte en
   bortglömd yta.
   ══════════════════════════════════════════════════════════════ */
.live-data-block { display: flex; flex-direction: column; gap: var(--spacing-sm, 10px); }

.live-data-block__status {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm, 8px);
  padding: var(--spacing-md, 16px);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm, 0.875rem);
}
.live-data-block__status--error { color: var(--color-error); }
.live-data-block__spinner { animation: liveDataSpin 0.9s linear infinite; }
@keyframes liveDataSpin { to { transform: rotate(360deg); } }

.live-data-block__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: var(--spacing-sm, 10px);
}

.live-data-block__stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--spacing-sm, 10px);
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface-alt, #f3f4f6);
}
.live-data-block__label {
  font-size: var(--font-size-xs, 0.75rem);
  font-weight: 700;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.live-data-block__value {
  font-size: var(--font-size-lg, 1.125rem);
  font-weight: 800;
  color: var(--color-text);
}
.live-data-block__icon-label {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--spacing-xs, 6px);
  padding: var(--spacing-sm, 10px);
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface-alt, #f3f4f6);
  color: var(--color-text);
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: 700;
}

.live-data-block__list {
  display: flex;
  gap: var(--spacing-sm, 10px);
  overflow-x: auto;
  padding-bottom: 2px;
  scroll-snap-type: x proximity;
}
.live-data-block__list::-webkit-scrollbar { display: none; }
.live-data-block__list-item {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs, 6px);
  min-width: 120px;
  padding: var(--spacing-sm, 10px);
  border-radius: var(--radius-sm, 10px);
  border: 1.5px solid var(--color-border);
  background: var(--color-surface);
  scroll-snap-align: start;
}

.live-data-block__grouped-list { display: flex; flex-direction: column; }
.live-data-block__group {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm, 10px);
  padding: var(--spacing-sm, 8px) var(--spacing-xs, 4px);
  border-bottom: 1px solid var(--color-border);
}
.live-data-block__group:last-child { border-bottom: none; }
.live-data-block__group-key {
  flex: 1;
  font-weight: 700;
  font-size: var(--font-size-sm, 0.875rem);
  color: var(--color-text);
  text-transform: capitalize;
}
.live-data-block__group-minmax {
  font-size: var(--font-size-sm, 0.875rem);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.live-data-block__freshness { font-size: var(--font-size-xs, 0.75rem); color: var(--color-text-muted); }
.live-data-block__freshness--cached { font-style: italic; }

.data-attribution { font-size: var(--font-size-xs, 0.7rem); color: var(--color-text-muted); opacity: 0.8; }


/* ══════════════════════════════════════════════════════════════
   DATA RESULT CARD (2026-08-21, v19) — Activity.CardTemplate ==
   "dataResult", se ActivityCard.razor + DataResultCardVariant.razor.
   Kompakt ikon+värde-kort för en DataQuery-mappad aktivitet — väder,
   aktiekurs, avgångstavla, sportresultat, domänoberoende — med valfri
   inline-expansion (Activity.ExpandInline) istället för ActivityDetail.
   Samma design-tokens som .activity-card, samma cardIn-animation, för
   att kännas som samma korttyp snarare än en bortkopplad specialyta.
   ══════════════════════════════════════════════════════════════ */
.data-result-card {
  width: 100%;
  border-radius: var(--border-radius-lg, 18px);
  border: var(--card-border-width, 1.5px) solid var(--color-border);
  background: var(--color-surface);
  box-shadow: var(--card-shadow);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: box-shadow 180ms ease, transform 120ms ease, border-color 180ms ease;
  animation: cardIn 0.3s cubic-bezier(0.34, 1.1, 0.64, 1) both;
  overflow: hidden;
  /* RÄTTELSE 2026-08-23: en flerkolumns .activity-grid sträcker (CSS
     Grids default align-items:stretch) annars ALLA kort i samma RAD till
     samma höjd som det högsta — så när ett kort expanderas
     (Activity.ExpandInline, .data-result-card__expanded växer kortet) såg
     grannkorten i samma rad ut att "expandera" också, fast bara som tomt
     utrymme, eftersom bara det faktiskt klickade kortet har något
     .data-result-card__expanded-innehåll. align-self: start opt-out:ar
     just DEN HÄR kort-typen ur radsträckningen, så varje korts höjd
     bestäms bara av sitt eget innehåll. Skopat till just .data-result-card
     (inte hela .activity-grid) eftersom det bara är den här korttypen som
     har växande/krympande höjd — vanliga .activity-card har aldrig behövt
     (eller stört sig på) radsträckning. */
  align-self: start;
}
.data-result-card:hover  { box-shadow: var(--card-shadow-hover); border-color: var(--color-primary); }
.data-result-card:active { transform: scale(0.98); }
.data-result-card--done   { opacity: 0.6; }
.data-result-card--locked { cursor: not-allowed; opacity: 0.6; }

.data-result-card__row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm, 12px);
  padding: var(--spacing-sm, 12px) var(--spacing-md, 16px);
}

.data-result-card__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm, 12px);
  background: var(--color-surface-alt, #f3f4f6);
  color: var(--color-primary);
}
.data-result-card__emoji { font-size: 1.5rem; line-height: 1; }

.data-result-card__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.data-result-card__title {
  margin: 0;
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: 700;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.data-result-card__value {
  margin: 0;
  font-size: var(--font-size-md, 1rem);
  font-weight: 800;
  color: var(--color-text);
}

.data-result-card__fav {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}
.data-result-card__fav--active { color: var(--color-error); }

.data-result-card__chevron {
  flex-shrink: 0;
  display: flex;
  color: var(--color-text-muted);
  transition: transform 200ms ease;
}
.data-result-card--expanded .data-result-card__chevron { transform: rotate(180deg); }

.data-result-card__expanded {
  padding: 0 var(--spacing-md, 16px) var(--spacing-md, 16px);
  padding-top: var(--spacing-sm, 12px);
  border-top: 1px solid var(--color-border);
  animation: dataResultExpand 180ms ease both;
}
@keyframes dataResultExpand {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* RÄTTELSE 2026-08-23: .activity-grid går till flera kolumner redan vid
   640px (se premium-desktop.css — filens egen brytpunktstabell kallar
   640px "stor telefon / liten surfplatta", INTE desktop; 900px är där
   "det stora skiftet" till desktop sker). Bra default för en vanlig,
   fritt bläddringsbar .activity-card-grid, men en .data-result-card-lista
   är en TIDSSERIE — timme för timme, dygn för dygn — som läses i ordning
   uppifrån och ned, inte som fristående brickor man bläddrar mellan sida
   vid sida. Två kolumner av tidsordnad data på en telefon-bred skärm blev
   både otydligt (vilken ordning läser man i, ner först eller höger
   först?) och krävde horisontell skroll för att se allt.
   :has(> .data-result-card) riktar bara in sig på grids som FAKTISKT
   innehåller den korttypen — en vanlig .activity-grid med vanliga
   .activity-card rörs inte. !important eftersom premium-desktop.css:s
   bredare regel (högre specificitet OCH laddas efter den här filen, se
   index.html) annars alltid skulle vinna. Under 900px: alltid en kolumn.
   Vid 900px+ (äkta desktop — det var där du sa att sida-vid-sida redan
   såg bra ut): samma auto-fill/minmax(260px) som den vanliga griden
   skulle gett, så desktop-vyn är oförändrad. */
.activity-grid:has(> .data-result-card) {
  grid-template-columns: 1fr !important;
}
@media (min-width: 900px) {
  .activity-grid:has(> .data-result-card) {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)) !important;
  }
}


/* ══════════════════════════════════════════════════════════════
   DATA SOURCE SEARCH HOME — "shelves"-läget (2026-08-21, v19) +
   "stickyTabs"-läget (2026-08-22). Se UiConfig.SearchLayout/
   SearchStickyDataViewRef och DataSourceSearchHomeView.razor. Hyllorna
   återanvänder EXAKT samma "ActivityListRenderer:s .activity-grid →
   horisontell shelf i ren CSS"-mönster som .sections-home__row-scroll
   ovan i den här filen — nya, namnrymda klasser, samma mekanik, samma
   breddvärden (220px / 260px ≥640px / 168px <380px) för visuell
   konsekvens mellan de två hylltyperna i appen.
   ══════════════════════════════════════════════════════════════ */
.data-source-search-home__sticky {
  position: sticky;
  top: var(--header-min-height, 60px);
  z-index: 40;
  padding: var(--spacing-sm, 10px) 0;
  background: var(--color-background);
}

/* 2026-08-22: rubrik för den fastnålade ytan — tidigare renderades
   ingenting alls här (bara <DataViewResult> rakt av), vilket gjorde att
   "nu"-kortet inte gick att skilja från vilken annan vy som helst. En
   liten (icke-animerad — se motivering nedan) prick i packets egen
   --color-primary + vyens eget TitleKey som rubrik räcker för att göra
   klart att det här är den aktuella/"just nu"-vyn, utan att hårdkoda
   ordet för det (helt domänoberoende, som resten av filen). Ingen
   puls-animation: datan är en periodisk ögonblicksbild (hämtas om vid
   sidladdning/platsbyte), inte en sann strömmande live-källa, så en
   pulserande prick hade lovat mer än vyn faktiskt levererar — jmf.
   .voice-recorder__btn--record.is-recording i ui.css, som PULSAR
   eftersom den representerar en verkligt pågående inspelning. */
.data-source-search-home__sticky-title {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs, 6px);
  margin: 0 0 var(--spacing-xs, 6px);
  font-size: var(--font-size-sm, 0.875rem);
  font-weight: 700;
  color: var(--color-text);
}
.data-source-search-home__sticky-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
}

.data-source-search-home__shelf-row { padding: var(--spacing-sm, 10px) 0; }
.data-source-search-home__shelf-header { margin-bottom: var(--spacing-sm, 8px); }
.data-source-search-home__shelf-title {
  margin: 0;
  font-size: var(--font-size-xs, 0.75rem);
  font-weight: 800;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

.data-source-search-home__shelf-scroll {
  overflow-x: auto;
  padding-bottom: var(--spacing-xs, 4px);
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.data-source-search-home__shelf-scroll::-webkit-scrollbar { display: none; }

.data-source-search-home__shelf-scroll .activity-grid {
  display: flex;
  gap: var(--spacing-sm, 8px);
}
.data-source-search-home__shelf-scroll .activity-card,
.data-source-search-home__shelf-scroll .data-result-card {
  flex: 0 0 auto;
  width: 220px;
  scroll-snap-align: start;
}

@media (min-width: 640px) {
  .data-source-search-home__shelf-scroll .activity-card,
  .data-source-search-home__shelf-scroll .data-result-card { width: 260px; }
}

/* ══════════════════════════════════════════════════════════════
   REDUCED-MOTION / SMALL-SCREEN SAFETY
   ══════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .sections-home__row-scroll { scroll-behavior: auto; }
  .data-source-search-home__shelf-scroll { scroll-behavior: auto; }
  /* premium-home.css polish (2026-07-26): magazine-home__hero applies the
     shared entrance keyframe directly (not via the .premium-home-entrance
     utility class), so it needs its own opt-out here too. */
  .magazine-home__hero { animation: none; }
  /* v19 (2026-08-21): samma opt-out för de två nya animerade ytorna. */
  .data-result-card, .data-result-card__expanded, .live-data-block__spinner { animation: none; }
}

@media (max-width: 480px) {
  .magazine-home__hero,
  .magazine-home__hero-body { min-height: 200px; }
}

/* ══════════════════════════════════════════════════════════════
   SMALL-PHONE BREAKPOINT (2026-07-26, premium-home.css strategy §4)
   dashboard-home__grid/dashboard-tile (shared with today-home via the
   same classes) already got their <380px pass in v14-additions.css.
   This covers the three views here that had no dedicated mobile
   breakpoint at all before now: map, search, sections.
   ══════════════════════════════════════════════════════════════ */

@media (max-width: 380px) {
  .map-home__consent-icon { width: 22px; height: 22px; }
  .map-home__consent-title { font-size: var(--font-size-sm, 0.875rem); }
  .map-home__pin-tile { min-height: 64px; } /* larger tap target than the 56px baseline */

  .search-home__field-wrap { padding: var(--spacing-xs, 6px) var(--spacing-sm, 10px); }
  .search-home__shortcuts { gap: var(--spacing-xs, 4px); }

  /* 2026-08-20, datakälle-strategin: samma <380px-pass som resten av den
     här sektionen, se filkommentaren ovan — data-source-search-home delar
     search-home__field-wrap/field/icon (redan justerade två rader ovan)
     och behöver bara egna klasser täckta här. */
  .data-source-search-home__tabs { gap: var(--spacing-xs, 4px); }
  .data-source-search-home__tab { padding: var(--spacing-xs, 6px) var(--spacing-sm, 10px); }
  .data-source-search-home__place-result { padding: var(--spacing-sm, 8px) var(--spacing-sm, 10px); }

  .sections-home__row-scroll .activity-card { width: 168px; }

  /* v19 (2026-08-21): data-result-card/shelves + live-data-block, samma
     <380px-pass. */
  .data-source-search-home__shelf-scroll .activity-card,
  .data-source-search-home__shelf-scroll .data-result-card { width: 168px; }
  .data-result-card__row { padding: var(--spacing-sm, 10px) var(--spacing-sm, 12px); }
  .data-result-card__icon { width: 38px; height: 38px; }
  .live-data-block__grid { grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); }
}
