/* Mona Spice — cuisine de contraste
   Olive, sage, terracotta and beige on a pale green ground, with black doing
   the structural work. Heavy condensed display type against a quiet body face:
   the contrast in the name, applied to the page. */

/* ------------------------------------------------------------------ fonts

   Laqonic is a commercial typeface and is not bundled here. To use the real
   thing, buy the webfont licence, drop the files in as:

       assets/fonts/laqonic-regular.woff2
       assets/fonts/laqonic-medium.woff2
       assets/fonts/laqonic-bold.woff2

   and uncomment the three @font-face rules below. Nothing else changes —
   "Laqonic" is already first in both font stacks, so it takes over everywhere
   the moment the files exist.

   Until then the page uses Barlow (SIL Open Font License, self-hosted): the
   closest freely-licensable match for Laqonic's condensed geometric shapes.
   Semi Condensed sets the text, Condensed sets the headings.
*/

/*
@font-face { font-family: "Laqonic"; src: url("/assets/fonts/laqonic-regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Laqonic"; src: url("/assets/fonts/laqonic-medium.woff2")  format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Laqonic"; src: url("/assets/fonts/laqonic-bold.woff2")    format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
*/

/* The handwriting on the About page: Caveat, a variable font, so one file
   covers the whole weight range. Self-hosted like the rest — the site loads
   nothing from a CDN. It sets the asides Mona writes in her own voice, and
   never anything a reader has to be able to read quickly. */
@font-face {
  font-family: 'Caveat';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/assets/fonts/Caveat-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Caveat';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/assets/fonts/Caveat-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/BarlowCondensed-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/BarlowCondensed-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/BarlowCondensed-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/BarlowCondensed-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-500-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow Semi Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/BarlowSemiCondensed-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Brand palette: olive, sage, pale green, black, terracotta, beige.
     Text pairings below were contrast-checked — see docs/BRAND.md. */
  --olive:      #54682B;
  --sage:       #B9BB9C;
  --pale:       #D7D9C3;
  --terracotta: #C77265;
  --beige:      #CBBAAB;

  --paper:      #E3E4D5;   /* page ground */
  --paper-warm: #D7D9C3;   /* image placeholders, alternate bands */
  --surface:    #F2F3EC;   /* cards, panels, inputs */
  --ink:        #0B0B0A;
  --ink-soft:   #2C3519;
  --muted:      #495A26;   /* 5.9:1 on paper */
  --line:       #C4C6AA;
  --line-soft:  #D5D7C0;

  /* Terracotta is too light for text on the pale ground, so it is used as a
     fill (with black on top) and this deeper tone carries accent text. */
  --accent:     #874F46;   /* 5.0:1 on paper */
  --accent-fill:#C77265;
  --accent-tint:#F3E4E0;
  --accent-bright:#E9A28E;  /* the shade on "balance." — used for the slogan */

  /* Olive taken down toward black: the ground for the dark sections. Keeps the
     palette honest while staying deep enough for photography to glow on it.
     Paper text sits at 8.8:1. */
  --ground:      #333E1C;
  --ground-dim:  #C3C8AE;   /* secondary text on --ground, 6.4:1 */

  /* One typeface throughout — Laqonic when licensed, Barlow until then. */
  --display: "Laqonic", "Barlow Condensed", "Avenir Next Condensed",
             "Arial Narrow", Impact, system-ui, sans-serif;
  --sans: "Laqonic", "Barlow Semi Condensed", "Avenir Next Condensed",
          -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  /* Mona's own hand, for the asides on the About page. */
  --script: "Caveat", "Bradley Hand", "Segoe Script", cursive;

  --wrap: 1280px;
  --gutter: clamp(20px, 5vw, 64px);
  --radius: 0px;
  --radius-portrait: 16px;   /* the About portraits are the one soft edge */

  --shadow-md: 0 10px 30px -14px rgba(0, 0, 0, .3);
  --shadow-lg: 0 26px 60px -22px rgba(0, 0, 0, .4);

  --ease: cubic-bezier(.22, .61, .36, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Always leave room for the scrollbar.
   *
   * Without this, a page whose height sits near the viewport's gets into a
   * loop: the scrollbar appears, which narrows the viewport, which reflows the
   * content shorter, which removes the scrollbar, which widens it again. The
   * header is a flex row with space-between, so the logo shivers from side to
   * side several times a second. The admin is the page most likely to land on
   * that boundary, because its screens are short and it re-renders in place.
   */
  scrollbar-gutter: stable;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* height:auto matters: the img tags carry real width/height attributes (good for
   layout stability), and without this max-width would squeeze the width while
   the attribute held the height — stretching every logo and photo vertically. */
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  line-height: .96;
  letter-spacing: 0.005em;
  margin: 0;
}

.wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.narrow { max-width: 780px; }

.eyebrow {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow-red { color: var(--accent); }

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter: saturate(1.5) blur(14px);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
.site-header.is-stuck { border-bottom-color: var(--ink); }

.site-header .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; height: 116px;
  transition: height .28s var(--ease);
}
/* The lockup is tall, so it gets room at the top of the page and shrinks once
   the header sticks — full presence on arrival, compact bar while reading. */
.site-header.is-stuck .wrap { height: 74px; }

/* The real lockup, at its true proportions. It is a tall stacked mark, so the
   header is deep enough to let it read rather than shrinking it to a smudge. */
.brand { display: flex; align-items: center; }
.brand .brand-logo {
  height: 94px; width: auto;
  /* Reserve the width before the image has decoded. `width: auto` on an
     undecoded image measures zero, so the nav beside it jumps once on every
     cold load. */
  aspect-ratio: 1348 / 1324;
  transition: height .28s var(--ease), opacity .2s var(--ease);
}
.site-header.is-stuck .brand .brand-logo { height: 56px; }
.brand:hover .brand-logo { opacity: .78; }

.nav { display: flex; align-items: center; gap: 26px; }
.nav a {
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 15px; letter-spacing: .04em;
  color: var(--ink);
  padding-block: 3px;
  position: relative;
  transition: color .2s var(--ease);
}
/* A rounded terracotta bar rather than a square black border: a border-bottom
   cannot have round ends, so the rule is its own element. It grows from the
   middle on hover and simply sits there on the current section. */
.nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 3px;
  border-radius: 999px;
  background: var(--accent-fill);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .2s var(--ease);
}
.nav a:hover { color: var(--accent); }
.nav a:hover::after,
.nav a.is-active::after { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .nav a::after { transition: none; }
}

/* Mobile header: the lockup on its own line, the full menu centred underneath.
   Hiding App/About/Contact below 720px meant three sections were simply
   unreachable on a phone. */
@media (max-width: 760px) {
  .site-header .wrap {
    flex-direction: column;
    height: auto;
    gap: 8px;
    padding-block: 12px 10px;
  }
  .site-header.is-stuck .wrap { height: auto; padding-block: 8px; }

  .brand { justify-content: center; }
  .brand .brand-logo { height: 56px; }
  .site-header.is-stuck .brand .brand-logo { height: 40px; }

  .nav {
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px 15px;
    width: 100%;
  }
  .nav a.hide-sm { display: inline-block; }
  .nav a { font-size: 14px; letter-spacing: .03em; }
}

/* ------------------------------------------------------------------ hero */

.hero-lead { padding-block: clamp(26px, 4vw, 52px) clamp(16px, 2.4vw, 26px); }
.hero { padding-block: clamp(28px, 4vw, 52px) clamp(26px, 4vw, 44px); }

.hero-title {
  font-size: clamp(42px, 7.6vw, 104px);
  line-height: .9;
  letter-spacing: -0.005em;
  max-width: 16ch;
}
.hero-title .red { color: var(--accent); }

.hero-lede {
  margin-top: clamp(20px, 3vw, 28px);
  max-width: 54ch;
  font-size: clamp(16.5px, 1.8vw, 19px);
  color: var(--ink-soft);
}

.hero-meta {
  margin-top: 32px;
  display: flex; flex-wrap: wrap; gap: 14px 26px; align-items: center;
}

/* A thin red rule used to break sections, echoing the chilli */

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 15px; letter-spacing: .05em;
  padding: 12px 26px;
  border-radius: 999px;
  border: 2px solid var(--ink);
  background: var(--ink); color: var(--paper);
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease),
              border-color .18s var(--ease), transform .18s var(--ease), opacity .18s var(--ease);
}
.btn:hover { background: var(--olive); border-color: var(--olive); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: .4; cursor: not-allowed; transform: none; }

.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.btn-sm { padding: 7px 16px; font-size: 13px; border-width: 1.5px; border-radius: 999px; }
.btn-danger { background: transparent; color: var(--accent); border-color: var(--accent); }
.btn-danger:hover { background: var(--accent); color: var(--paper); }

/* --------------------------------------------------------------- filters */

.filters {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.chip {
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 14px; letter-spacing: .05em;
  color: var(--ink);
  padding: 7px 16px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: transparent; cursor: pointer;
  transition: all .16s var(--ease);
  white-space: nowrap;
}
.chip:hover { border-color: var(--ink); }
.chip.is-active { background: var(--olive); border-color: var(--olive); color: #fff; }

/* ------------------------------------------------------------------ grid */

/* The card flourish deliberately overhangs its card, which would otherwise
   widen the document and let the page scroll sideways on tablets. Clip it at
   the source; `overflow-clip-margin` still lets it paint past the content edge,
   so the decoration reads as intended without any scrollable overflow. */
#dishes {
  overflow-x: clip;
  overflow-clip-margin: 70px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  gap: clamp(26px, 3vw, 46px) clamp(18px, 2.2vw, 30px);
  padding-block: clamp(30px, 5vw, 52px) clamp(30px, 5vw, 60px);
}

.card { display: block; position: relative; }

.card-frame {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 14px;
  background: var(--paper-warm);
}
.card-frame img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .7s var(--ease), opacity .5s var(--ease);
  opacity: 0;
}
.card-frame img.is-loaded { opacity: 1; }
.card:hover .card-frame img { transform: scale(1.045); }

/* What a dish is free of, or is, in the corner where its number used to be.
   A number told a reader their position in a list they were already looking
   at; these say something the photograph cannot. */
/* The badges live here rather than in the frame, so a tooltip can leave the
   photograph. Same box as the frame, no clipping, and it lets the mouse
   through except where a badge actually is. */
.card-marks {
  position: absolute;
  top: 0; left: 0; right: 0;
  aspect-ratio: 4 / 5;
  pointer-events: none;
  z-index: 2;
}
.card-marks > * { pointer-events: auto; }

.card-diet {
  /* Off the corner rather than against it: pressed into the very edge of a
     photograph these read as part of the frame instead of marks on the dish. */
  position: absolute; top: 14px; left: 14px;
  display: flex; gap: 5px;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}
/* On the dish itself, where there is room for the words. */
.diet-marks {
  display: flex; flex-wrap: wrap; gap: 8px 16px;
  margin-top: 18px;
}
.diet-mark {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted);
}

.diet-icon-free { color: var(--accent-fill); }
.diet-icon-is { color: var(--olive, #54682B); }

/* red index tab, echoing the logo's blocky counters */
.card-index {
  position: absolute; top: 10px; left: 10px;
  border-radius: 999px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 13px; letter-spacing: .06em;
  color: #fff; background: var(--accent-fill);
  padding: 4px 9px;
}

.card-count {
  position: absolute; right: 14px; bottom: 14px;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 700; color: #fff;
  background: rgba(0,0,0,.58);
  backdrop-filter: blur(6px);
  padding: 6px 12px;
  border-radius: 999px;
}
.card-count svg { width: 16px; height: 16px; }

.card-body { padding-top: 13px; }
.card-title {
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 23px; line-height: 1.02; letter-spacing: .01em;
  color: var(--muted);              /* the olive green */
  transition: color .18s var(--ease);
}
.card:hover .card-title { color: var(--accent); }
.card-desc {
  margin-top: 7px; font-size: 14.5px; color: var(--ink); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-cat { margin-top: 9px; }

.card-draft {
  position: absolute; top: 10px; right: 10px;
  border-radius: 999px;
  font-family: var(--display);
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  background: var(--ink); color: #fff;
  padding: 4px 8px;
}

/* --------------------------------------------------------- recipe detail */

.recipe-hero { padding-top: clamp(26px, 4vw, 48px); }

.back-link {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 14px; letter-spacing: .05em;
  color: var(--muted);
  transition: color .2s var(--ease), gap .2s var(--ease);
}
.back-link:hover { color: var(--accent); gap: 11px; }

.recipe-title {
  font-size: clamp(42px, 8vw, 92px);
  letter-spacing: -0.005em;
  margin-top: 18px;
  max-width: 16ch;
}
.recipe-lede {
  margin-top: 18px; max-width: 62ch;
  font-size: clamp(16.5px, 1.7vw, 19px); color: var(--ink-soft);
}

.recipe-facts {
  display: flex; flex-wrap: wrap; gap: 0;
  margin-top: 30px;
  border-top: 2px solid var(--olive);
  border-bottom: 1px solid var(--line);
}
.fact {
  padding: 15px 30px 15px 0;
  margin-right: 30px;
  border-right: 1px solid var(--line-soft);
}
.fact:last-child { border-right: 0; margin-right: 0; }
.fact-value {
  font-family: var(--display); font-weight: 700;
  font-size: 26px; margin-top: 2px;
}

/* One shape for every dish photo, whatever the camera did.
   The library is 53 portrait / 45 square / 2 landscape, ranging 0.75–1.33, so
   letting each photo keep its own aspect made pages jump around wildly. These
   are top-down plate shots with the plate centred, so a centred 4:3 crop trims
   empty table rather than food. */
.recipe-figure {
  margin: clamp(30px, 5vw, 52px) 0 0;
  overflow: hidden;
  border-radius: 16px;
  background: var(--paper-warm);
  aspect-ratio: 4 / 3;
}
.recipe-figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* More than one photograph at the top of a dish.
 *
 * Scroll-snap, not a script: the browser pages it, it works before any
 * JavaScript has run and with none at all, and a trackpad, a keyboard and a
 * thumb all reach it without anything being wired up. The dots are ordinary
 * links to the slides, which is also why they work with the page prerendered. */
/* Calories and the macros, in the rail under the ingredients. Auto-fit rather
   than a fixed column count: a dish with three figures should not leave three
   empty cells, and a dish with six should not spill. */
.field-unit { color: var(--muted); font-weight: 400; font-size: 11px; }

.macros { margin-top: 18px; }
.macros-locked p { margin: 0; font-size: 13px; color: var(--muted); }
.macro-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
  gap: 14px 10px;
}
.macro { display: flex; flex-direction: column; gap: 2px; }
.macro-value { font-family: var(--display); font-size: 19px; color: var(--ink); }
.macro-label {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted);
}

.hero-carousel { padding: 0; }
.hero-track {
  display: flex;
  height: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.hero-track::-webkit-scrollbar { display: none; }
.hero-slide {
  flex: 0 0 100%;
  height: 100%;
  margin: 0;
  scroll-snap-align: center;
}
.hero-slide img { width: 100%; height: 100%; object-fit: cover; object-position: center; }

.hero-dots { display: flex; gap: 7px; justify-content: center; margin-top: 12px; }
.hero-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--line);
  transition: background .18s ease, transform .18s ease;
}
.hero-dot:hover, .hero-dot:focus-visible { background: var(--accent); transform: scale(1.25); }

@media (prefers-reduced-motion: reduce) {
  .hero-track { scroll-behavior: auto; }
}

.recipe-body {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: clamp(36px, 6vw, 84px);
  padding-block: clamp(46px, 7vw, 84px);
  /* No `align-items: start` here: it shrinks the rail to its content height,
     which leaves `position: sticky` no room to travel. Letting the column
     stretch to the row height is what makes the ingredients panel pin. */
}
@media (max-width: 900px) {
  .recipe-body { grid-template-columns: 1fr; gap: 42px; }
}

.rail { position: sticky; top: 98px; }
@media (max-width: 900px) { .rail { position: static; } }

.rail-card {
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 24px;
}
.rail-card h2 { font-size: 26px; margin-bottom: 14px; }

.ing-list { list-style: none; margin: 0; padding: 0; }
.ing-list li {
  display: flex; gap: 12px; align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 15px;
}
.ing-list li:last-child { border-bottom: 0; }
.ing-amt {
  flex: 0 0 auto; min-width: 68px;
  font-variant-numeric: tabular-nums;
  color: var(--accent); font-weight: 700; font-size: 14px;
}
.ing-item { color: var(--ink-soft); }

.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 20px; margin-bottom: 26px;
  padding-bottom: 12px; border-bottom: 2px solid var(--olive);
}
.section-head h2 { font-size: clamp(28px, 3.6vw, 40px); }

/* ------------------------------------------------------------------ steps */

.step {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 20px;
  padding-bottom: 38px;
  position: relative;
}
.step:not(:last-child)::after {
  content: ""; position: absolute;
  left: 22px; top: 46px; bottom: 10px;
  width: 2px; background: var(--line);
}
.step-num {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  background: var(--olive); color: #fff;
  font-family: var(--display); font-weight: 700;
  font-size: 20px;
  position: relative; z-index: 1;
}
.step-text { font-size: 16.5px; color: var(--ink-soft); line-height: 1.7; }
.step-text p { margin: 0 0 12px; }
.step-text p:last-child { margin-bottom: 0; }

.step-media { margin-top: 16px; display: grid; gap: 14px; }
.step-photo {
  overflow: hidden;
  border-radius: 12px;
  background: var(--paper-warm);
  aspect-ratio: 4 / 3;
  max-width: 520px;
}
.step-photo img { width: 100%; height: 100%; object-fit: cover; object-position: center; }

/* ------------------------------------------------------- instagram embeds */

.ig-embed {
  border: 2px solid var(--ink);
  overflow: hidden;
  background: var(--surface);
  max-width: 420px;
}
.ig-embed iframe { width: 100%; border: 0; display: block; }

.ig-link {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 14px; letter-spacing: .05em;
  color: var(--accent);
  padding: 8px 0;
  transition: gap .2s var(--ease);
}
.ig-link:hover { gap: 12px; }
.ig-link svg { flex: none; }

/* ------------------------------------------------------------- galleries */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
  padding-bottom: clamp(48px, 8vw, 96px);
}
.gallery figure { margin: 0; overflow: hidden; border-radius: 12px; background: var(--paper-warm); cursor: zoom-in; }
.gallery img { aspect-ratio: 1; object-fit: cover; width: 100%; transition: transform .6s var(--ease); }
.gallery figure:hover img { transform: scale(1.06); }

.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(0, 0, 0, .95);
  display: grid; place-items: center;
  padding: 24px;
  opacity: 0; pointer-events: none;
  transition: opacity .26s var(--ease);
}
.lightbox.is-open { opacity: 1; pointer-events: auto; }
.lightbox img { max-width: min(1100px, 92vw); max-height: 88vh; width: auto; border-radius: 10px; }
.lightbox-close {
  position: absolute; top: 18px; right: 22px;
  background: none; border: 0; color: #fff; font-size: 32px;
  cursor: pointer; line-height: 1; opacity: .8;
}
.lightbox-close:hover { opacity: 1; color: var(--accent); }
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: none; border: 0; color: #fff; font-size: 42px;
  cursor: pointer; padding: 12px 20px; opacity: .6;
}
.lightbox-nav:hover { opacity: 1; color: var(--accent); }
.lightbox-prev { left: 6px; } .lightbox-next { right: 6px; }

/* ------------------------------------------------------------------ misc */

.divider { border: 0; border-top: 1px solid var(--line); margin: 0; }

.empty { padding: clamp(60px, 12vw, 116px) 0; text-align: center; color: var(--muted); }
.empty h2 { font-size: 30px; color: var(--ink); margin-bottom: 10px; }

.spinner {
  width: 22px; height: 22px;
  border: 3px solid var(--line); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
  margin: 40px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

.reveal { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

/* ---------------------------------------------------------------- footer */

.site-footer {
  border-top: 5px solid var(--accent-fill);
  padding-block: clamp(40px, 6vw, 68px);
  background: var(--ground);
  color: var(--paper);
}
/* Three bands: the mark, the way around, the three things to do next. The
   middle one is centred on the page rather than on whatever is left over, so
   the outer two are given equal columns however wide they turn out. */
.footer-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 30px clamp(24px, 4vw, 60px);
  align-items: center;
}
.footer-logo { max-width: 190px; }
.footer-links {
  display: grid;
  justify-items: center;
  gap: 14px;
  text-align: center;
}
.footer-actions {
  display: grid;
  gap: 10px;
  justify-items: end;
  justify-self: end;
}
.footer-btn {
  /* Centred inside the pill. They share a width so the three line up, which
     left the shortest label sitting well left of the middle of its own
     button. */
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-width: 232px;
  padding: 10px 18px;
  border: 1.5px solid rgba(227, 228, 213, .3);
  border-radius: 999px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 14px; letter-spacing: .06em;
  color: var(--paper);
  transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.footer-btn:hover {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--ink);
}
.footer-btn-glyph { display: inline-flex; }
.footer-btn-glyph svg { width: 18px; height: 18px; }
.footer-links a {
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 15px; letter-spacing: .05em;
  color: var(--paper);
  border-bottom: 2px solid transparent;
}
.footer-links a:hover { border-bottom-color: var(--accent); color: #fff; }

/* ----------------------------------------------------------------- admin */

.admin-shell { padding-block: 36px 100px; }

.field { margin-bottom: 20px; }
.field label {
  display: block; margin-bottom: 7px;
  font-size: 11px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted);
}
.field input, .field textarea, .field select {
  width: 100%;
  font-family: var(--sans); font-size: 15.5px; color: var(--ink);
  padding: 11px 13px;
  border: 1.5px solid var(--line);
  border-radius: 0;
  background: var(--surface);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
.field textarea { resize: vertical; min-height: 90px; line-height: 1.6; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: 0; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.field-hint { margin-top: 6px; font-size: 12.5px; color: var(--muted); }

.row { display: flex; gap: 14px; flex-wrap: wrap; }
.row > * { flex: 1 1 160px; }

.repeat-item { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 10px; }

.icon-btn {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 0;
  background: var(--surface); color: var(--muted);
  cursor: pointer; font-size: 17px; line-height: 1;
  transition: all .16s var(--ease);
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); }
.icon-btn:disabled { opacity: .35; cursor: not-allowed; }

.panel {
  background: var(--surface);
  border: 1.5px solid var(--line);
  padding: 24px;
  margin-bottom: 20px;
}
.panel > h2 { font-size: 24px; margin-bottom: 5px; }
.panel > .panel-sub { font-size: 13.5px; color: var(--muted); margin-bottom: 20px; }

.step-editor {
  border-left: 4px solid var(--accent);
  border-top: 1px solid var(--line);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 18px;
  margin-bottom: 14px;
  background: var(--paper);
}
.step-editor-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.step-editor-head strong {
  font-family: var(--display); font-weight: 700;
  text-transform: uppercase; font-size: 18px; letter-spacing: .05em;
}

.dropzone {
  border: 2px dashed var(--line);
  padding: 26px; text-align: center;
  color: var(--muted); font-size: 14px;
  cursor: pointer;
  transition: all .2s var(--ease);
}
.dropzone:hover, .dropzone.is-over { border-color: var(--accent); background: var(--accent-tint); color: var(--accent); }

.thumbs { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.thumb-item { position: relative; width: 124px; height: 124px; overflow: hidden; border-radius: 8px; background: var(--paper-warm); cursor: pointer; }
.thumb-item img { width: 100%; height: 100%; object-fit: cover; }
.thumb-item button {
  position: absolute; top: 3px; right: 3px;
  width: 20px; height: 20px;
  border: 0; background: rgba(0,0,0,.75); color: #fff;
  font-size: 12px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}
/* A photo kept on the record but off the page. Greyed rather than removed —
   it can still be a step's photo, and the choice has to stay reversible. */
.thumb-item.is-hidden img { opacity: .3; filter: grayscale(1); }
.thumb-item.is-hidden::before {
  content: "HIDDEN"; position: absolute; top: 50%; left: 0; right: 0;
  transform: translateY(-50%); z-index: 1;
  font-family: var(--display); font-size: 10px; font-weight: 700; letter-spacing: .1em;
  text-align: center; color: var(--ink);
}
.thumb-eye {
  top: auto !important; bottom: 3px; right: 3px;
  font-size: 11px !important;
}
/* In the set the top of the page turns through. */
.thumb-item.is-top { outline: 2px dashed var(--accent); outline-offset: -2px; }

/* What each photograph is for, in words.
 *
 * These were two 20px glyphs sitting on the photograph itself, which is
 * findable only by somebody who already knows it is there — the person who
 * needed them could not see them, which is the whole test. */
.thumb-flags { display: flex; gap: 4px; }
.thumb-flag {
  flex: 1;
  font: inherit; font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  padding: 4px 0;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--surface); color: var(--muted);
  cursor: pointer;
}
.thumb-flag:hover { border-color: var(--accent); color: var(--accent); }
.thumb-flag.is-on {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.thumb-flag[disabled] { opacity: .55; cursor: default; }
.thumb-flag[disabled]:hover { border-color: var(--line); color: var(--muted); }
.thumb-flag.is-on[disabled] { opacity: .75; color: #fff; }

/* The unit shortcut beside an ingredient's amount. Narrow on purpose: it is
   a way of typing, not a field of its own. */
.step-tools { display: flex; gap: 4px; margin-bottom: 5px; }
.step-tools .icon-btn { width: 26px; height: 24px; font-size: 12px; }

.ing-unit {
  flex: 0 0 118px; min-width: 0;
  font: inherit; font-size: 13px;
  padding: 7px 6px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--surface); color: var(--ink);
}

.thumb-item.is-hero { outline: 3px solid var(--accent); outline-offset: -3px; }
.thumb-item.is-hero::after {
  content: "HERO"; position: absolute; bottom: 0; left: 0; right: 0;
  background: var(--accent); color: #fff;
  font-family: var(--display); font-size: 10px; font-weight: 700; letter-spacing: .1em;
  text-align: center; padding: 2px;
}

.admin-bar {
  position: sticky; bottom: 0; z-index: 40;
  display: flex; gap: 12px; align-items: center; justify-content: flex-end;
  padding: 16px 0;
  background: linear-gradient(to top, var(--paper) 72%, transparent);
}
.admin-bar .status { margin-right: auto; font-size: 13.5px; color: var(--muted); }

.admin-list { display: grid; gap: 1px; }
.admin-row {
  display: grid; grid-template-columns: 56px minmax(0,1fr) auto auto;
  gap: 16px; align-items: center;
  padding: 12px;
  transition: background .16s var(--ease);
}
.admin-row:hover { background: var(--surface); }
.admin-row img { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; background: var(--paper-warm); }
.admin-row-title {
  font-family: var(--display); font-weight: 700;
  text-transform: uppercase; font-size: 19px; letter-spacing: .02em;
}
.admin-row-meta { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

.pill {
  font-family: var(--display);
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 9px;
}
.pill-live { background: var(--olive); color: #fff; }
.pill-draft { background: var(--accent-tint); color: var(--accent); }

.login-card {
  max-width: 400px; margin: clamp(50px, 12vh, 120px) auto;
  background: var(--surface); border: 2px solid var(--ink);
  padding: 34px;
  box-shadow: var(--shadow-md);
}
.login-card .login-logo { max-width: 150px; margin-bottom: 22px; }
.login-card h1 { font-size: 32px; margin-bottom: 6px; }
.login-card p { color: var(--muted); font-size: 14.5px; margin: 0 0 24px; }

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 20px);
  background: var(--ink); color: #fff;
  padding: 13px 24px; font-size: 14px; font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0; pointer-events: none;
  transition: opacity .24s var(--ease), transform .24s var(--ease);
  z-index: 300;
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.toast.is-error { background: var(--accent); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ----------------------------------------------------------------- about

   Laid out from the maquette: the hero answers three questions beside a
   portrait, the sections below alternate between plain text and cream cards,
   and Mona's own hand (Caveat) carries the asides. Nothing decorative is load
   bearing — every stroke, chilli and stacked card edge is aria-hidden, and the
   page reads in order without any of it.                                    */

.ab-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.04fr) minmax(0, 1.06fr) minmax(0, 1.04fr);
  gap: clamp(18px, 2.6vw, 38px);
  align-items: start;
  padding-block: clamp(28px, 4.5vw, 60px) clamp(24px, 4vw, 56px);
}

.ab-title {
  font-family: var(--display);
  font-size: clamp(44px, 6.4vw, 92px);
  line-height: .86;
  letter-spacing: -.01em;
  text-transform: uppercase;
  margin: 0;
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 .22em;
}
.ab-title-line { display: block; }
/* The second line carries the brush, so it sits under the words rather than
   under the whole block. */
.ab-title-line--under { flex: 1 0 100%; }

.ab-chilli {
  width: clamp(46px, 6vw, 86px);
  height: auto;
  transform: rotate(-8deg);
  flex: 0 0 auto;
}
.ab-chilli--small { width: clamp(30px, 3.4vw, 44px); }

.ab-brush {
  display: block;
  width: min(78%, 320px);
  height: clamp(10px, 1.4vw, 18px);
  /* Clear of the word rather than tucked under it — at -.06em the stroke was
     touching the descender of the full stop. */
  margin-top: .1em;
  fill: var(--olive);
  opacity: .9;
}
.ab-brush--accent { fill: var(--accent-fill); width: min(64%, 250px); }

.ab-alias {
  font-family: var(--sans);
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.45;
  color: var(--ink-soft);
  margin: clamp(20px, 2.4vw, 30px) 0 clamp(26px, 3vw, 38px);
}

.ab-qa + .ab-qa { margin-top: clamp(22px, 2.6vw, 32px); }

.ab-q {
  font-family: var(--display);
  font-size: clamp(20px, 2vw, 27px);
  text-transform: uppercase;
  letter-spacing: .01em;
  color: var(--ink);
  margin: 0 0 8px;
}
/* A short olive rule under each question, the same gesture as the brush
   without pretending to be hand-drawn at this size. */
.ab-q::after {
  content: "";
  display: block;
  width: 46px; height: 3px;
  margin-top: 6px;
  background: var(--olive);
}

.ab-a {
  font-size: clamp(13.5px, 1.05vw, 15px);
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 10px;
  /* Wide enough that a paragraph stops dropping its last word onto a line of
     its own, which is what made these read as ragged. */
  max-width: 44ch;
  text-wrap: pretty;
}
.ab-a:last-child { margin-bottom: 0; }

.ab-portrait {
  position: relative;
  margin: 0;
  border-radius: var(--radius-portrait);
  overflow: hidden;
  box-shadow: 0 18px 40px rgba(11, 11, 10, .12);
}

/* Her hand, on the photograph, with an arrow to the person it is about.
   No box behind it: the shadow is enough to hold it against a wall that is
   already pale, and a panel would look like a caption rather than a note. */
.ab-portrait-note {
  position: absolute;
  top: clamp(12px, 2vw, 24px);
  left: clamp(14px, 2.2vw, 26px);
  right: clamp(14px, 2.2vw, 26px);
  font-family: var(--script);
  font-size: clamp(15px, 1.55vw, 22px);
  line-height: 1.14;
  color: var(--ink);
  text-shadow: 0 1px 12px rgba(242, 243, 236, .95), 0 0 4px rgba(242, 243, 236, .9);
  pointer-events: none;
}
.ab-portrait-arrow {
  display: block;
  width: clamp(64px, 6.6vw, 98px);
  height: auto;
  /* Under the middle of the writing and pointing down and right, which is
     where she is standing. Pointing the other way it landed on the picture
     hanging on the wall behind her. */
  margin: 0 0 0 clamp(30px, 5.4vw, 84px);
  fill: none;
  /* Olive, like the arrow by the plates further down — not the ink of the
     writing. A black line on a photograph reads as a mark on the print. */
  stroke: var(--olive);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* A breath of paper behind it, so it holds on a dark part of a photograph
     as well as on a pale wall. */
  filter: drop-shadow(0 1px 3px rgba(242, 243, 236, .85));
}
.ab-portrait img { display: block; width: 100%; height: auto; }

.ab-hero-side { padding-top: clamp(8px, 2vw, 26px); }

.ab-hand {
  margin: clamp(26px, 3vw, 38px) 0 0;
}
.ab-hand blockquote {
  font-family: var(--script);
  font-size: clamp(26px, 2.9vw, 40px);
  line-height: 1.18;
  color: var(--ink);
  margin: 0;
  max-width: 15ch;
}

/* ------------------------------------------------------------ her kitchen */

.ab-section-title {
  font-family: var(--display);
  font-size: clamp(28px, 3.6vw, 46px);
  text-transform: uppercase;
  line-height: 1;
  margin: 0 0 6px;
}
.ab-section-title::after {
  content: "";
  display: block;
  width: 118px; height: 4px;
  margin-top: 10px;
  background: var(--olive);
}

.ab-welcome,
.ab-healthy,
.ab-close {
  display: grid;
  gap: clamp(26px, 4vw, 60px);
  padding-block: clamp(34px, 5vw, 72px);
  align-items: start;
}
/* Both columns to the same height, so the pile of cards ends where the run of
   cards beside it ends rather than floating half way up. */
.ab-welcome {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
}
.ab-welcome > * { display: flex; flex-direction: column; }
.ab-welcome .ab-card:last-child { margin-bottom: 0; }
.ab-stack { flex: 1; }
.ab-card--tall { height: 100%; }
.ab-healthy { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); align-items: center; }
.ab-close   { grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); }

.ab-method {
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1.6;
  color: var(--ink-soft);
  margin: clamp(14px, 1.6vw, 20px) 0 clamp(18px, 2vw, 26px);
  max-width: 46ch;
}
.ab-method strong { color: var(--ink); }

.ab-card {
  background: var(--surface);
  border-radius: 4px;
  padding: clamp(16px, 1.6vw, 22px) clamp(18px, 1.8vw, 26px);
  box-shadow: 0 10px 26px rgba(11, 11, 10, .07);
}
.ab-card + .ab-card { margin-top: clamp(12px, 1.4vw, 18px); }
.ab-card p {
  font-size: clamp(13.5px, 1.02vw, 15px);
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0 0 12px;
}
.ab-card p:last-child { margin-bottom: 0; }
.ab-card--tall { position: relative; z-index: 2; }

/* The pile. The two backs are empty boxes rotated behind the real card, so
   nothing readable is ever on a tilt. */
/* Room on every side for the two behind to show. */
.ab-stack { position: relative; padding: 18px 26px 20px 20px; }
.ab-stack-back {
  position: absolute;
  inset: 0;
  border-radius: 3px;
}
/* Out to the left and up: its left edge and top corner are what show. */
.ab-stack-back--olive {
  background: var(--olive);
  transform: rotate(-1.6deg) translate(-20px, -12px);
}
/* Across the top and down the right. Turned the other way, so the corner that
   dips below the card in front is the bottom right — which is the shape of the
   pile Mona drew. */
.ab-stack-back--accent {
  background: var(--accent-fill);
  transform: rotate(2deg) translate(22px, -10px);
}

/* Headings site-wide are condensed capitals; these three are Mona's hand, so
   they have to undo both. Sentence case is the point of them. */
.ab-hand-title {
  font-family: var(--script);
  font-weight: 600;
  font-size: clamp(26px, 2.7vw, 37px);
  line-height: 1.16;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  margin: 0 0 clamp(12px, 1.4vw, 18px);
}
.ab-hand-title--lg { font-size: clamp(28px, 3.1vw, 43px); }

/* ---------------------------------------------------------- healthy plates */

.ab-dish { margin: 0; border-radius: var(--radius-portrait); overflow: hidden; }
/* Cropped rather than letterboxed: the source is a wide separator image, and
   at the column's full width it was a thin strip beside a tall block of text. */
.ab-dish img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: center;
}

.ab-healthy-body { position: relative; }
/* The maquette draws a hand's arrow from the photograph to the heading. It is
   only ever true side by side, so it appears with the two-column layout. */
.ab-arrow {
  display: none;
  width: clamp(150px, 15vw, 215px);
  height: auto;
  /* Back across the gutter, so the tail starts over the photograph rather
     than hanging in the space beside it. */
  margin: 0 0 clamp(-14px, -1vw, -6px) clamp(-96px, -6.5vw, -44px);
  fill: none;
  stroke: var(--olive);
  stroke-width: 4.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .9;
}
/* Under the heading and clear of it. Absolutely positioned it landed on top
   of the last word, which is the sort of thing only a render shows. */
.ab-healthy-body .ab-chilli--small {
  display: block;
  margin: 0 0 clamp(10px, 1.2vw, 16px);
  transform: rotate(-14deg);
}

@media (min-width: 900px) {
  .ab-arrow { display: block; }
}

/* ------------------------------------------------------------ the closing */

/* One line, as it is written. It is a sentence with a colon in it, and broken
   over three lines it read as three thoughts. Only where there is room: on a
   narrow screen it wraps like anything else. */
.ab-contrast .ab-hand-title { max-width: none; }
@media (min-width: 900px) {
  .ab-contrast .ab-hand-title {
    white-space: nowrap;
    /* As large as the longest of the three languages allows on one line —
       English needs the most room, and at 30px it still has some to spare. */
    font-size: clamp(19px, 2.1vw, 30px);
  }
}

.ab-quote { position: relative; padding-top: clamp(28px, 4vw, 54px); }
.ab-quote blockquote {
  font-family: var(--display);
  font-size: clamp(22px, 2.55vw, 36px);
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0;
  position: relative;
  /* Room for the closing mark. Without it the Spanish, which ends its last
     line further right than the French, runs under it. */
  padding-right: clamp(26px, 3.2vw, 54px);
}
/* The quotation marks are the maquette's, in terracotta and large enough to
   read as a mark rather than as punctuation. */
.ab-quote blockquote::before,
.ab-quote blockquote::after {
  content: "\201C";
  position: absolute;
  font-family: var(--display);
  font-size: clamp(70px, 9vw, 128px);
  line-height: 1;
  color: var(--accent-fill);
  pointer-events: none;
}
.ab-quote blockquote::before { top: clamp(-46px, -4.6vw, -30px); left: -.06em; }
.ab-quote blockquote::after  {
  content: "\201D";
  right: -.02em;
  bottom: clamp(-56px, -5.4vw, -34px);
}

.ab-closing {
  font-size: clamp(13.5px, 1.05vw, 15px);
  line-height: 1.6;
  color: var(--ink-soft);
  margin: clamp(22px, 2.4vw, 30px) 0 0;
  max-width: 52ch;
}
.ab-hand-line {
  font-family: var(--script);
  font-size: clamp(22px, 2.3vw, 31px);
  line-height: 1.2;
  color: var(--ink);
  margin: clamp(14px, 1.6vw, 20px) 0 clamp(16px, 1.8vw, 22px);
}

/* ------------------------------------------------------------- app promo */

.app-section {
  background: var(--ground);
  color: var(--paper);
  border-top: 5px solid var(--accent-fill);
  overflow: hidden;
}

.app-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: clamp(32px, 6vw, 76px);
  align-items: center;
  padding-block: clamp(52px, 8vw, 104px) 0;
}

.app-title {
  font-size: clamp(34px, 5vw, 66px);
  margin-top: 14px;
  color: var(--paper);
}
.app-lede {
  margin-top: 20px;
  max-width: 46ch;
  font-size: clamp(16px, 1.7vw, 18.5px);
  color: var(--ground-dim);
}

.app-points {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: grid;
  gap: 11px;
  max-width: 46ch;
}
.app-points li {
  position: relative;
  padding-left: 26px;
  font-size: 15.5px;
  color: var(--paper);
}
/* small chilli-red tick */
.app-points li::before {
  content: "";
  position: absolute;
  left: 0; top: .55em;
  width: 11px; height: 11px;
  background: var(--accent-fill);
}

.app-cta {
  margin-top: clamp(28px, 4vw, 38px);
  padding-bottom: clamp(52px, 8vw, 96px);
}

/* Apple's badge must not be recoloured, rotated or given effects, and needs
   clear space around it — so the "not yet" state lives in the label beside it,
   never on the badge itself. */
.app-store {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.app-store-badge {
  display: block;
  width: 170px;
  height: auto;
  /* clear space: Apple asks for at least 1/10th of the badge height */
  margin: 6px;
}
.app-store-link { display: inline-block; transition: opacity .18s var(--ease); }
.app-store-link:hover { opacity: .85; }

.app-store-when {
  margin: 0;
  display: grid;
  gap: 1px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ground-dim);
}
.app-store-when strong {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 22px;
  letter-spacing: .03em;
  color: var(--paper);
}

.app-note {
  margin: 14px 0 0;
  font-size: 13.5px;
  color: var(--ground-dim);
  opacity: .85;
}

/* Two phones, the front one overlapping — screenshots are the real app. */
.app-shots {
  position: relative;
  align-self: end;
  min-height: 300px;
  padding-top: 20px;
}
.app-shot {
  border-radius: 22px;
  box-shadow: 0 30px 60px -24px rgba(0, 0, 0, .85);
  border: 1px solid rgba(247, 247, 247, .14);
}
.app-shot-back {
  width: 62%;
  position: absolute;
  right: 4%;
  bottom: -6%;
  transform: rotate(4deg);
  opacity: .82;
}
.app-shot-front {
  width: 68%;
  position: relative;
  margin-left: 2%;
  transform: rotate(-2.5deg);
  margin-bottom: -8%;
}

@media (max-width: 900px) {
  .app-inner { grid-template-columns: 1fr; gap: 8px; }
  .app-cta { padding-bottom: clamp(34px, 6vw, 52px); }
  .app-shots { min-height: 0; max-width: 460px; margin-inline: auto; }
  .app-shot-front { margin-bottom: -14%; }
}

/* ------------------------------------------------------- card flourish */

/* A petal fan behind each dish, tinted with a vivid colour sampled from that
   dish's own photo. Purely decorative, so it is aria-hidden and never
   intercepts a click. */
/* The chilli from the logo, peeking out behind the top-right corner. The mark
   is a PNG, so it is used as a mask over a solid fill rather than as an image —
   that way it still takes the vivid colour lifted from the dish photo. */
.card-flourish {
  position: absolute;
  z-index: 0;
  top: -30px;
  right: -58px;
  width: 74%;
  max-width: 230px;
  aspect-ratio: 1340 / 296;
  pointer-events: none;
  opacity: .92;
  background: currentColor;
  -webkit-mask: url("/assets/img/logo-chilli.png?v=89c8ee2b") no-repeat center / contain;
  mask: url("/assets/img/logo-chilli.png?v=89c8ee2b") no-repeat center / contain;
  transform: rotate(-28deg) scaleX(-1);
  transition: transform .6s var(--ease), opacity .4s var(--ease);
}

.card:hover .card-flourish {
  transform: rotate(-22deg) scaleX(-1) scale(1.07);
  opacity: 1;
}

/* The photo has to sit above the flourish for the peek-out to read. */
.card-frame { z-index: 1; }

@media (max-width: 560px) {
  .card-flourish { width: 70%; right: -44px; top: -18px; }
}

/* -------------------------------------------------- floating background */

.bg-float {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  contain: strict;            /* keeps this layer out of the page's layout work */
}

.bg-item {
  position: absolute;
  width: var(--size);
  height: var(--size);
  color: var(--olive);
  opacity: .1;
  will-change: transform;
  animation-name: bg-drift-a;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
.bg-item svg { width: 100%; height: 100%; }

.bg-item.bg-drift-b { animation-name: bg-drift-b; color: var(--accent); }
.bg-item.bg-drift-c { animation-name: bg-drift-c; color: var(--ink-soft); opacity: .07; }

/* Longer travel than before so the field visibly moves rather than breathing. */
@keyframes bg-drift-a {
  from { transform: translate3d(0, 0, 0) rotate(var(--rot)); }
  to   { transform: translate3d(48px, -66px, 0) rotate(calc(var(--rot) + 22deg)); }
}
@keyframes bg-drift-b {
  from { transform: translate3d(0, 0, 0) rotate(var(--rot)); }
  to   { transform: translate3d(-58px, 52px, 0) rotate(calc(var(--rot) - 20deg)); }
}
@keyframes bg-drift-c {
  from { transform: translate3d(0, 0, 0) rotate(var(--rot)); }
  to   { transform: translate3d(40px, 58px, 0) rotate(calc(var(--rot) + 16deg)); }
}

/* Everything real sits above the decoration. NB: do not set `position` on
   .site-header here — it is already `sticky`, and overriding it to `relative`
   silently unsticks the header. Raising its z-index is enough. */
.site-header { z-index: 60; }
main, .site-footer { position: relative; z-index: 1; }
/* Overflow is contained on #dishes (see below) rather than on main — clipping
   main stops the recipe page's sticky ingredients rail from pinning. */

@media (prefers-reduced-motion: reduce) {
  .bg-item { animation: none; transform: rotate(var(--rot)); }
}

/* Small screens: thin the field so text never fights the pattern. */
@media (max-width: 700px) {
  .bg-item { opacity: .07; }
  .bg-item:nth-child(2n) { display: none; }
}



/* -------------------------------------------------------- grid paging */

.grid-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding-bottom: clamp(56px, 9vw, 110px);
  margin-top: calc(-1 * clamp(30px, 5vw, 60px));
}
.grid-count {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ------------------------------------------------------- dish controls */

.dish-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 22px;
  border-top: 2px solid var(--olive);
  margin-top: clamp(30px, 5vw, 52px);
  padding-top: 20px;
}
/* the filter row now lives inside .dish-controls, which owns the rule above it */
.dish-controls .filters {
  border-top: 0;
  margin-top: 0;
  padding-top: 0;
  flex: 1 1 auto;
}

.search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 1 300px;
  min-width: 210px;
}
.search-icon {
  position: absolute;
  left: 12px;
  color: var(--muted);
  pointer-events: none;
}
.search input {
  width: 100%;
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink);
  padding: 9px 34px 9px 36px;
  border: 1.5px solid var(--line);
  border-radius: 0;
  background: var(--surface);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
  -webkit-appearance: none;
  appearance: none;
}
.search input::placeholder { color: var(--muted); opacity: .8; }
.search input::-webkit-search-cancel-button { display: none; }
.search input:focus {
  outline: 0;
  border-color: var(--olive);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--olive) 18%, transparent);
}

.search-clear {
  position: absolute;
  right: 6px;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border: 0; background: none;
  color: var(--muted);
  font-size: 19px; line-height: 1;
  cursor: pointer;
}
.search-clear:hover { color: var(--accent); }
/* `display: grid` above outranks the [hidden] attribute's display:none. */
.search-clear[hidden] { display: none; }

@media (max-width: 700px) {
  .dish-controls { flex-direction: column; align-items: stretch; }
  .search { flex: 1 1 auto; order: -1; }
}

/* ---------------------------------------------------------------- contact */

.contact { background: var(--paper); }

.contact-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(30px, 5vw, 72px);
  align-items: center;
  padding-block: clamp(52px, 8vw, 96px);
}
@media (max-width: 820px) {
  .contact-inner { grid-template-columns: 1fr; gap: 34px; }
}

.contact-title { font-size: clamp(38px, 6vw, 74px); margin-top: 12px; }
.contact-lede {
  margin-top: 18px;
  max-width: 44ch;
  font-size: clamp(16px, 1.7vw, 18.5px);
  color: var(--ink-soft);
}

.contact-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }

.contact-list a {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 20px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  transition: border-color .18s var(--ease), transform .18s var(--ease),
              background .18s var(--ease);
}
.contact-list a:hover {
  border-color: var(--olive);
  transform: translateX(4px);
}

.contact-icon {
  flex: none;
  border-radius: 50%;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  color: var(--paper);
  background: var(--olive);
}
.contact-icon svg { width: 21px; height: 21px; }
.contact-list li:nth-child(2) .contact-icon { background: var(--accent-fill); color: var(--ink); }
.contact-list li:nth-child(3) .contact-icon { background: var(--ink); }

.contact-text { display: grid; gap: 2px; min-width: 0; }
.contact-text small {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.contact-text strong {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 21px;
  letter-spacing: .02em;
  color: var(--ink);
  overflow-wrap: anywhere;
}




/* ----------------------------------------------------------- hero banner */

/* Full-bleed photo as the ground for the opening copy. The picture rotates, so
   the scrim has to hold up over anything from a dark slate plate to a white
   bowl in daylight — hence a fixed dark wash rather than a per-image guess. */
.hero-banner {
  --hero-accent: var(--accent-fill);
  position: relative;
  display: grid;
  /* Without an explicit track the implicit column sizes to its content, and the
     `margin-inline:auto` on .wrap then centres that narrow box — which pushes
     the copy off the page's left alignment. */
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  min-height: clamp(540px, 82vh, 880px);
  padding-block: clamp(56px, 9vw, 104px) clamp(64px, 8vw, 96px);
  overflow: hidden;
  background: var(--ink);
  border-bottom: 4px solid var(--hero-accent);
  transition: border-color .9s var(--ease);
  isolation: isolate;
}

.hero-banner-media { position: absolute; inset: 0; z-index: 0; }

.hero-banner-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 52%;
  opacity: 0;
  transition: opacity .9s var(--ease);
}
.hero-banner-img.is-active { opacity: 1; }

.hero-banner-scrim {
  position: absolute;
  inset: 0;
  background:
    /* Heavy under the copy, easing off over the right of the plate. */
    linear-gradient(100deg,
      rgba(11, 11, 10, .94) 0%,
      rgba(11, 11, 10, .90) 38%,
      rgba(11, 11, 10, .62) 66%,
      rgba(11, 11, 10, .40) 100%),
    linear-gradient(to top, rgba(11, 11, 10, .78) 0%, rgba(11,11,10,.10) 46%),
    /* A flat floor so no single bright photo can wash the type out. */
    rgba(11, 11, 10, .22);
}

.hero-banner-content {
  position: relative;
  z-index: 1;
  /* .wrap's `margin-inline: auto` suppresses grid stretch, so the box would
     shrink-wrap its text and then centre — losing the page's left alignment.
     An explicit width restores it; max-width still caps the measure. */
  width: 100%;
}
/* Keep the copy inside the darkest part of the wash rather than letting it run
   across the plate, which is where the photo is brightest. */
.hero-banner-content > * { max-width: min(730px, 65%); }
@media (max-width: 900px) { .hero-banner-content > * { max-width: 100%; } }

/* The Spanish and French headlines are ~25% longer than the English one. At a
   single size they wrapped to five lines and grew the whole banner by 160px on
   every language switch, so each language gets a size that lands on the same
   number of lines and keeps the section height stable. */
:root[lang="es"] .hero-banner .hero-title,
:root[lang="fr"] .hero-banner .hero-title {
  font-size: clamp(34px, 5.9vw, 78px);
  max-width: 18ch;
}

/* Type on the photo */
.hero-banner .hero-title { color: var(--paper); max-width: 15ch; }
.hero-banner .hero-title .red { color: var(--accent-bright); }
.hero-banner .hero-lede { color: #DCDECB; max-width: 46ch; }
.hero-banner .eyebrow { color: #B9BCA6; }

.btn-on-dark {
  background: var(--paper);
  border-color: var(--paper);
  color: var(--ink);
}
.btn-on-dark:hover {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--ink);
}

@media (max-width: 760px) {
  .hero-banner {
    min-height: clamp(500px, 76vh, 720px);
  }
  /* On a narrow column the side gradient does nothing — darken from the floor. */
  .hero-banner-scrim {
    background: linear-gradient(to top,
      rgba(11, 11, 10, .92) 0%,
      rgba(11, 11, 10, .74) 46%,
      rgba(11, 11, 10, .46) 100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-banner-img { transition: none; }
}




/* ----------------------------------------------------------- hero banner */

/* A sibling of .wrap rather than a child, so it spans the page edge to edge
   without a 100vw trick (which overflows whenever a scrollbar is present). */
.hero-banner {
  --hero-accent: var(--olive);
  position: relative;
  border-top: 3px solid var(--ink);
  border-bottom: 3px solid var(--hero-accent);
  background: var(--paper-warm);
  transition: border-color .9s var(--ease);
}

/* Two stacked layers crossfade; the stage owns the height so the images can be
   absolutely positioned without the band collapsing between swaps. */
.hero-banner-stage {
  display: block;
  position: relative;
  height: clamp(280px, 46vh, 620px);
  overflow: hidden;
}
.hero-banner-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 52%;
  opacity: 0;
  transition: opacity .9s var(--ease);
}
.hero-banner-img.is-active { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .hero-banner-img { transition: none; }
}



/* ----------------------------------------------------------- hero figure */

.hero-figure {
  margin: 0;
  position: relative;
}
.hero-figure img {
  width: 100%;
  height: auto;
  background: var(--paper-warm);
}

/* The dish on the pass, credited under the photo. */
.hero-figure figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 14px;
  padding-top: 12px;
  border-top: 2px solid var(--olive);
  margin-top: 12px;
}
.hero-figure figcaption a {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(15px, 1.5vw, 19px);
  letter-spacing: .03em;
  color: var(--ink);
  transition: color .18s var(--ease);
}
.hero-figure figcaption a:hover { color: var(--accent); }

@media (max-width: 520px) {
  .brand .brand-logo { height: 50px; }
  .nav { gap: 9px 13px; }
  .nav a { font-size: 13px; }
  .hero-figure figcaption { flex-direction: column; gap: 4px; }
}

/* ---------------------------------------------------------------- ticker */

/* Two identical runs sit side by side; the track slides exactly one run width
   and restarts, so the loop is seamless with no JS. */
/* Full-strength olive, so the band still reads as its own stripe against the
   deeper --ground of the section below it. */
.ticker {
  background: var(--olive);
  border-block: 3px solid var(--ground);
  overflow: hidden;
  padding-block: 13px;
}

.ticker-track {
  display: flex;
  width: max-content;
  animation: ticker-slide 34s linear infinite;
  will-change: transform;
}
.ticker:hover .ticker-track { animation-play-state: paused; }

.ticker-run {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.4vw, 34px);
  padding-right: clamp(18px, 2.4vw, 34px);
  flex: none;
}

@keyframes ticker-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.ticker-item {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(17px, 2vw, 26px);
  letter-spacing: .15em;
  line-height: 1;
  color: var(--paper);
  white-space: nowrap;
}
.ticker-chilli {
  height: clamp(13px, 1.5vw, 19px);
  width: auto;
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .ticker-track { animation: none; }
}

/* ------------------------------------------------------------------ forms */

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 18px;
  margin-top: 6px;
}
.form-status {
  margin: 0; font-size: 13.5px; line-height: 1.45; color: var(--muted); flex: 1 1 200px;
}
.form-status.is-ok { color: var(--olive); font-weight: 600; }
.form-status.is-error { color: var(--accent); }

.checks legend {
  font-size: 11px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 9px;
}
.checks { border: 0; padding: 0; margin: 0 0 20px; }
.checks label {
  display: flex; align-items: center; gap: 9px;
  font-size: 14.5px; color: var(--ink-soft);
  margin-bottom: 7px; cursor: pointer;
  text-transform: none; letter-spacing: 0;
}
.checks input { width: 17px; height: 17px; accent-color: var(--olive); flex: none; }

/* ---------------------------------------------------------- contact layout */

/* Copy and the contact methods stack down the left; the form fills the right
   across both rows. Without explicit placement the form wrapped underneath the
   copy and left the right half empty. */
/* Copy and the contact pills form one column, centred against the form. They
   used to be separate grid items, which let the tall form stretch the row
   between them and push the pills to the bottom. */
.contact-inner {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: center;
}
.contact-side { display: grid; gap: 0; }
.contact-form {
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: 18px;
  padding: clamp(22px, 3vw, 30px);
}
/* Heading and submit centred; the fields themselves stay left-aligned so the
   labels still line up with what you type. */
.contact-form > .eyebrow { text-align: center; }
.contact-form .form-actions {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 10px;
}
.contact-form .form-status { flex: none; text-align: center; max-width: 44ch; }
.contact-list { margin-top: 26px; }

/* ------------------------------------------------------------- subscribe */

.subscribe {
  background: var(--ground);
  color: var(--paper);
  border-top: 4px solid var(--accent-fill);
}
.subscribe-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .92fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  padding-block: clamp(52px, 8vw, 96px);
}
@media (max-width: 880px) {
  .subscribe-inner { grid-template-columns: 1fr; gap: 34px; }
}

.subscribe-title { font-size: clamp(34px, 5vw, 64px); margin-top: 12px; color: var(--paper); }
.subscribe-lede {
  margin-top: 18px; max-width: 44ch;
  font-size: clamp(16px, 1.7vw, 18.5px); color: var(--ground-dim);
}

.subscribe-perks { list-style: none; margin: 30px 0 0; padding: 0; display: grid; gap: 18px; }
.subscribe-perks li { display: flex; gap: 15px; align-items: flex-start; }
.perk-icon {
  flex: none; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-fill); color: var(--ink);
}
.perk-icon svg { width: 20px; height: 20px; }
.subscribe-perks strong {
  display: block;
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 19px; letter-spacing: .03em; color: var(--paper);
  margin-bottom: 2px;
}
.subscribe-perks span span, .subscribe-perks li > span:last-child {
  font-size: 14.5px; color: var(--ground-dim); line-height: 1.5;
}

.subscribe-form {
  background: var(--surface);
  color: var(--ink);
  border-radius: 18px;
  padding: clamp(24px, 3vw, 32px);
}
.subscribe-form-title { font-size: 30px; margin-bottom: 8px; }
.subscribe-form-note { font-size: 14px; color: var(--muted); margin: 0 0 22px; line-height: 1.55; }

/* ------------------------------------------------------- footer instagram */

.footer-ig {
  display: inline-flex; align-items: center; gap: 12px;
  margin-top: 20px; padding: 10px 18px 10px 12px;
  border: 1.5px solid rgba(227, 228, 213, .28);
  border-radius: 999px;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.footer-ig:hover { border-color: var(--accent-fill); background: rgba(199, 114, 101, .12); }
.footer-ig-glyph {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-fill); color: var(--ink);
}
.footer-ig-glyph svg { width: 19px; height: 19px; }
.footer-ig-text { display: grid; gap: 1px; }
.footer-ig-text small {
  font-size: 10.5px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ground-dim);
}
.footer-ig-text strong {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 18px; letter-spacing: .03em; color: var(--paper);
}

/* ---------------------------------------------------------------- slogan */

/* The brand line, given real presence rather than eyebrow-sized fine print. */
.tagline {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 clamp(14px, 2vw, 22px);
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(17px, 2.2vw, 27px);
  letter-spacing: .17em;
  line-height: 1;
  color: var(--accent);
}

/* Doubled class so this beats plain `.tagline` whatever the source order — the
   hero sits on a dark photo and needs the lifted shade that "balance." uses. */
.tagline.tagline-on-dark { color: var(--accent-bright); }

.tagline-chilli {
  height: clamp(15px, 1.9vw, 23px);
  width: auto;
  flex: none;
}


/* --------------------------------------------------------- about, extended */

.about-points {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.about-points li {
  position: relative;
  padding-left: 22px;
  font-size: clamp(13.5px, 1.02vw, 15px);
  line-height: 1.5;
  color: var(--ink-soft);
}
.about-points li::before {
  content: "";
  position: absolute;
  left: 0; top: .55em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent-fill);
}

/* ------------------------------------------------------- language switcher */

.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}
.lang-btn {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 12.5px;
  letter-spacing: .08em;
  color: var(--muted);
  background: none;
  border: 0;
  border-radius: 999px;
  padding: 5px 10px;
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.lang-btn:hover { color: var(--ink); }
.lang-btn.is-active { background: var(--olive); color: #fff; }

/* On the dark hero/footer the switcher inverts. */
.site-footer .lang-switch { border-color: rgba(227,228,213,.28); background: transparent; }
.site-footer .lang-btn { color: #9C9F8C; }
.site-footer .lang-btn:hover { color: var(--paper); }
.site-footer .lang-btn.is-active { background: var(--accent-fill); color: var(--ink); }

@media (max-width: 620px) {
  .lang-btn { padding: 4px 8px; font-size: 11.5px; }
}

.about-closing {
  margin: 0 0 14px;
  font-size: 16.5px;
  color: var(--ink-soft);
  max-width: 54ch;
  line-height: 1.6;
}
.about-quote blockquote + .about-closing { margin-top: 4px; }
.about-closing + .btn { margin-top: 10px; }

/* The quote itself stays left under its opening mark; the copy and the button
   that follow are centred in the column. */
.about-quote .about-closing {
  text-align: center;
  margin-inline: auto;
}
.about-quote > .btn {
  display: block;
  width: fit-content;
  margin-inline: auto;
}


/* ---------------------------------------------------- footer brand + login */

/* The Instagram badge sits beside the lockup, centred against it. */
.footer-brand {
  display: flex;
  align-items: center;
  gap: clamp(18px, 3vw, 34px);
  flex-wrap: wrap;
}
.footer-brand .footer-logo { margin: 0; }
.footer-brand .footer-ig { margin-top: 0; }



/* ------------------------------------------------------- dish separator */

/* A full-bleed slice of one dish, breaking the run of dark sections. */
.dish-separator {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--paper-warm);
  border-top: 4px solid var(--accent-fill);
  border-bottom: 4px solid var(--ground);
}
.dish-separator img {
  display: block;
  width: 100%;
  height: clamp(180px, 26vh, 300px);
  object-fit: cover;
  object-position: center 48%;
  transition: transform 1.1s var(--ease);
}
.dish-separator:hover img { transform: scale(1.035); }

.dish-separator-label {
  position: absolute;
  left: 0; bottom: 0;
  display: grid;
  gap: 2px;
  padding: 22px clamp(20px, 5vw, 64px) 16px;
  color: var(--paper);
  /* Two stops rather than one: with a single fade the eyebrow sat where the
     gradient had almost run out, and "FROM THE COLLECTION · SHARING" was pale
     text on whatever the photograph happened to be doing up there. */
  background: linear-gradient(to top,
              rgba(11,11,10,.88) 0%, rgba(11,11,10,.62) 55%, transparent 100%);
  width: 100%;
}
.dish-separator-label .eyebrow { color: #C9CCB8; }
/* "From the collection · Sharing" — the dot spaced like the one on a dish card. */
.dish-separator-label .sep-dot { margin: 0 .45em; opacity: .7; }
.dish-separator-label strong {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(17px, 2vw, 24px);
  letter-spacing: .04em;
  transition: color .18s var(--ease);
}
.dish-separator:hover strong { color: var(--accent-bright); }


/* ------------------------------------------------------ footer right rail */

.footer-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 18px;
}
@media (max-width: 720px) {
  .footer-right { align-items: flex-start; }
}

/* The chef's door: present in the footer, deliberately understated. */
.login-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 13px;
  letter-spacing: .12em;
  color: var(--ground-dim);
  padding: 8px 17px;
  border: 1.5px solid rgba(227, 228, 213, .26);
  border-radius: 999px;
  transition: color .18s var(--ease), border-color .18s var(--ease), background .18s var(--ease);
}
.login-link:hover {
  color: var(--paper);
  border-color: var(--accent-fill);
  background: rgba(199, 114, 101, .14);
}
.login-lock { display: grid; place-items: center; }
.login-lock svg { width: 14px; height: 14px; }

/* Closing line, centred under everything. */
.footer-made {
  margin-top: clamp(30px, 5vw, 48px);
  padding-top: 22px;
  border-top: 1px solid rgba(227, 228, 213, .16);
  text-align: center;
}
.footer-made p {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(12px, 1.3vw, 15px);
  letter-spacing: .18em;
  color: var(--ground-dim);
  opacity: .8;
}

/* ------------------------------------------------- contact methods, compact */

/* Three small, evenly-sized pills sitting centred under the copy, rather than
   three full-width bars stacked down the column. */
.contact-list {
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
}
.contact-list li { flex: 0 1 auto; }
.contact-list a {
  gap: 10px;
  padding: 10px 16px 10px 11px;
  border-radius: 999px;
}
.contact-list a:hover { transform: translateY(-2px); }
.contact-icon { width: 32px; height: 32px; }
.contact-icon svg { width: 16px; height: 16px; }
.contact-text small { font-size: 9.5px; letter-spacing: .14em; }
.contact-text strong { font-size: 15px; }

.contact-copy { text-align: center; }
.contact-copy .contact-lede { margin-inline: auto; }
@media (max-width: 820px) {
  .contact-list { justify-content: flex-start; }
  .contact-copy { text-align: left; }
  .contact-copy .contact-lede { margin-inline: 0; }
}


/* ------------------------------------------ eyebrows on the dark ground */

/* --accent (#874F46) was chosen against the pale page and drops to 1.75:1 on
   --ground. The lifted shade gives 5.4:1 and matches "balance." in the hero. */
.app-section .eyebrow-red,
.subscribe .eyebrow-red,
.app-section .eyebrow,
.subscribe .eyebrow {
  color: var(--accent-bright);
  letter-spacing: .2em;
}
.app-store-when { color: var(--ground-dim); }

/* ------------------------------------------------- living page background */

/* Two very slow, very faint warm washes drifting across the paper. It reads as
   the page quietly breathing rather than as an animation. */
body::before {
  content: "";
  position: fixed;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 32% at 22% 28%, rgba(199, 114, 101, .16), transparent 68%),
    radial-gradient(34% 30% at 78% 62%, rgba(84, 104, 43, .16), transparent 68%),
    radial-gradient(30% 26% at 52% 88%, rgba(203, 186, 171, .16), transparent 70%);
  animation: page-breathe 46s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes page-breathe {
  from { transform: translate3d(-2.5%, -1.5%, 0) scale(1); }
  to   { transform: translate3d(2.5%, 2%, 0) scale(1.08); }
}

@media (prefers-reduced-motion: reduce) {
  body::before { animation: none; }
}

/* ------------------------------------------------------- cursor ember trail */

.cursor-flame {
  position: fixed;
  inset: 0;
  z-index: 90;            /* above content, below the lightbox (200) */
  pointer-events: none;
}

/* ------------------------------------------------------------------ print */

/* People cook from paper. A recipe should print as a clean single-column
   sheet: the dish, its ingredients, its method — no chrome, no decoration. */
@media print {
  .site-header,
  .site-footer,
  .bg-float,
  .cursor-flame,
  .ticker,
  .dish-separator,
  .login-strip,
  .app-section,
  .subscribe,
  .contact,
  .lang-switch,
  .back-link,
  .ig-embed,
  .ig-link,
  .gallery,
  .gallery-block,
  .lightbox,
  .dish-controls,
  .grid-more,
  .hero-banner,
  .hero { display: none !important; }

  body::before { display: none !important; }

  html, body {
    background: #fff !important;
    color: #000 !important;
    font-size: 11pt;
  }

  .wrap, .recipe-body { max-width: none; padding: 0; margin: 0; }

  /* Single column — the sticky rail makes no sense on paper. */
  .recipe-body { display: block; }
  .rail { position: static; }
  .rail-card { border: 0; padding: 0; background: none; }

  .recipe-title { font-size: 26pt; margin-bottom: 4pt; }
  .recipe-lede { font-size: 11pt; margin-bottom: 8pt; }
  .section-head { border-bottom: 1pt solid #000; margin: 14pt 0 8pt; }
  .section-head h2 { font-size: 14pt; }

  .recipe-facts { border-top: 1pt solid #000; border-bottom: 1pt solid #000; }
  .fact { padding: 6pt 16pt 6pt 0; margin-right: 16pt; }
  .fact-value { font-size: 12pt; }

  /* One photo, small — enough to recognise the dish, not enough to eat ink. */
  .recipe-figure { max-width: 62mm; margin: 0 0 10pt; break-inside: avoid; aspect-ratio: 1 / 1; }
  .step-media { display: none; }

  .ing-list li { padding: 2pt 0; border-bottom: .3pt solid #999; }
  .ing-amt { color: #000; font-weight: 700; }

  .step { break-inside: avoid; padding-bottom: 8pt; grid-template-columns: 22pt 1fr; gap: 8pt; }
  .step-num {
    width: 20pt; height: 20pt; font-size: 10pt;
    background: none; color: #000; border: 1pt solid #000;
  }
  .step:not(:last-child)::after { display: none; }
  .step-text { font-size: 10.5pt; line-height: 1.45; }

  a { text-decoration: none; color: #000; }
  /* The URL is the only way back to the source from a printout. */
  article::after {
    content: "monaspice.com";
    display: block;
    margin-top: 14pt;
    padding-top: 6pt;
    border-top: .5pt solid #999;
    font-size: 8pt;
    letter-spacing: .12em;
    text-transform: uppercase;
  }

  @page { margin: 14mm; }
}

/* Dietary chips, set apart from the category chips by a divider. */
.chip-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-left: 12px;
  margin-left: 4px;
  border-left: 1.5px solid var(--line);
}
.chip-diet.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (max-width: 700px) {
  .chip-group { padding-left: 0; margin-left: 0; border-left: 0; }
}

.checks-inline { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-bottom: 0; }
.checks-inline label { margin-bottom: 0; }

/* Team rows have no thumbnail, so they need their own column shape. */
.admin-row.team-row { grid-template-columns: minmax(0, 1fr) auto auto; }

/* ---------------------------------------------------------- editor extras */

.list-tools {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 14px; margin-bottom: 16px;
}
.row-actions { display: flex; gap: 8px; }
.admin-row { grid-template-columns: 56px minmax(0,1fr) auto auto; }

/* Draft recovery */
.recover-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 14px;
  margin-bottom: 22px; padding: 16px 20px;
  background: var(--accent-tint);
  border: 1.5px solid var(--accent-fill);
  border-radius: 14px;
}
.recover-bar strong { display: block; font-size: 15px; }
.recover-bar span span, .recover-bar > div > span { font-size: 13.5px; color: var(--muted); }
.recover-actions { display: flex; gap: 8px; flex: none; }

/* Bulk paste */
.bulk { margin-top: 14px; }
.bulk summary {
  display: inline-flex; align-items: center; gap: 7px;
  cursor: pointer; list-style: none;
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 13px; letter-spacing: .1em; color: var(--muted);
  padding: 6px 0;
}
.bulk summary::-webkit-details-marker { display: none; }
.bulk summary::before { content: "＋"; font-size: 15px; line-height: 1; }
.bulk[open] summary::before { content: "－"; }
.bulk summary:hover { color: var(--ink); }
.bulk-text {
  width: 100%; font-family: var(--sans); font-size: 14.5px; line-height: 1.55;
  padding: 12px 13px; border: 1.5px solid var(--line); background: var(--surface);
  resize: vertical;
}
.bulk-text:focus { outline: 0; border-color: var(--olive); }
.bulk-actions { display: flex; gap: 8px; margin-top: 10px; }

/* Ingredient reordering */
.row-move { display: flex; flex-direction: column; gap: 2px; flex: none; padding-top: 2px; }
.icon-btn-xs { width: 26px; height: 18px; font-size: 11px; border-radius: 4px; }

/* Visual step-photo picker */
.photo-pick { display: flex; flex-wrap: wrap; gap: 7px; }
.photo-pick-item, .photo-pick-none {
  width: 58px; height: 58px; padding: 0; cursor: pointer;
  border: 2px solid var(--line); border-radius: 8px; overflow: hidden;
  background: var(--surface); color: var(--muted);
  display: grid; place-items: center; font-size: 17px; line-height: 1;
  transition: border-color .15s var(--ease), transform .15s var(--ease);
}
.photo-pick-item img { width: 100%; height: 100%; object-fit: cover; }
.photo-pick-item:hover, .photo-pick-none:hover { border-color: var(--muted); transform: translateY(-1px); }
.photo-pick-item.is-on, .photo-pick-none.is-on { border-color: var(--accent); }

/* Photo captions */
.thumbs { align-items: flex-start; }
.thumb-cell { display: grid; gap: 6px; width: 124px; }
.thumb-caption {
  width: 92px; font-family: var(--sans); font-size: 11.5px;
  padding: 5px 7px; border: 1.5px solid var(--line); background: var(--surface);
}
.thumb-caption:focus { outline: 0; border-color: var(--olive); }

/* Preview banner on the recipe page */
.preview-bar {
  position: sticky; top: 0; z-index: 120;
  background: var(--accent-fill); color: var(--ink);
  text-align: center; padding: 9px 16px;
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 13px; letter-spacing: .12em;
}

/* The hero centres only on true phone widths. The rest of the mobile block
   uses 760px, but a zoomed browser or a half-screen desktop window lands in
   that range too — and there the banner reads better left-aligned, matching
   the header logo. */
@media (max-width: 560px) {
  .hero-banner-content { text-align: center; }
  .hero-banner-content > * { margin-inline: auto; }
  .tagline { justify-content: center; }
  .hero-title, .hero-lede { margin-inline: auto; }
  .hero-meta { justify-content: center; }
}

/* ================================================================= mobile
   On a narrow column, left-aligned blocks with different measures read as
   ragged. Everything centres, with one exception: rows that pair an icon with
   text stay left-aligned inside a centred block, because centring text beside a
   fixed icon just looks broken. */

@media (max-width: 760px) {

  /* ---- dish grid controls */
  .dish-controls { align-items: center; }
  .filters { justify-content: center; }
  .chip-group { justify-content: center; }

  /* ---- app + club */
  .app-copy, .subscribe-copy { text-align: center; }
  .app-lede, .subscribe-lede { margin-inline: auto; }
  .app-cta { display: flex; flex-direction: column; align-items: center; }
  .app-store { justify-content: center; }
  .app-store-when { text-align: center; }
  .app-note { text-align: center; }

  /* Icon + text rows: centre the block, keep each row readable. */
  .app-points, .subscribe-perks { justify-items: center; }
  .app-points li, .subscribe-perks li { text-align: left; max-width: 22rem; }
  .app-points li { padding-left: 26px; }

  /* ---- separator */
  .dish-separator-label { text-align: center; align-items: center; justify-items: center; }

  /* ---- contact: form first, then the ways to reach you, all centred */
  .contact-inner { grid-template-columns: 1fr; gap: 26px; }
  .contact-side { order: 2; }
  .contact-form { order: 1; }
  .contact-copy { text-align: center; }
  .contact-copy .contact-lede { margin-inline: auto; }
  .contact-list {
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-top: 22px;
  }
  .contact-list li { width: 100%; max-width: 320px; }
  .contact-list a { width: 100%; }

  /* ---- footer */
  .footer-inner { flex-direction: column; align-items: center; text-align: center; gap: 22px; }
  .footer-inner { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .footer-actions { justify-items: stretch; justify-self: stretch; }
  .footer-btn { min-width: 0; justify-content: center; }
  .footer-brand { flex-direction: column; align-items: center; gap: 16px; }
  .footer-logo { margin-inline: auto; }
  .footer-right { align-items: center; }
  .footer-links { justify-content: center; }
  .login-link { margin-inline: auto; }

  /* ---- about */
  .ab-hero,
  .ab-welcome,
  .ab-healthy,
  .ab-close { grid-template-columns: minmax(0, 1fr); }
  /* The photograph belongs under the name, not after the questions. */
  .ab-portrait { order: -1; }
  .ab-hand blockquote { max-width: none; }
  .ab-healthy-body .ab-chilli--small { display: none; }
  .ab-stack { padding-right: 0; }
  .ab-stack-back--olive  { transform: rotate(-1.6deg) translate(-6px, -7px); }
  .ab-stack-back--accent { transform: rotate(1.4deg)  translate(8px, 3px); }
  .ab-quote { padding-top: clamp(34px, 13vw, 56px); }
}

/* Preview banner language pills */
.preview-bar { display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap; }
.preview-langs { display: inline-flex; gap: 4px; }
.preview-langs button {
  font: inherit; letter-spacing: .1em;
  border: 1.5px solid rgba(11,11,10,.35); background: none; color: var(--ink);
  border-radius: 999px; padding: 2px 10px; cursor: pointer;
}
.preview-langs button.is-on { background: var(--ink); color: var(--accent-bright); border-color: var(--ink); }

/* Photo reorder arrows under each thumbnail */
.thumb-move { display: flex; justify-content: center; gap: 4px; }

/* Invalid field feedback */
.field input.is-invalid { border-color: var(--accent); }
.hint-bad { color: var(--accent); }
.hint-soft { color: var(--muted); font-style: italic; }

/* ------------------------------------------------------ editor on a phone */
@media (max-width: 760px) {
  .admin-shell { padding-block: 20px 90px; }
  .panel { padding: 18px 16px; }
  .row { flex-direction: column; gap: 0; }
  .row > * { flex: 1 1 auto; }

  /* The action bar becomes a thumb-reachable block, primary action last. */
  .admin-bar { flex-wrap: wrap; gap: 8px; padding: 12px 0 18px; }
  .admin-bar .status { flex: 1 1 100%; margin: 0 0 2px; text-align: center; font-size: 12.5px; }
  .admin-bar .btn { flex: 1 1 45%; }
  .admin-bar .btn:last-child { flex: 1 1 100%; order: 5; }

  .step-editor { padding: 14px 12px; }
  .repeat-item { flex-wrap: wrap; }
  .repeat-item input[data-f="amount"] { flex: 0 0 96px !important; }
  .photo-pick-item, .photo-pick-none { width: 52px; height: 52px; }

  .list-tools { flex-direction: column; align-items: stretch; }
  .list-tools .search { flex: 1 1 auto; }
  .admin-row { grid-template-columns: 48px minmax(0,1fr); row-gap: 8px; }
  .admin-row .pill { justify-self: start; grid-column: 2; }
  .row-actions { grid-column: 1 / -1; flex-wrap: wrap; }
  .recover-bar { flex-direction: column; align-items: stretch; text-align: center; }
  .recover-actions { justify-content: center; }
}

/* --------------------------------------------------------- editor UX round */

.editor-nav {
  position: sticky; top: 0; z-index: 45;
  display: flex; gap: 6px; overflow-x: auto;
  padding: 10px 0; margin-bottom: 18px;
  background: linear-gradient(to bottom, var(--paper) 82%, transparent);
  scrollbar-width: none;
}
.editor-nav::-webkit-scrollbar { display: none; }
.editor-nav a {
  flex: none;
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 12.5px; letter-spacing: .09em;
  color: var(--muted);
  padding: 6px 13px; border: 1.5px solid var(--line); border-radius: 999px;
  transition: all .15s var(--ease);
}
.editor-nav a:hover { color: var(--ink); border-color: var(--muted); }
.editor-nav a.is-on { background: var(--olive); border-color: var(--olive); color: #fff; }

/* Panels the nav jumps to shouldn't hide their heading under it. */
.panel[id], details.panel-fold[id] { scroll-margin-top: 64px; }

/* Collapsible secondary panel */
details.panel-fold > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px;
  cursor: pointer; list-style: none; margin: -4px 0;
}
details.panel-fold > summary::-webkit-details-marker { display: none; }
details.panel-fold > summary h2 { margin: 0; }
details.panel-fold > summary::after {
  content: "▾"; margin-left: auto; color: var(--muted);
  transition: transform .2s var(--ease);
}
details.panel-fold[open] > summary::after { transform: rotate(180deg); }
.fold-hint { font-size: 12.5px; color: var(--muted); }
.fold-sub {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 15px; letter-spacing: .08em; color: var(--muted);
  margin: 20px 0 12px;
}
details.panel-fold[open] > summary { margin-bottom: 6px; }

/* Autogrow textareas: the height is scripted, so kill manual resize handles */
textarea.autogrow { resize: none; overflow: hidden; min-height: 0; }

/* Camera button sits under the dropzone, phone-first */
.camera-btn { margin-top: 10px; }
@media (pointer: fine) and (min-width: 761px) { .camera-btn { display: none; } }

/* Offline banner */
.offline-bar {
  position: sticky; top: 0; z-index: 130;
  background: var(--ink); color: var(--paper);
  text-align: center; padding: 9px 16px;
  font-size: 13px; letter-spacing: .02em;
}

/* Save confirmation flash */
.btn-flash { background: var(--olive) !important; border-color: var(--olive) !important; color: #fff !important; }

/* --------------------------------------------------------- admin: site text */

/* One card per string, with the three languages side by side so a change can be
   made in all of them at once rather than three passes over the same list. */
.text-group {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  padding: 16px 18px;
  margin-bottom: 12px;
}
.text-group[hidden] { display: none; }
.text-group > summary h2 { font-size: 19px; }
.text-group-n {
  font-family: var(--sans); font-size: 12px; font-weight: 700;
  color: var(--muted); letter-spacing: .06em;
}

.text-row {
  padding: 16px 0;
  border-top: 1px solid var(--line-soft);
}
.text-row[hidden] { display: none; }
.text-row-head {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 8px;
}
.text-row-head code {
  font-size: 12px;
  color: var(--muted);
  background: var(--paper);
  padding: 2px 7px;
  border-radius: 5px;
}
.text-row-head .btn { margin-left: auto; }

.text-langs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.text-langs label { display: block; }
.text-langs label > span {
  display: block;
  font-family: var(--sans); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; color: var(--muted);
  margin-bottom: 4px;
}
.text-langs textarea {
  width: 100%;
  min-height: 46px;
  font: inherit;
  font-size: 14px;
  line-height: 1.45;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  resize: none;
}
.text-langs textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* An untouched box shows the shipped wording, greyed, so the author can see
   what they are replacing without it being mistaken for a value. */
.text-langs textarea::placeholder { color: var(--muted); opacity: .75; }

/* Three columns of text is unreadable on a phone — stack them. */
@media (max-width: 760px) {
  .text-langs { grid-template-columns: 1fr; gap: 10px; }
  .text-row-head { flex-wrap: wrap; }
  .text-row-head .btn { margin-left: 0; }
}

/* Sign-in name, inline on each row of the team panel. */
.username-field {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.username-field label {
  font-family: var(--sans); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.username-field input {
  width: 150px;
  font: inherit; font-size: 13.5px;
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #fff;
}
.username-status { font-size: 12.5px; color: var(--muted); }


/* The privacy link, small and out of the way but always reachable. */
.footer-legal {
  display: inline-block;
  /* Centred: it is the last thing on the page and belongs to nothing on either
     side of it, so aligning it left made it look like a stray link. */
  margin-inline: auto;
  font-size: .82rem;
  letter-spacing: .04em;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.footer-legal:hover,
.footer-legal:focus-visible { color: var(--ink); border-bottom-color: currentColor; }
.footer-legal-row { text-align: center; }


/* An ingredient group's heading — "For the dough". Set small and in the accent
   so it reads as a label on the list rather than as another page heading. */
.ing-section {
  font-family: var(--font-display, inherit);
  font-size: .78rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 22px 0 8px;
}
.ing-section:first-child { margin-top: 4px; }


/* The EN/ES/FR switch above the ingredients and the method in the admin.
   The count beside each language says which have been written out, so a
   half-finished translation is visible without clicking through. */
.lang-tabs { display: flex; gap: 6px; margin: 0 0 12px; }
.lang-tab {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: .82rem;
  padding: 5px 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--muted); cursor: pointer;
}
.lang-tab:hover { border-color: var(--ink); color: var(--ink); }
.lang-tab.is-on { background: var(--olive, #54682B); border-color: var(--olive, #54682B); color: var(--paper); }
.lang-count { font-size: .74rem; opacity: .75; }

/* An ingredient row that starts a section, so the grouping is visible while
   editing rather than only on the published page. */
.repeat-item.has-section { border-top: 1px solid var(--line); padding-top: 10px; }
.ing-section-input { color: var(--accent); font-size: .84rem; }


/* The admin's Numbers screen. */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; }
.stat-card {
  padding: 18px 16px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
}
.stat-value { font-family: var(--font-display, inherit); font-size: 1.9rem; line-height: 1; color: var(--ink); }
.stat-label { margin-top: 6px; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.stat-rank { width: 56px; text-align: center; font-weight: 700; color: var(--accent); }

/* One column per day, height relative to the busiest. Deliberately unlabelled
   on the y axis: the shape is the point, and a precise count is a tooltip away. */
.day-bars {
  display: flex; align-items: flex-end; gap: 4px;
  height: 160px; padding: 12px 0 0;
  overflow-x: auto;
}
.day-bar { flex: 0 0 26px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; }
.day-bar-fill { background: var(--olive, #54682B); border-radius: 2px 2px 0 0; min-height: 3px; }
.day-bar-label { margin-top: 6px; font-size: .62rem; color: var(--muted); text-align: center; }

/* ------------------------------------------------------ keyboard visibility */

/*
 * Where the keyboard is.
 *
 * The site had focus styles on three elements and `outline: none` everywhere
 * else, which means anybody navigating by keyboard was moving an invisible
 * cursor around — they could use the site exactly as well as they could use it
 * blindfolded. `:focus-visible` rather than `:focus`, so a mouse click does not
 * leave a ring behind it.
 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2.5px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* On the dark footer the accent has too little contrast to serve as a ring. */
.site-footer :where(a, button):focus-visible {
  outline-color: var(--paper);
}

/*
 * Straight to the dishes.
 *
 * Every page begins with the same six navigation links. Without this, reaching
 * the actual content by keyboard means tabbing past all of them, on every page,
 * every time. Off-screen until focused, then it comes to the top-left.
 */
.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: .04em;
  text-transform: uppercase;
  border-radius: 3px;
  transition: top .12s ease-out;
}
.skip-link:focus { top: 12px; }

/* The target must be able to take focus for the jump to move the caret too. */
#main:focus { outline: none; }

/* ------------------------------------------------------------- onwards */

/* The foot of a dish page: three more, and a step either side. */
.onwards { margin-top: 56px; padding-bottom: 8px; }

.onward-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-top: 16px;
}

.onward-card { display: block; }
.onward-photo {
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 3px;
  margin-bottom: 9px;
}
.onward-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.onward-card:hover .onward-photo img { transform: scale(1.02); }
.onward-photo img { transition: transform .35s ease-out; }

.onward-cat { display: block; color: var(--olive); margin-bottom: 2px; }
.onward-title {
  display: block;
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.15;
  color: var(--ink);
  text-transform: uppercase;
}

.onward-nav {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 40px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.onward-step { display: grid; gap: 3px; max-width: 46%; color: var(--ink); }
.onward-step .eyebrow { color: var(--muted); }
.onward-next { text-align: right; justify-items: end; }

@media (max-width: 640px) {
  .onward-grid { grid-template-columns: repeat(2, 1fr); }
  .onward-grid .onward-card:nth-child(3) { display: none; }
  .onward-title { font-size: 15px; }
}

/* The per-language blocks inside the card panel. */
.card-lang-head {
  margin: 22px 0 10px;
  font-family: var(--font-display);
  font-size: 15px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--olive);
}

/* The translate button sits on the language bar, pushed to the far end so it
   never reads as a fourth language. */
.lang-tabs { display: flex; align-items: center; gap: 6px; }
.lang-translate { margin-left: auto; white-space: nowrap; }
.lang-translate[disabled] { opacity: .6; }

/* The per-language translate buttons above the title and description. */
.translate-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }

/* And the one on each card language block, beside its heading. */
.card-lang-head { display: flex; align-items: center; gap: 12px; }
.card-lang-head .btn { margin-left: auto; }

/* ------------------------------------------------------------------ spice

   One to three chillies, the logo's own drawing stood upright. Nought shows
   nothing at all: a "not spicy" badge on nine dishes in ten is noise.        */

.spice { display: inline-flex; align-items: center; gap: 2px; }
.spice-pod { width: auto; display: block; }

/* On a card, opposite the photo count. */
.card-spice {
  position: absolute; left: 14px; bottom: 14px;
  display: inline-flex; align-items: center;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}

/* In the editor: four buttons, one of them on. */
.spice-pick { display: flex; flex-wrap: wrap; gap: 8px; }
.spice-opt {
  display: inline-flex; align-items: center; gap: 4px;
  min-height: 40px;
  padding: 6px 14px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.spice-opt:hover { border-color: var(--accent-fill); }
.spice-opt.is-on { border-color: var(--accent-fill); background: var(--accent-tint); }
.spice-opt .spice-pod { height: 20px; }

.diet-mark-spice .spice-pod { height: 22px; }

/* --------------------------------------------------------- diet tooltips

   The browser's own tooltip takes about a second and never appears on a
   phone. This one is instant, follows the palette, and answers to a keyboard
   as well as a mouse — on the cards, where the icons have no words beside
   them, each one is focusable for exactly that reason.                      */

.diet-tip { position: relative; display: inline-flex; border-radius: 4px; z-index: 6; }
.diet-tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(3px);
  padding: 5px 9px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: .02em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .14s var(--ease), transform .14s var(--ease);
  z-index: 5;
}
.diet-tip:hover::after,
.diet-tip:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.diet-tip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .diet-tip::after { transition: none; }
}

/* ------------------------------------------------------- the method, gated

   The site gates what the app gates: one step, then the club. It is the same
   number in three places — recipe.js, prerender.py and the app — because a
   recipe that is free on one screen and paid on the other is a bug with a
   price on it.                                                              */

.method-locked {
  margin-top: 22px;
  padding: 22px clamp(18px, 2.4vw, 28px);
  border: 1.5px dashed var(--line);
  border-radius: 6px;
  background: var(--surface);
}
.method-locked-head {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 8px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 15px; letter-spacing: .06em;
  color: var(--olive);
}
.method-locked-head svg { width: 17px; height: 17px; }
.method-locked p:not(.method-locked-head) {
  margin: 0 0 16px;
  font-size: 15px; line-height: 1.55;
  color: var(--ink-soft);
  max-width: 52ch;
}

/* ------------------------------------------------------------ nav login

   Up in the header, on the right, where somebody looking for a way in looks
   first. It used to live at the very bottom of the page.                    */

.nav-login {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 13px 5px 10px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase;
  font-size: 13px; letter-spacing: .06em;
  color: var(--muted);
  transition: border-color .18s var(--ease), color .18s var(--ease),
              background .18s var(--ease);
}
.nav-login:hover { border-color: var(--accent-fill); color: var(--accent); background: var(--accent-tint); }
.nav-login .login-lock svg { width: 15px; height: 15px; display: block; }
/* It has no underline of its own — the rule under a nav link would run under
   the pill and read as a mistake. */
.nav-login::after { content: none; }

@media (max-width: 760px) {
  .nav-login span:last-child { display: none; }
  .nav-login { padding: 6px 9px; }
}

/* ----------------------------------------------------- the Play Store badge

   Google's own artwork, unaltered, at the same height as Apple's beside it.
   Their badge carries its own clear space inside the file, which is why it is
   a little wider for the same height and must not be cropped to match.      */

.play-store-badge {
  /* 74, not 57. Google's file carries its own clear space — the black pill is
     only 77% of the image's height — so at Apple's 57 the badge beside it came
     out visibly smaller. This makes the two pills the same height; the clear
     space grows with it, which is what their guidelines ask for anyway. */
  height: 74px;
  width: auto;
  display: block;
}
.app-store { flex-wrap: wrap; align-items: center; }

/* --------------------------------------------------------- the detailed card

   The app's RecipeCard on the page: three figures across the top, then the
   rows, then Mona's notes. Members only, like the app — everyone else is told
   what is on it rather than shown a gap.                                    */

.recipe-card { margin-top: clamp(26px, 3.4vw, 44px); }
.recipe-card-body {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  padding: 4px clamp(16px, 2vw, 26px);
}

.card-figures {
  display: flex;
  flex-wrap: wrap;
  padding: 18px 0;
}
.card-figure {
  flex: 1 1 140px;
  text-align: center;
  padding: 0 12px;
  border-left: 1px solid var(--line-soft);
}
.card-figure:first-child { border-left: 0; }
.card-figure .eyebrow { min-height: 2.2em; }   /* "Du début à la fin" wraps, "Niveau" does not */
.card-figure-value {
  font-family: var(--display);
  font-size: clamp(19px, 2vw, 25px);
  line-height: 1.05;
  color: var(--ink);
  margin: 4px 0 0;
}

.card-row {
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}
.card-row > p:not(.eyebrow) {
  margin: 5px 0 0;
  font-size: 15.5px; line-height: 1.55;
  color: var(--ink);
}
/* Notes, substitutions, make-ahead: any card row written a point per line. */
.card-row ul { margin: 8px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.card-row li {
  position: relative; padding-left: 18px;
  font-size: 15.5px; line-height: 1.5; color: var(--ink-soft);
}
.card-row li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--olive);
}

/* What a non-member sees in its place. */
.card-teaser {
  display: flex; align-items: center; gap: 12px;
  margin-top: clamp(26px, 3.4vw, 44px);
  padding: 15px 18px;
  border: 1px solid color-mix(in srgb, var(--olive) 26%, transparent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--olive) 7%, transparent);
  color: var(--muted);
  font-size: 14.5px; line-height: 1.45;
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.card-teaser:hover {
  border-color: var(--olive);
  background: color-mix(in srgb, var(--olive) 12%, transparent);
}
.card-teaser-glyph svg { width: 21px; height: 21px; display: block; }
.card-teaser-more { margin-left: auto; font-size: 20px; line-height: 1; }

/* The way through to the dishes, under the contrast block where it now sits. */
.ab-cta { margin-top: clamp(16px, 2vw, 24px); align-self: start; }

/* ------------------------------------------------- the head of a dish page

   The photograph next to the title rather than under it, so what a dish is
   and what it looks like arrive together. Below 860px they stack: two columns
   there would make a narrow photo beside a narrow paragraph.                */

.recipe-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
  gap: clamp(22px, 3.6vw, 52px);
  /* Centred against the words, not hung from the top of them. The text column
     is the taller of the two — title, lede, timings, marks — so aligning to
     the start left the photograph floating up by a hundred points or so. */
  align-items: center;
  margin-top: clamp(18px, 2.4vw, 26px);
}
.recipe-hero-grid .recipe-figure,
.recipe-hero-grid .hero-carousel { margin-top: 0; }

@media (max-width: 860px) {
  .recipe-hero-grid { grid-template-columns: minmax(0, 1fr); }
}

/* The heading over the contact form, in the palette's red. `--accent` rather
   than `--accent-fill`: the fill is a background colour and sits at 2.6:1 on
   paper, which is not a colour to set words in. */
.contact-form-title {
  color: var(--accent);
  margin-bottom: 14px;
}

/* ------------------------------------------------------------- the member */
/* Signing in on the site. The club is bought in the app; this is the door
   that lets what was bought there open here as well. */

.nav-login.is-signed-in .login-lock { background: var(--accent-tint); }
.nav-login.is-member .login-lock { background: var(--accent); color: var(--paper); }

.member-dialog {
  width: min(420px, calc(100vw - 32px));
  padding: 26px 26px 24px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .18);
}
.member-dialog::backdrop { background: rgba(28, 26, 23, .38); backdrop-filter: blur(2px); }
.member-dialog h2 {
  font-family: var(--display); font-size: 30px; line-height: 1.05;
  text-transform: uppercase; margin: 0 0 8px;
}
.member-lede { margin: 0 0 18px; font-size: 14px; color: var(--muted); }
.member-close-row { display: flex; justify-content: flex-end; margin: -10px -8px 0 0; }
.member-close {
  border: 0; background: none; cursor: pointer;
  font-size: 26px; line-height: 1; color: var(--muted); padding: 4px 8px;
}
.member-close:hover { color: var(--ink); }
.member-form .field { margin-bottom: 14px; }
.member-form .btn { width: 100%; margin-top: 4px; }
.member-forgot {
  display: block; width: 100%; margin-top: 12px;
  border: 0; background: none; cursor: pointer;
  font-family: var(--sans); font-size: 13.5px; color: var(--accent);
}
.member-forgot:hover { text-decoration: underline; }
.member-note {
  margin: 0 0 12px; font-size: 13.5px; color: var(--olive);
}
.member-note.is-bad { color: var(--accent); }
.member-foot {
  margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line-soft);
  font-size: 12.5px; color: var(--muted);
}

.member-menu {
  position: absolute; z-index: 60;
  min-width: 200px; padding: 14px;
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--paper);
  box-shadow: 0 16px 40px rgba(0, 0, 0, .16);
}
.member-who { margin: 0; font-size: 13.5px; color: var(--ink); word-break: break-all; }
.member-tier {
  margin: 4px 0 12px;
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
}
.member-menu .btn { width: 100%; }
.member-menu .member-admin {
  display: flex; width: 100%; margin-bottom: 8px;
  text-decoration: none;
}
.member-swap {
  border: 0; background: none; padding: 0; cursor: pointer;
  font-family: var(--sans); font-size: 12.5px; color: var(--accent);
  text-decoration: underline;
}
.member-join .field-hint { margin-top: 5px; }

/* `display: block` on the badge beats the browser's own [hidden] rule, so an
   element marked hidden went on being drawn. */
.play-store-badge[hidden] { display: none; }

/* The badge in the hero. Smaller than the one in the app section — it stands
   beside a button there, not on its own — and never below Apple's minimum. */
.hero-store { line-height: 0; }
.hero-store .app-store-badge { width: 146px; margin: 0; }
@media (max-width: 560px) {
  .hero-store .app-store-badge { width: 132px; }
}
