/* recipe pack — the shared design for every Cisa recipe site.
   Layout, spacing and type scale are fixed here; COLOUR AND TYPEFACE ARE NOT.
   Each site overrides the semantic tokens below from its own site.yaml, which
   base.html emits as an inline :root block after this file. Nothing in the
   rules further down may hardcode a brand colour — if it does, that site's
   brand silently stops applying, which is exactly the bug this layer exists
   to prevent.

   The geometry came from the live pastaa.fi stylesheet
   (pastaa.shared.843359c56.css): the same design at a fraction of the bytes,
   163 KB of Webflow output for a site that uses a few dozen rules. */

:root {
  /* ---- semantic tokens: every site sets these ---------------------------
     canvas      the page ground
     canvas-alt  alternating section band, a shade off canvas
     surface     cards and panels lifted off the ground
     ink         headings, and the fill of solid buttons
     on-ink      text ON ink — not decorative, it has to stay legible there
     body        running text
     accent      the brand colour: links, focus rings, active states
     accent-soft a tint of accent, for hero grounds and badges
     highlight   the wine/offer accent, used sparingly and never as a badge */
  --canvas: #fff;
  --canvas-alt: #fafafa;
  --surface: #fff;
  --ink: #040404;
  --on-ink: #fff;
  --body: #5f5f5f;
  --accent: #156950;
  --accent-soft: #ffe9c7;
  --highlight: #ce106e;

  /* Promo panel runs its own dark palette — it sits on a photograph, so it
     cannot inherit the page ground and stay readable. Sites may override. */
  --promo-bg: #241a12;
  --promo-fade: #1a120bd9;
  --promo-fade-deep: #14100be6;
  --promo-ink: #fff;
  --promo-name: #d8cec3;
  --promo-vol: #bdb2a5;

  /* ---- neutrals: shared, not per-site --------------------------------- */
  --neutral-300: gainsboro;
  --neutral-400: #bfbfbf;
  --neutral-500: #8e8e8e;
  /* Muted TEXT. The pack's greys came from the live Webflow stylesheet, where
     #8e8e8e is used for small print — 3.1:1 on the panel background, well under
     the 4.5:1 WCAG AA needs. This is the lightest neutral that clears it on
     both #fff and #fafafa, so the design barely moves. --neutral-500 stays for
     borders and rules, where contrast rules do not apply. */
  --muted: #737373;
  --neutral-700: #333;
  --shadow: #0000000f;
  --shadow-strong: #04040426;

  /* Icon shapes. Held as variables so the rules can MASK them and paint with
     a token — see .search-button. */
  --icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");

  /* ---- type: families come from site.yaml, the scale does not ---------- */
  --font-display: system-ui, sans-serif;
  --font-body: system-ui, sans-serif;

  /* Aliases. The rules below were written against the Webflow token names and
     there is no gain in renaming 60 declarations to say the same thing. */
  --neutral-100: var(--canvas);
  --neutral-200: var(--canvas-alt);
  --neutral-600: var(--body);
  --neutral-800: var(--ink);
  /* --primary-1 removed 2026-08-08. It aliased --accent-soft and was
     painted both as a solid rule on white (1.3:1, invisible) and as
     eyebrow text on the dark promo band (11-13:1, correct). Use
     --accent for marks on light grounds, --accent-soft for text on
     dark ones. */
  --secondary-2: var(--accent);
  --wine-accent: var(--highlight);
}

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

/* Reserve the scrollbar gutter. No longer load-bearing now the gate is in the
   flow rather than an overlay that hid overflow, but it still stops any future
   modal from reflowing the page sideways. */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  color: var(--neutral-600);
  background: var(--neutral-100);
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1.667;
}

img { max-width: 100%; height: auto; }
a { color: inherit; }

h1, h2, h3, h4 { font-family: var(--font-display); color: var(--neutral-800); margin: 0 0 16px; font-weight: 500; text-wrap: balance; }
h1 { font-size: 42px; line-height: 1.26; margin-bottom: 24px; }
h2 { font-size: 32px; line-height: 1.4; }
h3 { font-size: 26px; line-height: 30px; }
.heading-size-h4 { font-size: 22px; font-weight: 500; line-height: 1.27273; }
.no-margin { margin-bottom: 0; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
:focus-visible { outline: 2px solid var(--wine-accent); outline-offset: 2px; }

/* ---------------------------------------------------------------- layout */
.container-default { max-width: 1270px; margin: 0 auto; padding: 0 24px; }
.container-default.narrow { max-width: 820px; }
.section { padding: 120px 0; }
.narrow-section { padding: 140px 0; }
.narrow-section.recipes { padding-bottom: 120px; }
.bg-neutral-100 { background: var(--neutral-100); }
.bg-neutral-200 { background: var(--neutral-200); }
.divider { width: 100%; height: 1px; background: var(--neutral-300); }
.divider.footer { margin-top: 48px; }
.title-container.hc-flex {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: center; gap: 16px; margin-bottom: 48px;
}
.lead { font-size: 20px; max-width: 65ch; }

.breadcrumbs { font-size: 15px; color: var(--muted); margin-bottom: 24px; }
.breadcrumbs a { color: var(--neutral-600); text-decoration: none; }
.breadcrumbs a:hover { color: var(--neutral-800); }

/* ---------------------------------------------------------------- header */
.header {
  width: 100%; max-width: 1222px; margin: 0 auto; padding: 40px 0;
  background: var(--surface); box-shadow: 0 6px 28px var(--shadow); position: relative; z-index: 5;
}
.header-container { max-width: 1222px; margin: 0 auto; padding: 0 32px; }
.header-wrapper { display: flex; justify-content: space-between; align-items: center; gap: 24px; }
.header-logo { width: 150px; transition: opacity .35s; }
.header-logo:hover { opacity: .6; }

.header-search { position: relative; margin: 0; }
.search-input {
  min-width: 350px; min-height: 56px; padding: 20px 20px 20px 52px;
  background: var(--neutral-200); border: 1px solid transparent;
  color: var(--neutral-800); font: inherit; font-size: 17px; line-height: 1.2;
  text-transform: lowercase; transition: background-color .2s;
}
.search-input:hover, .search-input:focus { background: color-mix(in srgb, var(--ink) 6%, var(--surface)); }
.search-input::placeholder { color: var(--neutral-700); font-size: 18px; }
.search-button {
  position: absolute; inset: 18px auto 18px 20px;
  width: 22px; max-width: 22px; min-height: 22px; padding: 0; border: 0; cursor: pointer;
  /* Masked, not a coloured background-image: a data URI cannot read a CSS
     variable, so an inlined stroke colour would keep pastaa's near-black on
     every other brand. The mask carries the shape, --ink carries the colour. */
  background: var(--ink);
  -webkit-mask: var(--icon-search) no-repeat 50% / contain;
  mask: var(--icon-search) no-repeat 50% / contain;
}
.search-input.search-page { min-height: 64px; padding: 23px 60px 23px 18px; border-color: var(--neutral-300); }
.search-button.search-page { width: 32px; max-width: 32px; min-height: 32px; left: auto; right: 20px; }
.hero-search { position: relative; max-width: 560px; margin-top: 32px; }
.hero-search .search-input { width: 100%; min-width: 0; }

/* ---------------------------------------------------------------- buttons */
.button-secondary {
  display: inline-block; padding: 24px 42px;
  border: 1px solid var(--ink); background: transparent; color: var(--neutral-800);
  font-size: 18px; line-height: 1; text-align: center; text-transform: lowercase;
  text-decoration: none; transition: color .3s, background-color .3s, border-color .2s;
}
.button-secondary:hover { background: var(--neutral-800); color: var(--neutral-100); border-color: transparent; }
.button-secondary.small { padding: 20px 24px; font-size: 16px; line-height: 18px; }
.button-secondary.category {
  padding: 20px 24px; margin: 0; border: 0; background: var(--neutral-100);
  color: var(--neutral-700); font-size: 16px; line-height: 18px;
  box-shadow: 0 4px 18px var(--shadow);
}
.button-secondary.category:hover, .button-secondary.category.is-current { background: var(--neutral-800); color: var(--neutral-100); }
.category-nav { display: flex; flex-wrap: wrap; gap: 14px; margin: 32px 0 56px; }

/* ---------------------------------------------------------------- recipe */
.recipe-hero { min-height: 60vh; background: var(--neutral-300) 50% / cover no-repeat; }
.recipe-details-wrapper.split { display: flex; align-items: flex-start; margin-top: -200px; }
.main-recipe-card {
  width: 100%; max-width: 72%; padding: 92px 72px;
  background: var(--neutral-100); box-shadow: 0 4px 18px var(--shadow);
}
.recipe-lead { font-size: 20px; }
.about-the-recipe-card {
  flex: none; width: 100%; max-width: 30%; margin-left: 40px; padding: 48px 56px;
  background: var(--neutral-100); box-shadow: 0 4px 18px var(--shadow);
  position: sticky; top: 32px; align-self: flex-start;
}
.about-the-recipe-item { display: flex; align-items: center; text-transform: lowercase; }
.about-the-recipe-item.recipe-page { margin-bottom: 24px; }
.about-the-recipe-text { color: var(--neutral-800); font-weight: 500; }
.about-recipe-content { display: flex; gap: 18px; flex-wrap: wrap; }

.tabs-menu { display: flex; margin-bottom: 28px; }
.tab-link {
  width: 100%; padding: 12px; border: 0; cursor: pointer;
  background: var(--neutral-100); box-shadow: 0 4px 18px var(--shadow);
  color: var(--neutral-800); font: inherit; font-size: 18px; text-align: center;
  transition: background-color .2s, color .2s, box-shadow .2s;
}
.tab-link:hover { background: var(--neutral-800); color: var(--neutral-100); }
.tab-link.is-current { background: var(--neutral-800); color: var(--neutral-100); box-shadow: none; }
.tab-link.center-tab { margin: 0 32px; text-transform: lowercase; }
.recipe-tab[hidden] { display: none; }

.rich-text h2, .rich-text h3 { margin-top: 48px; }
.rich-text li { margin-bottom: 12px; }
.rich-text ol, .rich-text ul { margin-bottom: 26px; padding-left: 22px; }
.rich-text a { color: var(--secondary-2); }

/* ------------------------------------------------------------ wine card */
.wine-block { margin-top: 56px; }
.wine-availability { margin: 0; font-size: 15px; color: var(--muted); }
.wine-availability strong { color: var(--neutral-800); }
.wine-card-wrapper {
  display: flex; gap: 20px; margin-top: 20px; padding: 20px 25px;
  background: var(--surface); box-shadow: 0 4px 18px var(--shadow);
}
.left-side-card { display: flex; gap: 15px; max-width: 680px; }
.image-2 { max-height: 140px; width: auto; object-fit: contain; }
.title-card-wrapper { display: flex; flex-direction: column; justify-content: center; gap: 10px; }
.wine-title { color: var(--neutral-800); font-size: 26px; line-height: 120%; }
.wine-type-country { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.wine-type { padding: 0 6px; background: var(--wine-accent); }
.wine-text { color: var(--on-ink); font-size: 12px; line-height: 24px; letter-spacing: -.25px; }
.wine-text.dark { color: var(--muted); }
.wine-text.black { color: var(--ink); line-height: 18px; }
.wine-note { font-size: 15px; font-style: italic; color: var(--neutral-600); }
.right-side-card { display: flex; flex-direction: column; justify-content: space-between; align-items: flex-end; gap: 10px; width: 50%; }
.wine-price-size { display: flex; flex-direction: column; align-items: flex-end; }
.wine-price { color: var(--ink); font-size: 44px; line-height: 100%; white-space: nowrap; }
.wine-size { color: var(--muted); line-height: 100%; }
.wine-unavailable { max-width: 22ch; text-align: right; font-size: 14px; color: var(--muted); }
/* The badge is shown only for a verified rating (enforced in v_wine_card).
   Live pastaa.fi hides this element outright, so a LÖYTÖ never reached a reader. */
.wine-badge-wrapper { display: flex; align-items: center; gap: 8px; }
.wine-badge { max-width: 32px; }
.wine-badge-text { font-size: 13px; font-weight: 600; color: var(--secondary-2); text-transform: uppercase; letter-spacing: .4px; }

/* ------------------------------------------------------------ card grid */
.latest-recipes-grid { display: grid; grid-template-columns: repeat(3, 1fr); column-gap: 26px; row-gap: 60px; }
.recipe-card-wrapper {
  display: block; height: 100%; color: var(--neutral-600); text-decoration: none;
  background: var(--surface); box-shadow: 0 4px 18px var(--shadow); transition: transform .3s;
}
.recipe-card-wrapper:hover { transform: scale(.94); }
.image-wrapper.card { display: flex; justify-content: center; align-items: center; }
.card-image { width: 100%; max-height: 260px; object-fit: cover; }

/* A wine card carries a bottle, not a dish, and the two cannot share a crop
   rule. `width:100% + object-fit:cover` fills a landscape card from a portrait
   cut-out by cropping everything but the middle of the glass — which is why
   searching "el abuelo" returned three black slabs.
   PIN THE HEIGHT, NEVER THE WIDTH: the markettiviini cut-outs are not a
   uniform 300x600, they range 136x585 to 295x459, so a width-pinned box
   renders a narrow bottle nearly 400px tall.
   Inert on the other eleven sites: nothing emits .is-wine unless the search
   index carries wine entries. */
.recipe-card-wrapper.is-wine .image-wrapper.card { padding: 18px 0; }
.recipe-card-wrapper.is-wine .card-image {
  width: auto; max-width: 70%; height: 260px; object-fit: contain;
}
.recipe-card-details { padding: 24px 30px; }
.recipe-card-details h3 { font-size: 22px; line-height: 1.3; }
.recipe-card-details p { font-size: 16px; }
.small-accent-line { width: 16%; min-height: 2px; margin-bottom: 16px; background: var(--accent); }
.mg-bottom-56px { margin-bottom: 24px; }
.empty, .search-status { color: var(--muted); }

/* ---------------------------------------------------------------- footer */
.footer { border-top: 1px solid var(--neutral-300); background: var(--surface); }
.footer .container-default { padding-top: 80px; padding-bottom: 40px; }
.footer-top { display: flex; flex-wrap: wrap; gap: 60px; justify-content: space-between; }
.footer-newsletter { max-width: 46ch; }
.footer-cats ul { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 24px; margin: 0; padding: 0; list-style: none; }
.footer-cats a { color: var(--neutral-600); text-decoration: none; }
.footer-cats a:hover { color: var(--neutral-800); }
.footer-bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; font-size: 15px; }
.footer-bottom p { margin: 8px 0; }


/* ------------------------------------------------------------ responsive */
@media (max-width: 991px) {
  .latest-recipes-grid { grid-template-columns: 1fr 1fr; }
  .recipe-details-wrapper.split { flex-direction: column; margin-top: -120px; }
  .main-recipe-card, .about-the-recipe-card { max-width: 100%; }
  .about-the-recipe-card { margin: 24px 0 0; position: static; }
  .main-recipe-card { padding: 56px 40px; }
  .search-input { min-width: 220px; }
}
@media (max-width: 767px) {
  h1 { font-size: 32px; }
  h2 { font-size: 26px; }
  .section, .narrow-section { padding: 72px 0; }
  .latest-recipes-grid { grid-template-columns: 1fr; }
  .header { padding: 20px 0; }
  .header-container { padding: 0 20px; }
  .header-wrapper { flex-wrap: wrap; }
  .header-search { width: 100%; }
  .main-recipe-card { padding: 32px 20px; }
  .wine-card-wrapper { flex-direction: column; padding: 15px; }
  .left-side-card { flex-direction: column; }
  .right-side-card { width: 100%; align-items: flex-start; }
  .wine-price-size { flex-direction: row; align-items: flex-end; gap: 15px; }
  .wine-unavailable { text-align: left; }
  .tab-link.center-tab { margin: 0 8px; }
  .tab-link { font-size: 15px; }
  .recipe-hero { min-height: 40vh; }
}
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .recipe-card-wrapper:hover { transform: none; }
}

/* ======================================================================
   Added after first review: consent + age gate, promo strip, hero
   scroller, newsletter, search typeahead, larger mobile bottle.
   ====================================================================== */

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--neutral-800); color: var(--on-ink); padding: 12px 18px;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------- age gate + consent */
/* In the flow, server-rendered, first thing in <main>. On a first visit this IS
   the first paint, so nothing moves. The <html> class is set by a blocking
   script in <head> before paint, so a returning reader never sees a flash. No
   overlay and no overflow:hidden — the old version's scrollbar removal was
   itself a layout shift, on every single first visit. */
.agegate { display: none; }
/* Compact by design. This is a gate, not a landing page: it asks one question
   and the reader answers it in about two seconds. Sized so the whole panel
   plus the header fits in roughly a third of a laptop viewport, leaving the
   site visible underneath. */
.agegate-inner { padding: 30px 24px 34px; max-width: 820px; margin: 0 auto; }
.agegate-kicker {
  margin: 0 0 8px; font-size: 12px; font-weight: 600; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--wine-accent);
}
/* 26px keeps the question on ONE line at this max-width in all four of the
   estate's display faces. At 38px it wrapped in Poppins and DM Serif Display,
   which alone cost 45px of height. */
.agegate h1, .agegate-title {
  font-size: 26px; line-height: 1.25; margin: 0 0 8px;
  font-family: var(--font-display); color: var(--ink); font-weight: 500;
  text-wrap: balance;
}
.agegate-lead { font-size: 16px; color: var(--neutral-600); max-width: 64ch; margin: 0 0 18px; }
.agegate-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
.agegate-row button {
  padding: 12px 20px; border: 1px solid var(--neutral-800); cursor: pointer;
  background: var(--surface); color: var(--neutral-800); font: inherit; font-size: 15px;
  transition: background-color .2s, color .2s;
}
.agegate-row button:hover { background: var(--neutral-800); color: var(--on-ink); }
.agegate-yes { background: var(--neutral-800); color: var(--on-ink); }
.agegate-yes:hover { background: var(--wine-accent); border-color: var(--wine-accent); }
.agegate-no { border-style: dashed; color: var(--muted); }
.agegate-cats {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px;
  border: 0; border-top: 1px solid var(--neutral-300); margin: 0 0 12px; padding: 14px 0 0;
}
.agegate-cats legend {
  padding: 0; font-size: 12px; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--muted);
}
.agegate-cats label { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--neutral-700); }
.agegate-cats input { accent-color: var(--wine-accent); width: 18px; height: 18px; }
.agegate-note { margin: 0; font-size: 13px; line-height: 1.45; color: var(--muted); max-width: 72ch; }

/* Which state the page is in — decided before paint by the head script. */
.consent-unknown #agegate { display: block; }
/* NOT .consent-unknown: a reader who has not answered yet still sees the page,
   with the banner over it. Google arrives as a first-time visitor on every
   crawl and can never click, so hiding the content for that state meant every
   page indexed as 108 words of age-verification copy instead of the recipe.
   Valvira accepts the age confirmation inside the cookie banner — and a banner
   is something you put ON a page, not instead of one.
   consent-denied stays: someone who has said they are under 18 should not see
   alcohol content. */
.consent-denied  .site-content,
.consent-denied  .header,
.consent-denied  .footer { display: none; }
.consent-denied #agegate-denied { display: block; }

@media (max-width: 767px) {
  .agegate-inner { padding: 24px 20px 28px; }
  .agegate h1, .agegate-title { font-size: 22px; }
  .agegate-lead { font-size: 15px; }
  .agegate-row { flex-direction: column; }
  .agegate-row button { width: 100%; }
}

/* ------------------------------------------------------- promo banner */
/* Front page only. The scene is a background plate; the bottle and every
   number sit on top as real elements, so nothing is baked in. */
.promo { position: relative; overflow: hidden; background: var(--promo-bg); isolation: isolate; }
.promo-scene { position: absolute; inset: 0; z-index: -2; }
.promo-scene img { width: 100%; height: 100%; object-fit: cover; object-position: 22% 50%; }
/* Scrim only over the copy side, so the food keeps its contrast. */
.promo::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, color-mix(in srgb, var(--promo-bg) 0%, transparent) 38%, var(--promo-fade) 60%, var(--promo-fade-deep) 100%);
}
.promo-inner {
  display: grid; grid-template-columns: 1fr auto minmax(0, 46ch);
  align-items: center; gap: 40px;
  padding-top: 44px; padding-bottom: 44px; min-height: 380px;
}
.promo-bottle { grid-column: 2; }
.promo-bottle img {
  display: block; height: 300px; width: auto;
  filter: drop-shadow(0 24px 34px #0000008c);
}
.promo-copy { grid-column: 3; color: var(--promo-ink); }
.promo-eyebrow {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 10px; font-size: 12px; font-weight: 600;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--accent-soft);
}
/* Viinilehti marks in the banner.

   These marks are supplied as dark ink for a light page, and the banner ground
   is near-black, so as supplied they were invisible. The banner therefore
   knocks them out to solid white rather than tinting them a second colour:
   the mark keeps its exact shape and proportions, which is what a
   certification mark has to keep, and white is legible on every scene plate. */
.promo-marks {
  display: inline-flex; align-items: center; gap: 15px; margin: 0 0 14px;
}
.promo-marks .rz-badge-img { width: 46px; height: 46px; display: block; }
.promo-marks .rz-rating { display: inline-flex; flex-direction: column; gap: 3px; }
.promo-marks .rz-rating-mark {
  width: 82px; height: auto; display: block;
  filter: brightness(0) invert(1);
}
.promo-marks .rz-stars { display: inline-flex; gap: 1px; }
.promo-marks .rz-stars svg { width: 15px; height: 14px; }
.promo-marks .rz-stars .on  { fill: #ffffff; }
.promo-marks .rz-stars .off { fill: rgba(255, 255, 255, .3); }
.promo-headline {
  margin: 0 0 12px; font-size: 32px; line-height: 1.15; color: var(--promo-ink);
  text-wrap: balance;
}
.promo-name { margin: 0 0 20px; font-size: 15px; color: var(--promo-name); }
.promo-foot { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.promo-price { margin: 0; font-size: 38px; line-height: 1; color: var(--promo-ink); white-space: nowrap; }
.promo-vol { display: block; margin-top: 8px; font-size: 13px; color: var(--promo-vol); letter-spacing: .2px; }

/* ------------------------------------------------------ hero scroller */
.hero-scroll { background: var(--neutral-200); padding: 40px 0 80px; }
.hero-scroll-inner { display: block; }
.hero-panel { padding: 48px 0; }
.hero-panel h2 { font-size: 38px; }
.hero-panel p { max-width: 60ch; }
.hero-panel-img { width: 100%; margin: 24px 0; }
.hero-stage { display: none; }
.button-primary {
  display: inline-block; margin-top: 24px; padding: 20px 34px;
  background: var(--neutral-800); color: var(--on-ink); font-size: 17px;
  text-decoration: none; transition: background-color .25s;
}
.button-primary:hover { background: var(--wine-accent); }

/* Phones and tablets: the image pins to the top and cross-fades while the
   text panels scroll underneath. Applied in CSS, not by a JS-added class —
   restructuring after first paint is what CLS measures. */
@media (max-width: 991px) {
  .hero-scroll .hero-scroll-inner { display: flex; flex-direction: column; }
  .hero-scroll .hero-panel-img { display: none; }
  .hero-scroll .hero-stage {
    display: block; order: -1;              /* stage is last in source order */
    position: sticky; top: 12px; z-index: 1;
    height: 38vh; margin-bottom: 28px;
  }
  .hero-scroll .hero-shot {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0; transition: opacity .45s ease;
  }
  .hero-scroll .hero-shot.is-current { opacity: 1; }
  .hero-scroll .hero-panels { display: flex; flex-direction: column; }
  .hero-scroll .hero-panel {
    min-height: 52vh; display: flex; flex-direction: column; justify-content: center;
    padding: 0;
  }
}

/* Desktop: sticky cross-fading image column beside the text. CSS-only for the
   same reason. */
@media (min-width: 992px) {
  .hero-scroll .hero-scroll-inner {
    display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: start;
  }
  .hero-scroll .hero-panel { min-height: 78vh; display: flex;
    flex-direction: column; justify-content: center; padding: 0; }
  .hero-scroll .hero-panel-img { display: none; }
  .hero-scroll .hero-stage {
    display: block; position: sticky; top: 12vh; height: 76vh;
  }
  .hero-scroll .hero-shot {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0; transition: opacity .5s ease;
  }
  .hero-scroll .hero-shot.is-current { opacity: 1; }
}

/* --------------------------------------------------- search typeahead */
.header-search, .hero-search { position: relative; }
.typeahead {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
  margin: 0; padding: 6px 0; list-style: none;
  background: var(--surface); border: 1px solid var(--neutral-300);
  box-shadow: 0 10px 32px var(--shadow-strong); max-height: 60vh; overflow-y: auto;
}
.typeahead[hidden] { display: none; }
.typeahead-item a, .typeahead-more a {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 14px; color: var(--neutral-700); text-decoration: none; font-size: 15px;
}
.typeahead-item img { width: 56px; height: 40px; object-fit: cover; flex: none; }
/* Same reason as the card: a 56x40 cover crop of a bottle is a sliver of glass. */
.typeahead-item.is-wine img { object-fit: contain; }
.typeahead-item.is-active a, .typeahead-item a:hover,
.typeahead-more.is-active a, .typeahead-more a:hover {
  background: var(--neutral-200); color: var(--neutral-800);
}
.typeahead-more a { font-size: 14px; color: var(--wine-accent); border-top: 1px solid var(--neutral-300); }

/* -------------------------------------------------------- newsletter */
.newsletter-form { margin-top: 16px; }
.newsletter-row { display: flex; gap: 0; max-width: 420px; }
.newsletter-row input {
  flex: 1; min-width: 0; padding: 14px 16px;
  border: 1px solid var(--neutral-300); border-right: 0;
  font: inherit; font-size: 16px; background: var(--surface); color: var(--neutral-800);
}
.newsletter-row button {
  padding: 14px 26px; border: 0; background: var(--neutral-800); color: var(--on-ink);
  font: inherit; font-size: 16px; text-transform: lowercase; cursor: pointer;
  transition: background-color .2s;
}
.newsletter-row button:hover { background: var(--wine-accent); }
.newsletter-consent {
  display: flex; gap: 10px; margin-top: 12px; max-width: 46ch;
  font-size: 13px; line-height: 1.5; color: var(--muted);
}
.newsletter-consent input { margin-top: 3px; accent-color: var(--wine-accent); }
/* Charlie swaps the form for its own thank-you box on success. */
.charlie-message, [data-charlie-message] { margin-top: 12px; font-size: 14px; color: var(--secondary-2); }

/* ------------------------------------------------------- responsive */
@media (max-width: 991px) {
  .promo-inner { grid-template-columns: auto minmax(0, 1fr); gap: 28px; min-height: 0; }
  .promo-bottle { grid-column: 1; }
  .promo-copy { grid-column: 2; }
  .promo-bottle img { height: 230px; }
  .promo-headline { font-size: 26px; }
  .promo::after { background: linear-gradient(90deg, var(--promo-fade) 0%, var(--promo-fade-deep) 55%); }
  .hero-panel h2 { font-size: 30px; }
}

/* Phone. This opener was MISSING: the rules below sat at top level with an
   orphan closing brace after them, so the phone promo layout — scene as a
   150px banner strip, gradient off — applied at every viewport width. The
   promo has therefore never rendered as designed on desktop, on any site.
   Caught during the kanareseptit build; the same defect is in packs/pastaa. */
@media (max-width: 767px) {
  /* Phone: the scene becomes a banner image above the copy rather than a
     background it has to fight for contrast against. */
  .promo { display: flex; flex-direction: column; }
  .promo-scene { position: static; }
  .promo-scene img { height: 150px; }
  .promo::after { display: none; }
  .promo-inner { grid-template-columns: auto 1fr; gap: 20px; padding: 24px; background: var(--promo-bg); }
  .promo-bottle img { height: 180px; }
  .promo-headline { font-size: 22px; }
  .promo-price { font-size: 30px; }
  .promo-foot { gap: 14px; }
  .newsletter-row { max-width: 100%; }
  .typeahead { max-height: 50vh; }

  /* The bottle shot was reading smaller than the original on a phone.
     Live pastaa.fi lets it grow to 200px there; match that and let it
     scale down rather than crop. */
  .image-2 { max-height: 200px; object-fit: scale-down; }
}

/* Home: the h1 rides at the top of the hero-banner section, not in a hero
   block of its own — the reader meets the categories immediately. */
.hero-title { font-size: 30px; margin: 0; padding: 40px 0 8px; }
.browse .hero-search { margin-bottom: 40px; }
.browse .category-nav { margin-bottom: 0; }
@media (max-width: 767px) { .hero-title { font-size: 24px; padding: 28px 0 4px; } }

/* --------------------------------------------------- official Alko button */
/* Alko supplies this artwork to importers. It is used as delivered: no
   recolouring, no cropping, no substitute wording. Only the hit area and
   spacing around it are ours. */
.alko-button {
  display: inline-block; line-height: 0; text-decoration: none;
  transition: opacity .2s, transform .2s;
}
.alko-button:hover { opacity: .85; transform: translateY(-1px); }
.alko-button img { display: block; width: 200px; height: auto; }
/* On the dark banner the button's own white plate is what separates it. */
.promo-alko img { box-shadow: 0 6px 18px #0000005c; }
@media (max-width: 767px) {
  .alko-button img { width: 180px; }
}

/* ------------------------------------------------ "is it in my Alko?" */
.storecheck { margin-top: 32px; padding: 24px; background: var(--neutral-200); }
.storecheck-title { margin: 0 0 16px; font-size: 20px; }
.storecheck-controls { display: flex; flex-wrap: wrap; gap: 12px; }
.storecheck-open, .storecheck-geo {
  padding: 14px 22px; border: 1px solid var(--neutral-800); cursor: pointer;
  background: var(--surface); color: var(--neutral-800); font: inherit; font-size: 15px;
  text-transform: lowercase; transition: background-color .2s, color .2s;
}
.storecheck-open:hover, .storecheck-geo:hover { background: var(--neutral-800); color: var(--on-ink); }
.storecheck-geo { border-style: dashed; }

.storecheck-picker { margin-top: 16px; }
.storecheck-picker input {
  width: 100%; max-width: 420px; padding: 12px 14px;
  border: 1px solid var(--neutral-300); font: inherit; font-size: 16px;
}
.storecheck-list {
  list-style: none; margin: 8px 0 0; padding: 0; max-width: 420px;
  max-height: 300px; overflow-y: auto; background: var(--surface);
  border: 1px solid var(--neutral-300);
}
.storecheck-item {
  display: flex; flex-direction: column; gap: 2px; width: 100%;
  padding: 10px 14px; border: 0; border-bottom: 1px solid var(--neutral-200);
  background: none; font: inherit; text-align: left; cursor: pointer;
}
.storecheck-item:hover { background: var(--neutral-200); }
/* A quiet mark on shops that have it — the reader can often stop reading here. */
.storecheck-item.in-stock { border-left: 3px solid var(--secondary-2); }
.sc-name { color: var(--neutral-800); font-size: 15px; }
.sc-city { color: var(--muted); font-size: 13px; }

.storecheck-result { margin: 16px 0 0; font-size: 16px; min-height: 1.4em; }
.storecheck-result.yes { color: var(--secondary-2); font-weight: 500; }
.storecheck-result.no  { color: var(--neutral-700); }

.storecheck-subs { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--neutral-300); }
.storecheck-subs-lead { margin: 0 0 14px; font-size: 15px; color: var(--neutral-700); max-width: 56ch; }
.storecheck-subs ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.sub {
  display: grid; grid-template-columns: 60px 1fr auto; align-items: center;
  gap: 16px; padding: 14px 16px; background: var(--surface);
  border: 1px solid var(--neutral-300); transition: border-color .2s;
}
.sub:hover { border-color: var(--neutral-800); }
.sub-bottle { width: 60px; height: auto; max-height: 128px; object-fit: contain; }
.sub-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.sub-name { color: var(--neutral-800); font-size: 16px; line-height: 1.3; }
.sub-meta { color: var(--muted); font-size: 13px; }
.sub-badge {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 2px;
  font-size: 12px; font-weight: 600; letter-spacing: .3px;
  text-transform: uppercase; color: var(--secondary-2);
}
.sub-buy { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.sub-price { color: var(--neutral-800); font-size: 20px; white-space: nowrap; }

@media (max-width: 767px) {
  .storecheck { padding: 18px; }
  .storecheck-controls { flex-direction: column; }
  .storecheck-open, .storecheck-geo { width: 100%; }
  .storecheck-picker input, .storecheck-list { max-width: 100%; }
  .sub { grid-template-columns: 52px 1fr; gap: 12px; }
  .sub-bottle { width: 52px; }
  .sub-buy { grid-column: 1 / -1; flex-direction: row; align-items: center;
             justify-content: space-between; }
}
.storecheck.order-only p { margin: 0; font-size: 15px; color: var(--neutral-600); max-width: 60ch; }

/* No cross-fade wanted: fall back to the plain stack, each panel with its own
   image. Stated in CSS so it costs no layout shift either. */
@media (prefers-reduced-motion: reduce) {
  .hero-scroll .hero-scroll-inner { display: block; }
  .hero-scroll .hero-panel { min-height: 0; padding: 48px 0; display: block; }
  .hero-scroll .hero-panel-img { display: block; }
  .hero-scroll .hero-stage { display: none; }
}
.storecheck-subs-lead { margin: 0 0 12px; font-size: 15px; color: var(--neutral-700); max-width: 56ch; }

/* ------------------------------------------------- answer pages (listicle)

   The format that earns AI Overview citations: 239 impressions per page
   against 77 for a recipe page, measured on the flagship's GSC export.

   The answer block is styled to be the first thing a human eye lands on for
   the same reason it is the first substantial text in the DOM — the page
   exists to answer one question, and burying that under prose is how the
   citation goes to somebody else. */
.lst-answer {
  border-left: 4px solid var(--brand, #9c1c35);
  background: var(--surface-2, #f7f5f2);
  padding: 18px 22px;
  margin: 24px 0 32px;
  border-radius: 0 6px 6px 0;
}
.lst-answer-text {
  margin: 0;
  font-size: 1.15rem;
  line-height: 1.55;
  font-weight: 500;
}

/* Tables carry the per-variant numbers, which is the second thing lifted.
   They scroll inside their own box so a wide table never makes the whole
   document scroll sideways on a phone. */
.lst-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 20px 0;
  font-variant-numeric: tabular-nums;
}
.lst-body table th,
.lst-body table td {
  text-align: left;
  padding: 9px 12px;
  border-bottom: 1px solid var(--neutral-300, #e5e5e5);
}
.lst-body table th {
  background: var(--surface-2, #f7f5f2);
  font-weight: 600;
}
.lst-body > table { display: block; overflow-x: auto; }

.lst-faq { margin-top: 40px; }
.lst-faq details {
  border-bottom: 1px solid var(--neutral-300, #e5e5e5);
  padding: 12px 0;
}
.lst-faq summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.lst-faq summary::-webkit-details-marker { display: none; }
.lst-faq summary::before { content: "▾ "; }
.lst-faq details p { margin: 10px 0 2px; }

.lst-recipes { margin-top: 40px; }
.lst-recipe-list { margin: 0; padding-left: 20px; }
.lst-recipe-list li { margin: 6px 0; }

.lst-topics { margin-top: 36px; display: flex; flex-wrap: wrap; gap: 8px; }
.lst-topic {
  font-size: 13px;
  color: var(--neutral-600, #666);
  background: var(--surface-2, #f7f5f2);
  border-radius: 999px;
  padding: 4px 11px;
}

/* Per-site variation, driven by `listicle_variant` in site.yaml. One shared
   template; only the treatment changes. Variant 1 is the default and is what
   the flagship uses. */
.lst[data-variant="2"] .lst-answer {
  border-left: 0;
  border-top: 3px solid var(--brand, #9c1c35);
  background: transparent;
  border-radius: 0;
  padding: 16px 0 0;
}
.lst[data-variant="2"] .lst-body table th {
  background: transparent;
  border-bottom: 2px solid var(--brand, #9c1c35);
}
.lst[data-variant="3"] .lst-answer {
  border: 1px solid var(--neutral-300, #e5e5e5);
  border-left: 4px solid var(--brand, #9c1c35);
  background: transparent;
  border-radius: 6px;
}
.lst[data-variant="3"] .lst-body table tr:nth-child(even) td {
  background: var(--surface-2, #f7f5f2);
}

/* The wine follow-up. Closed by default and phrased as a question, so a reader
   who came for the cooking time is never shown a bottle they did not ask for. */
.lst-wine { margin-top: 28px; }
.lst-wine-details {
  border: 1px solid var(--neutral-300, #e5e5e5);
  border-radius: 6px;
  padding: 12px 16px;
}
.lst-wine-details > summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.lst-wine-details > summary::-webkit-details-marker { display: none; }
.lst-wine-details > summary::before { content: "🍷 "; }
.lst-wine-details[open] > summary { margin-bottom: 14px; }

/* ============================================== the Rosa-shape wine card
 * Ported from the flagship (task: same card estate-wide). Selectors and
 * markup match sites/rosaviinijaruoka exactly; colours ride each site's own
 * token set via var(--accent)/var(--ink)/var(--font-display) fallbacks.
 */
/* ============================================================ the wine card
 * Recipe -> "Viinisuositus". Three columns: bottle, the reading column, and a
 * buy rail. Same shape as the client's own /viinit/ listing card, which is the
 * one they asked to keep, with a second CTA added to the rail.
 *
 * The old card gave Viinilehti's price/quality mark a 74px column of its own,
 * where it was the biggest element on the card while the rating it certifies
 * was not rendering at all. Here every mark — food pairings, certifications,
 * the rating, the price/quality badge — shares ONE 26px row, so the card says
 * more in less height and nothing outshouts the wine's name.
 */
/* 700px column minus its padding leaves 660px for the whole card, so the
   reading column is what is left after the bottle and the rail — 100 + 200 + the
   gaps gives it ~320px, enough for a two-word wine name on one line. The live
   /viinit/ card runs at full page width and can afford wider outer columns; this
   one cannot, and the name is the thing that must not wrap. */
.rzw { display: grid; grid-template-columns: 124px minmax(0, 1fr) 200px;
  gap: 20px; align-items: start;
  padding: 22px 24px; background: #fff;
  border: 1px solid rgba(172, 20, 48, .28); }
/* The bottle carries the card. On the client's original it is the tallest thing
   in the row and the eye lands on it first; at 180px it was shorter than the
   text beside it and read as a thumbnail. HEIGHT box, so a bag-in-box widens
   into the 124px column instead of towering over a bottle. */
.rzw-shot { height: 240px; display: flex; align-items: center; justify-content: center; }
.rzw-shot img { max-height: 240px; max-width: 100%; width: auto; height: auto; }
/* Two columns for a grocery wine: bottle, then everything else. The buy block
   sits under the name, in the space the tasting note occupies on an Alko card,
   and the chain buttons run across rather than stacking in a 200px rail. */
.rzw.is-marketti { grid-template-columns: 124px minmax(0, 1fr); }
.rzw-buy.rzw-buy-inline { display: flex; flex-direction: row; align-items: center;
  flex-wrap: wrap; gap: 8px 28px; margin: 14px 0 0; }
.rzw-buy.rzw-buy-inline .rz-price { display: flex; align-items: baseline; }
.rzw-buy.rzw-buy-inline .rz-price-vol { align-self: flex-end; margin-left: -18px;
  padding-bottom: 3px; }
.rzw-buy.rzw-buy-inline .rz-chains { flex-direction: row; flex-wrap: wrap; width: auto;
  margin: 0; gap: 10px; }
.rzw-buy.rzw-buy-inline .rz-chains li { width: auto; }
.rzw-buy.rzw-buy-inline .rz-chains .rz-chain img { width: 150px; }
.rzw-main { min-width: 0; }
.rzw-name { margin: 0 0 10px; font-family: var(--font-display, Georgia), serif;
  font-size: clamp(18px, 1.9vw, 22px); line-height: 1.22; font-weight: 700;
  color: var(--accent-deep, #69143a); }
/* Taste pill + the two plain facts. The pill is the only coloured thing here:
   Alko's makutyyppi colours are a code Finnish wine buyers already read, and
   the colour arrives as data from the importer (--pill), never guessed in CSS. */
.rzw-facts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  margin: 0 0 10px; }
.rzw-taste { display: inline-block; padding: 5px 13px; border-radius: 3px;
  background: var(--pill, #69143a); color: #fff;
  font-size: 14px; font-weight: 600; line-height: 1.25; }
/* Yellow and pale grey pills need dark type to stay legible — the palette is
   Alko's and includes both, so this cannot be one fixed foreground. */
.rzw-taste[style*="#F8E848"], .rzw-taste[style*="#CECECE"] { color: #1a1a1a; }
.rzw-fact { font-size: 15px; color: var(--ink, #334155); }
.rzw-sep { color: rgba(0, 0, 0, .28); }
.rzw-note { margin: 0 0 12px; font-size: 15px; line-height: 1.5;
  color: var(--ink, #334155); }
/* Two rows: Alko's symbols, then Viinilehti's rating and mark. One wrapping
   row broke wherever the copy above it happened to end. */
.rzw-marks { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.rzw-vl { display: flex; align-items: center; gap: 16px; }
.rz-syms { display: flex; align-items: center; gap: 5px; margin: 0; padding: 0;
  list-style: none; }
.rz-syms li { display: flex; }
.rz-syms img { display: block; width: 26px; height: 26px; }
.rz-syms-more { font-size: 12px; font-weight: 600; color: var(--ink, #334155);
  opacity: .65; align-self: center; }
.rzw-pq { display: flex; }
/* --------------------------------------------------------------- buy rail */
.rzw-buy { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.rzw-ctas { display: flex; flex-direction: column; gap: 10px; align-items: flex-end; }
/* Chain buttons in the buy rail: 200px wide like the Alko button they replace,
   stacked rather than in the recipe page's three-across row, because the rail
   is 200px and three 150px logos do not fit it. */
.rzw-buy .rz-chains { flex-direction: column; flex-wrap: nowrap; gap: 8px;
  margin: 0; width: 200px; }
.rzw-buy .rz-chains li { width: 100%; }
.rzw-buy .rz-chains .rz-chain { display: block; }
.rzw-buy .rz-chains .rz-chain img { width: 100%; height: auto; }
.rz-price { margin: 0; line-height: 1; color: var(--ink-strong, #1f2937);
  font-family: var(--font-body, system-ui), sans-serif; font-weight: 700; }
.rz-price-from { font-size: 17px; font-weight: 600; margin-right: 5px;
  color: var(--ink, #334155); vertical-align: 14px; }
.rz-price-eur { font-size: 44px; letter-spacing: -.02em; }
.rz-price-cnt { font-size: 22px; vertical-align: super; margin-left: 2px;
  border-bottom: 2px solid currentColor; padding-bottom: 1px; }
.rz-price-vol { margin: 0; font-size: 15px; color: var(--ink, #334155); }
.rzw-buy .alko-button { display: block; line-height: 0; margin-top: 4px; }
.rzw-buy .alko-button img { display: block; width: 200px; height: auto; }
/* Secondary CTA. Deliberately quiet: Alko's button is the commercial action and
   is supplied artwork we may not restyle, so the only way to keep the hierarchy
   honest is to draw this one as an outline at the same width. */
.rzw-more { display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; width: 200px; padding: 10px 14px;
  border: 1.5px solid var(--accent, #ac1430); border-radius: 4px;
  background: #fff; color: var(--accent, #ac1430); text-decoration: none;
  font-size: 15px; font-weight: 600; }
.rzw-more svg { width: 15px; height: 15px; }
.rzw-more:hover { background: var(--accent, #ac1430); color: #fff; }
/* ------------------------------------------------------- Viinilehti marks
 * Wordmark above, stars below — the arrangement on Viinilehti's own supplied
 * artwork and on the client's live card. Sized to sit inside the 26px symbol
 * row rather than beside it as a block of its own.
 *
 * The price/quality mark was 74px, which made it the largest element on the
 * card. It is a footnote to the rating, not a headline: 38px puts it level with
 * the stars, which is where it belongs and where the live /viinit/ card has it.
 */
.rz-rating { display: inline-flex; flex-direction: column; gap: 2px; }
.rz-rating-mark { display: block; width: 84px; height: auto; }
.rz-badge-img { display: block; width: 38px; height: auto; }
/* Ratings and badges are TEXT plus an inline SVG token, never an image file.
 * The live site ships them as JPG/SVG assets, which is the reason none of it is
 * machine-readable — and why a 60-wine listing weighs 1.3 MB.
 */
/* Viinilehti supplies the star row as three finished SVGs — 3, 4 and 5 stars.
   There is no 2-star file, and 20 wines in this catalogue are rated 2, so the
   supplied set cannot serve the whole catalogue. These are drawn instead, in
   Viinilehti's own two colours read out of their artwork (#7A0017 filled,
   #D8D8D8 empty): visually the same row, every rating covered, and it scales
   with the type instead of being a fixed 98x16 bitmap-in-vector. The wordmark
   above them is still the supplied file — that is the trademark. */
.rz-stars { display: inline-flex; align-items: center; gap: 3px; vertical-align: middle; }
.rz-stars svg { width: 16px; height: 16px; flex: none; }
.rz-stars .on { fill: #7a0017; }
.rz-stars .off { fill: #d8d8d8; }
.rz-stars-text { font-size: 14px; color: var(--ink, #334155); }
/* Chain buttons use each chain's own supplied artwork — S-ryhmä, K-Ruoka and
 * Lidl are trademarks, not something to re-typeset. Only chains we actually
 * have a link for are rendered at all (see chain_links): a row of greyed-out
 * "ei tiedossa" non-answers reads as broken. */
.rz-chains { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0 0;
  padding: 0; list-style: none; }
.rz-chains .rz-chain { display: inline-block; padding: 0; border: 1px solid rgba(0, 0, 0, .12);
  border-radius: 6px; background: #fff; line-height: 0; overflow: hidden;
  transition: border-color .15s ease, box-shadow .15s ease; }
.rz-chains .rz-chain img { display: block; width: 150px; height: auto; }
.rz-chains .rz-chain:hover { border-color: var(--accent, #ac1430);
  box-shadow: 0 4px 14px -8px rgba(105, 20, 58, .6); }
.rz-chains .rz-chain-text { padding: 9px 16px; line-height: 1.3;
  color: var(--accent, #ac1430); text-decoration: none;
  font-size: 14px; font-weight: 600; }
/* One card per row, not a grid of tiles. The listing renders the SAME component
 * as the recipe page (.rzw) and that card is horizontal, so it does not tile.
 * The old tile carried a subset of the same data in a different order — two
 * surfaces describing the same 520 wines, already drifting apart. */
/* /viinit/ opens straight on the filters: 30px from the header to the heading,
   20px from the heading to the bar. The pack's section rhythm assumes a page
   that opens with a standfirst; this one opens with a control. */
.wz-bare { padding-top: 30px; }
.wz-row .rzw { border-color: rgba(0, 0, 0, .12); }
.wz-row .rzw:hover { border-color: var(--accent, #ac1430); }
.rzw-name a { color: inherit; text-decoration: none; }
.rzw-name a:hover { text-decoration: underline; text-underline-offset: 3px; }
.rzw-avail { margin: 0 0 10px; font-size: 14px; color: var(--ink, #334155); }
.wd-top .rz-syms { margin: 0 0 6px; }
/* The three chain buttons stack on a phone and eat most of a screen. They are
   150px wide artwork — three fit a row if they are allowed to shrink. */
@media (max-width: 620px) {
  .rz-chains { flex-wrap: nowrap; gap: 6px; }
  .rz-chains li { flex: 1 1 0; min-width: 0; }
  .rz-chains .rz-chain { display: block; }
  .rz-chains .rz-chain img { width: 100%; height: auto; }
}
/* The wine card at tablet width: the buy rail is 210px of a 700px column, and
   below ~760px that leaves the name wrapping every two words. Rail drops under
   the reading column and becomes a row — price on the left, the two CTAs on the
   right — so the bottle keeps its place beside the text. */
@media (max-width: 760px) {
  /* Mobile was close already — the client asked for about +10%, not the jump
     desktop needed. 160 -> 180. */
  .rzw, .rzw.is-marketti { grid-template-columns: 112px minmax(0, 1fr); gap: 18px; padding: 18px; }
  .rzw-buy.rzw-buy-inline .rz-chains .rz-chain img { width: 128px; }
  .rzw-shot { height: 180px; }
  .rzw-shot img { max-height: 180px; }
  .rzw-buy { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap;
    align-items: flex-end; justify-content: space-between; gap: 12px;
    padding-top: 16px; border-top: 1px solid rgba(0, 0, 0, .1); }
  .rzw-buy .rz-price, .rzw-buy .rz-price-vol { text-align: left; }
  .rzw-ctas { display: flex; gap: 10px; }
}
/* Phone: one column, and the bottle centred over the text rather than pinned
   left in a 104px gutter with a ragged column beside it. Both CTAs go full
   width — a 200px button in a 320px column is a target that reads as optional. */
@media (max-width: 560px) {
  .rzw { grid-template-columns: 1fr; gap: 14px; }
  .rzw-shot { height: 190px; }
  .rzw-shot img { max-height: 190px; }
  .rzw-name { text-align: center; }
  /* The rule between the two facts is a column divider. Once the row is centred
     and wrapping it becomes a stray vertical tick at the start of a line. */
  .rzw-facts { justify-content: center; }
  /* Symbols on their own line, rating and badge under them — side by side they
     squeeze the wordmark to about half its legible width on a 390px screen. */
  .rzw-marks { align-items: center; gap: 12px; }
  .rzw-marks .rz-rating { align-items: center; }
  .rzw-note { text-align: center; }
  .rzw-buy { flex-direction: column; align-items: stretch; }
  .rzw-buy .rz-price, .rzw-buy .rz-price-vol { text-align: center; }
  .rzw-buy .alko-button { align-self: center; }
  .rzw-more { width: 100%; }
  /* Grocery card on a phone: one column, and the chain buttons centred under
     the price rather than stretched edge to edge. */
  .rzw.is-marketti { grid-template-columns: 1fr; }
  .rzw-buy.rzw-buy-inline { flex-direction: column; align-items: center; gap: 14px; }
  /* align-self:flex-end is the DESKTOP trick that tucks the volume against the
     price baseline on one row. In a centred column it pins it to the right. */
  .rzw-buy.rzw-buy-inline .rz-price-vol { margin-left: 0; padding-bottom: 0;
    align-self: center; }
  .rzw-buy.rzw-buy-inline .rz-chains { flex-direction: column; align-items: center;
    width: 100%; max-width: 260px; }
  .rzw-buy.rzw-buy-inline .rz-chains li { width: 100%; }
  .rzw-buy.rzw-buy-inline .rz-chains .rz-chain { display: block; }
  .rzw-buy.rzw-buy-inline .rz-chains .rz-chain img { width: 100%; }
}
/* "alk." beside the markettiviini price in the recipe page's grocery block.
   Not .rz-price-from — that is sized for the 44px euro figure on a wine card
   and carries vertical-align:14px, which would lift the word off this line. */
.wz-price-from { font-weight: 600; margin-right: 4px; color: var(--ink, #334155); }

/* ---------------------------------------------------------------- hero band
   Top-of-page wine hero (_herobanner.html). The whole band is one link, so
   the click target is the banner rather than a small button.

   The plate carries its subject on one side and empty ground on the other, so
   a scrim runs from the copy side inward: it guarantees contrast for the text
   no matter which plate a site ships, without darkening the food. */
.chero { margin: 0 0 clamp(24px, 4vw, 44px); background: #14100e; overflow: hidden; }
.chero-link { position: relative; display: block; color: #fff; text-decoration: none; }
/* The band is a fixed-height strip, not the plate's own 16:9. At page width
   a 16:9 plate is ~700px tall, which pushes the recipes off the first
   screen; the plate is cropped to a banner instead. */
.chero-plate { display: block; height: clamp(300px, 34vw, 460px); }
.chero-plate img { display: block; width: 100%; height: 100%; object-fit: cover; }
.chero-link::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(12, 9, 8, .92) 0%, rgba(12, 9, 8, .78) 38%, rgba(12, 9, 8, 0) 68%);
}
.chero-inner {
  position: absolute; inset: 0; z-index: 1;
  width: min(1180px, 92%); margin: 0 auto;
  display: grid; grid-template-columns: minmax(90px, 20%) minmax(0, 1fr);
  /* one row, pinned to the band height. Left as auto, the row takes its
     height from the bottle's intrinsic 2600px and the whole band spills
     down over the page; minmax(0,1fr) plus min-height:0 on the children is
     what actually stops a grid item from expanding its track. */
  grid-template-rows: minmax(0, 1fr);
  align-items: stretch; gap: clamp(16px, 3vw, 40px);
}
.chero-bottle { display: flex; justify-content: center; align-items: center;
  min-height: 0; height: 100%; padding: 18px 0; box-sizing: border-box; }
.chero-bottle img { max-height: 100%; max-width: 100%; width: auto; height: auto;
  filter: drop-shadow(0 18px 34px rgba(0, 0, 0, .55)); }
.chero-copy { min-width: 0; min-height: 0; display: flex; flex-direction: column;
  justify-content: center; }
.chero-kicker {
  margin: 0 0 10px; font-size: clamp(11px, 1vw, 13px); font-weight: 700;
  letter-spacing: 2px; text-transform: uppercase; color: #f0c86a;
}
.chero-headline {
  margin: 0 0 14px; font-size: clamp(26px, 3.6vw, 54px); line-height: 1.05;
  font-weight: 800; letter-spacing: -.01em; text-wrap: balance; color: #fff;
}
.chero-marks { margin: 0 0 14px; }
.chero-name { margin: 0 0 18px; font-size: clamp(13px, 1.2vw, 16px); color: rgba(255, 255, 255, .82); }
.chero-foot { display: flex; align-items: center; gap: clamp(14px, 2.5vw, 28px); flex-wrap: wrap; }
.chero-price {
  margin: 0; font-size: clamp(28px, 3vw, 44px); font-weight: 700; line-height: 1;
  color: #fff; white-space: nowrap;
}
.chero-vol { display: block; margin-top: 6px; font-size: 13px; font-weight: 400;
  color: rgba(255, 255, 255, .7); white-space: nowrap; }
.chero-alko img { display: block; width: 200px; height: auto; border-radius: 2px; }

@media (max-width: 780px) {
  .chero-inner {
    grid-template-columns: minmax(70px, 30%) minmax(0, 1fr);
    align-content: start; padding-top: 6%;
  }
  .chero-link::after {
    background: linear-gradient(180deg, rgba(12, 9, 8, .90) 0%, rgba(12, 9, 8, .72) 45%, rgba(12, 9, 8, .15) 78%);
  }
  .chero-plate { height: clamp(380px, 108vw, 560px); }
  .chero-bottle { height: 100%; max-height: none; padding: 14px 0; }
  .chero-alko img { width: 168px; }
}

/* ------------------------------------------------------- viikon viini strip
   Collapsed to a single line under the recipe's own wine card. The LOYTO mark
   is in the collapsed head on purpose: it is the sales argument, so it has to
   be visible before the reader decides whether to expand. */
.wkw { margin: 22px 0 0; }
.wkw-box { border: 1px solid rgba(0, 0, 0, .14); border-radius: 8px; background: #fff; }
.wkw-box[open] { border-color: var(--accent, #ac1430); }
.wkw-head {
  display: flex; align-items: center; gap: 14px; padding: 10px 16px;
  cursor: pointer; list-style: none; min-height: 60px;
}
.wkw-head::-webkit-details-marker { display: none; }
.wkw-thumb { flex: 0 0 34px; height: 46px; display: flex; align-items: center; justify-content: center; }
.wkw-thumb img { max-height: 46px; max-width: 34px; width: auto; height: auto; }
.wkw-lead { flex: 1 1 auto; min-width: 0; }
.wkw-eyebrow {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--accent, #ac1430);
}
.wkw-mark { display: inline-flex; }
.wkw-mark .rz-badge-img { width: 22px; height: 22px; display: block; }
.wkw-name {
  display: block; margin-top: 2px; font-size: 15px; font-weight: 600;
  color: var(--ink-strong, #1f2937);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wkw-price { flex: 0 0 auto; font-size: 19px; font-weight: 700; white-space: nowrap;
  color: var(--ink-strong, #1f2937); }
.wkw-chev { flex: 0 0 auto; width: 20px; height: 20px; color: rgba(0, 0, 0, .45);
  transition: transform .18s ease; }
.wkw-box[open] .wkw-chev { transform: rotate(180deg); }
.wkw-body {
  display: flex; gap: 20px; padding: 4px 16px 18px;
  border-top: 1px solid rgba(0, 0, 0, .08); margin-top: 2px; padding-top: 16px;
}
.wkw-shot { flex: 0 0 84px; display: flex; align-items: flex-start; justify-content: center; }
.wkw-shot img { max-width: 84px; max-height: 190px; width: auto; height: auto; }
.wkw-detail { flex: 1 1 auto; min-width: 0; }
.wkw-marks { display: flex; align-items: center; gap: 14px; margin: 0 0 10px; }
.wkw-marks .rz-badge-img { width: 40px; height: 40px; display: block; }
.wkw-marks .rz-rating { display: inline-flex; flex-direction: column; gap: 3px; }
.wkw-marks .rz-rating-mark { width: 76px; height: auto; display: block; }
.wkw-marks .rz-stars svg { width: 14px; height: 13px; }
.wkw-facts { margin: 0 0 8px; font-size: 14px; color: var(--ink, #334155); }
.wkw-note { margin: 0 0 10px; font-size: 14px; line-height: 1.5; color: var(--ink, #334155); }
.wkw-avail { margin: 0 0 14px; font-size: 13px; color: rgba(0, 0, 0, .55); }
.wkw-alko img { display: block; width: 200px; height: auto; }

@media (max-width: 560px) {
  .wkw-price { font-size: 17px; }
  .wkw-name { font-size: 14px; }
  .wkw-body { flex-direction: column; gap: 14px; }
  .wkw-shot { flex: 0 0 auto; justify-content: flex-start; }
}

/* CTA in the collapsed head. Replaces a bare chevron, which read as furniture. */
.wkw-cta {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase;
  color: var(--accent, #ac1430); white-space: nowrap;
  border: 1px solid currentColor; border-radius: 3px; padding: 9px 14px;
}
.wkw-box[open] .wkw-cta { background: var(--accent, #ac1430); color: #fff; border-color: transparent; }
.wkw-cta .wkw-chev { width: 15px; height: 15px; transition: transform .18s ease; }
.wkw-box[open] .wkw-cta .wkw-chev { transform: rotate(90deg); }
.wkw-head:hover .wkw-cta { background: var(--accent, #ac1430); color: #fff; border-color: transparent; }
@media (max-width: 560px) {
  .wkw-cta { font-size: 11px; padding: 8px 10px; letter-spacing: .6px; }
  .wkw-cta .wkw-chev { width: 13px; height: 13px; }
}

/* Thin-distribution wines: the online-order line replaces the store count. */
.chero-online {
  margin: 0 0 12px; font-size: clamp(12px, 1.05vw, 14px); font-weight: 700;
  letter-spacing: 1.2px; text-transform: uppercase; color: #f0c86a;
}
.wkw-online {
  margin: 0 0 14px; font-size: 12px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: var(--accent, #ac1430);
}

/* ---- viikon viini, narrow screens.

   As one flex row the head has four things competing for ~340px: thumb,
   eyebrow, name, price and CTA. The name lost - it truncated to "2..." - and
   the price landed on top of what was left of it. Below 620px the head becomes
   a small grid instead: the bottle spans the left, the name gets the full
   remaining width and is allowed to wrap onto two lines, the price sits under
   it, and the CTA takes a full-width row of its own where it reads as a
   button rather than as a scrap wedged into a line. */
@media (max-width: 620px) {
  .wkw-head {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    grid-template-areas:
      "thumb lead"
      "thumb price"
      "cta   cta";
    column-gap: 12px; row-gap: 4px; padding: 12px 14px;
  }
  .wkw-thumb { grid-area: thumb; align-self: center; flex: none; height: 62px; }
  .wkw-thumb img { max-height: 62px; max-width: 44px; }
  .wkw-lead  { grid-area: lead; align-self: end; }
  .wkw-price { grid-area: price; align-self: start; font-size: 20px; }
  .wkw-cta   { grid-area: cta; justify-content: center; margin-top: 10px; padding: 12px 14px; }

  /* the whole point of the regrouping: let the name use the width it now has */
  .wkw-name {
    white-space: normal; overflow: visible; text-overflow: clip;
    font-size: 15px; line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .wkw-eyebrow { flex-wrap: wrap; row-gap: 2px; }
}

/* Hero contained rather than full-bleed.

   Rosa's page is a series of contained cards on a light ground, so a hero
   bleeding to both screen edges reads as a different site's furniture wedged
   above the content. Opting in per site keeps the repurpose sites full-bleed,
   where the band IS the top of the page. */
.chero--contained { background: transparent; }
.chero--contained .chero-link {
  width: min(1270px, 100% - 48px); margin: 0 auto;
  border-radius: 10px; overflow: hidden;
}
@media (max-width: 780px) {
  .chero--contained .chero-link { width: 100%; border-radius: 0; }
}

/* ============================================================ Viinisää
   Ristiinmarkkinointibanneri reseptisivujen loppuun. Vain rosaviinijaruoka
   sisällyttää sen tällä hetkellä; muilla sivustoilla nämä säännöt ovat
   käyttämättömiä eivätkä vaikuta mihinkään. */
.vs-banner{
  --vs-paper:#fdf1ec; --vs-ink:#3a1c29; --vs-ink-soft:#7a4456;
  --vs-coral:#f58e84; --vs-deep:#e26a5f; --vs-lemon:#f8ed43;
  --vs-line:#ecd5cd;
  display:block; width:100%; max-width:660px; margin:32px 0; padding:0;
  min-height:262px;
  background:var(--vs-paper);
  border:2px solid var(--vs-ink); border-radius:14px;
  color:var(--vs-ink);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  line-height:1.45;
}
.vs-banner *,.vs-banner *::before,.vs-banner *::after{box-sizing:border-box}
.vs-banner p{margin:0}
.vs-inner{padding:22px 24px 20px}
.vs-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}
/* Yksi rivi vain siellä missä pisin kelisana varmasti mahtuu. Kapeammalla se
   saa katketa kahdelle riville, ja tila on varattu kahdelle, joten sanan
   vaihtuminen ei siirrä mitään. Aiempi nowrap + overflow:hidden leikkasi
   SADONKORJUUKELI-sanan sanottomasti 361-400 px leveydellä. */
.vs-eyebrow{font-size:12px;font-weight:800;letter-spacing:.17em;color:var(--vs-ink-soft);
  height:18px;line-height:18px;white-space:nowrap}
.vs-brand{color:var(--vs-ink-soft)}
.vs-dot{opacity:.6}
.vs-keli{color:var(--vs-ink);letter-spacing:.12em}
.vs-glyph{flex:none;width:88px;height:40px;margin-top:-8px}
/* HUOM specificity: .vs-banner p{margin:0} on 0,1,1 ja voittaa paljaan
   .vs-title-tyyppisen 0,1,0 -saannon. Kaikki bannerin pystyvalit olivat siksi
   nollassa, vaikka ne oli kirjoitettu nakyviin. Siksi jokainen valia asettava
   saanto on skoopattu .vs-banner-etuliitteella. Ala poista etuliitetta. */
.vs-banner .vs-title{margin-top:8px;font-size:30px;line-height:1.1;font-weight:800;letter-spacing:-.01em}
.vs-banner .vs-sub{margin-top:4px;font-size:17px;font-weight:800;color:var(--vs-ink);
  background:linear-gradient(transparent 62%,var(--vs-lemon) 62%);display:inline-block;padding:0 3px}
.vs-banner .vs-body{margin-top:10px;font-size:15px;color:var(--vs-ink-soft)}
.vs-banner .vs-actions{margin-top:16px}
.vs-cta{display:inline-block;background:var(--vs-ink);color:var(--vs-paper);
  font-size:15px;font-weight:800;text-decoration:none;
  padding:12px 22px;border-radius:999px}
.vs-cta:hover,.vs-cta:focus{background:#4d2637}
.vs-cta:focus-visible{outline:3px solid var(--vs-ink);outline-offset:2px}
/* Arvonnan ehdot ja ikaraja poistettiin bannerista 21.8.2026: molemmat ovat
   jo Viinisaassa, ja Rosalla on oma K-18-portti. Erotinviiva siirtyi tahan,
   koska se oli kiinni poistetussa rivissa. */
.vs-banner .vs-url{margin-top:18px;padding-top:14px;border-top:1px solid var(--vs-line);
  font-size:13px;font-weight:800;color:var(--vs-ink)}
@media (max-width:560px){
  .vs-banner{min-height:0}
  .vs-eyebrow{white-space:normal;height:32px;line-height:16px}
  .vs-inner{padding:18px 16px 16px}
  .vs-banner .vs-title{font-size:24px}
  .vs-glyph{width:72px;height:33px}
  .vs-banner .vs-sub{font-size:15px}
  .vs-cta{display:block;text-align:center;padding:13px 16px}
}
@media (max-width:360px){
  .vs-title{font-size:21px}
  .vs-glyph{width:62px;height:28px;margin-top:-4px}
}
