/* Nikki Home - shared stylesheet for every page.
   Extracted from index.html so the landing page, the recipe index and
   the video page share one copy instead of three that drift apart. */

/* ---------------------------------------------------------------
   TRATTORIA
   Nikki chose Design A, so the site wears it. The token NAMES are
   unchanged on purpose - every rule below and all of site.js refers to
   them - only the values move. That turns a re-skin into a palette swap
   rather than a rewrite, and keeps the recipe modal, cook mode, filters,
   the CMS and the newsletter exactly as they were.

   The accent is #8F6237 rather than the concept's #9C6B3C. The lighter
   gold measures 4.07:1 on bone, and the section labels it colours are
   small caps - that fails AA. This one is 4.70:1 on bone and 4.99:1 on
   paper, same hue, and passes.
   --------------------------------------------------------------- */
:root {
    --ivory: #FBF8F2;      /* paper    */
    --stone: #DED4C4;      /* rules    */
    --frame: #A08D72;      /* the hairline around photographs. Deliberately
                              darker than --stone and NOT seasonal: it is a
                              picture frame, and a frame you can barely see
                              is not doing its job. */
    --warm-grey: #6E6257;  /* body     5.58:1 on paper */
    --charcoal: #2A211A;   /* ink     14.89:1 on paper */
    --accent: #8F6237;     /* gold     4.99:1 on paper */
    --cream: #F6F1E7;      /* bone     */
    --espresso: #1E1813;   /* dark bands */
    --serif: 'Bodoni Moda', Georgia, serif;
    --sans: 'Jost', sans-serif;
}

/* ---- Seasonal themes (set on <html data-season="..."> ) ---- */
/* The seasons warm the paper; they no longer repaint the brand.
   These used to override --accent too, which meant the gold the design was
   built and contrast-checked around (#8F6237, 4.99:1) was being replaced at
   runtime - in August by #E0B449, a pale yellow that measures about 1.9:1 on
   bone and made every section label almost unreadable. --stone had drifted
   pale enough that the hairline frames had all but vanished as well.
   Seasons move the paper and the rules a little. The gold stays put. */
html[data-season="spring"] { --cream: #F4F2E9; --stone: #D9D6C4; }
html[data-season="summer"] { --cream: #F8F3E6; --stone: #E0D5C0; }
html[data-season="autumn"] { --cream: #F5EEE3; --stone: #DCCFBB; }
html[data-season="winter"] { --cream: #F3F1EC; --stone: #D8D3C8; }

* { margin: 0; padding: 0; box-sizing: border-box; }
/* Smooth scrolling is one of the classic vestibular triggers, so it is offered
   rather than imposed - every in-page anchor animated a full-page glide even
   for people who had asked the operating system for no motion. */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* Visible to a screen reader, invisible on screen. Used for form labels the
   design carries as placeholder text. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Bodoni Moda is a Didone with an optical-size axis. Left on auto, a 57px
   heading selects opsz 57, where the hairlines are at their thinnest and
   start breaking up on screen. Pinning the axis low keeps enough weight in
   the thin strokes at display sizes. font-variation-settings inherits, and
   Jost simply ignores an axis it doesn't have. */
body {
    font-optical-sizing: none;
    font-variation-settings: 'opsz' 30;
    font-family: var(--sans);
    background-color: var(--ivory);
    color: var(--charcoal);
    line-height: 1.6;
    overflow-x: hidden;
}

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

/* ---------- Navigation ----------
   Scoped to #navbar, not bare nav. The sticky bar along the bottom of a phone
   is a <nav> too, and every rule written for the header was landing on it and
   being undone again further down the file - which is exactly how it ended up
   inverted the moment the header started blending. */
#navbar {
    position: fixed; top: 0; left: 0; right: 0; z-index: 100;
    padding: 1.5rem 4rem;
    display: flex; justify-content: space-between; align-items: center;
    background: linear-gradient(to bottom, var(--ivory) 0%, transparent 100%);
    transition: background 0.4s ease, box-shadow 0.4s ease, color 0.4s ease;
}
#navbar.scrolled {
    background: rgba(250, 248, 245, 0.95);
    box-shadow: 0 2px 20px rgba(0,0,0,0.05);
}
.logo {
    font-family: var(--serif); font-size: 1.8rem; font-weight: 400;
    letter-spacing: 0.15em; text-transform: uppercase;
    color: var(--charcoal); text-decoration: none;
    opacity: 0; transition: opacity 0.4s ease; pointer-events: none;
}
#navbar.scrolled .logo { opacity: 1; pointer-events: auto; }
.nav-links { display: flex; gap: 3rem; list-style: none; align-items: center; }
.nav-links a {
    font-size: 0.85rem; font-weight: 400; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--charcoal); text-decoration: none;
    position: relative; padding-bottom: 4px; cursor: pointer;
}
.nav-links a::after {
    content: ''; position: absolute; bottom: 0; left: 0;
    width: 0; height: 1px; background: var(--accent); transition: width 0.3s ease;
}
.nav-links a:hover::after { width: 100%; }

/* ---- Visible keyboard focus (accessibility) ---- */
a:focus-visible, button:focus-visible, [role="button"]:focus-visible,
.filter-tab:focus-visible, .btn:focus-visible, .mini-btn:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px;
}
.newsletter-form input:focus-visible, .admin-panel input:focus-visible,
.admin-panel textarea:focus-visible, .admin-panel select:focus-visible,
.notes-block textarea:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 1px;
}

/* ---- Mobile hamburger menu ---- */
.nav-toggle {
    display: none; flex-direction: column; gap: 5px; background: none; border: none;
    cursor: pointer; padding: 6px; z-index: 110;
}
.nav-toggle span { width: 26px; height: 2px; background: var(--charcoal); border-radius: 2px; transition: opacity .2s ease, transform .3s ease; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.mobile-menu {
    position: fixed; inset: 0; z-index: 105; background: rgba(250,248,245,0.98);
    backdrop-filter: blur(8px); display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 1.8rem; transform: translateY(-100%);
    visibility: hidden; transition: transform .35s ease, visibility .35s;
}
.mobile-menu.open { transform: translateY(0); visibility: visible; }
.mobile-menu a {
    font-family: var(--serif); font-size: 1.9rem; font-weight: 400; color: var(--charcoal);
    text-decoration: none; letter-spacing: 0.08em;
}
.mm-close { position: absolute; top: 1.2rem; right: 1.5rem; background: none; border: none; font-size: 2.4rem; line-height: 1; color: var(--charcoal); cursor: pointer; }
@media (max-width: 860px) {
    .recipe-grid, .row-recipes, .row-reels { grid-template-columns: repeat(2, 1fr); }
    .reel-grid, .feed-grid { grid-template-columns: repeat(2, 1fr); }
    .video-grid { grid-template-columns: 1fr; }
}
@media (max-width: 768px) { .nav-toggle { display: flex; } }
@media (prefers-reduced-motion: reduce) { .mobile-menu, .nav-toggle span { transition: none; } }

/* ---------- Hero ---------- */
.hero {
    height: 100vh; height: 100svh; display: flex; align-items: center; justify-content: center;
    position: relative; overflow: hidden;
}
.hero-image-container { position: absolute; inset: 0; }
/* The hero photograph is wrapped in <picture> so phones get a portrait cut.
   display:contents keeps the wrapper out of the layout entirely, so the <img>
   stays a direct child of the container and every rule below - the absolute
   fill, the Ken Burns drift, the cross-fade to the clip - goes on working
   without knowing the wrapper is there. */
.hero-image-container picture { display: contents; }
.hero-image {
    width: 100%; height: 100%; object-fit: cover;
    opacity: 0; animation: fadeIn 1.5s ease forwards 0.3s;
}
/* Slow drift on the still, so the hero is never completely dead even
   when the video doesn't load. Stops once video takes over. */
.hero-image { transform-origin: 52% 45%; }
html.js-motion .hero:not(.video-on) .hero-image {
    animation: fadeIn 1.5s ease forwards 0.3s, kenburns 34s ease-in-out 1.5s infinite alternate;
}
@keyframes kenburns { from { transform: scale(1); } to { transform: scale(1.075); } }

/* Ambient hero video. Sits over the still and cross-fades in only once
   it is actually playing, so a slow or blocked load is invisible —
   the photograph is always the fallback, never a black box. */
.hero-video {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
    opacity: 0; transition: opacity 1.4s ease; pointer-events: none;
}
.hero.video-on .hero-video { opacity: 1; }
.hero.video-on .hero-image { opacity: 0; transition: opacity 1.4s ease; }
.hero-overlay {
    position: absolute; inset: 0;
    background:
        radial-gradient(ellipse 78% 58% at 50% 47%, rgba(38,33,30,0.52) 0%, rgba(38,33,30,0.20) 46%, rgba(38,33,30,0) 76%),
        linear-gradient(to bottom, rgba(38,33,30,0.22) 0%, transparent 26%, transparent 64%, rgba(38,33,30,0.34) 100%);
}
.hero-content {
    position: relative; z-index: 10; text-align: center; padding: 2rem;
    opacity: 0; animation: slideUp 1s ease forwards 0.8s;
}
.hero-decoration { display: flex; align-items: center; justify-content: center; gap: 2rem; margin-bottom: 1.5rem; }
.hero-line { width: 80px; height: 1px; background: var(--accent); }
.hero-accent {
    font-family: var(--serif); font-size: 0.9rem; font-style: italic;
    letter-spacing: 0.3em; color: var(--accent); text-transform: lowercase;
}
.hero-title {
    font-family: var(--serif); font-size: clamp(4rem, 12vw, 9rem); font-weight: 400;
    letter-spacing: 0.15em; text-transform: uppercase; margin-bottom: 0.5rem;
    color: var(--ivory); line-height: 0.9;
    text-shadow: 0 2px 44px rgba(18,14,12,0.55), 0 1px 3px rgba(18,14,12,0.35);
}
.hero-title span { display: block; }
.hero-title .title-nikki { font-weight: 400; }
.hero-title .title-home { font-size: 0.6em; letter-spacing: 0.4em; color: rgba(250,248,245,0.72); }
.hero-subtitle {
    font-family: var(--serif); font-size: clamp(1rem, 2vw, 1.4rem); font-weight: 400;
    font-style: italic; letter-spacing: 0.15em; color: rgba(250,248,245,0.9); margin-top: 1.5rem;
    text-shadow: 0 1px 22px rgba(18,14,12,0.5);
}
.hero-subtitle::before, .hero-subtitle::after { content: '—'; margin: 0 1rem; color: var(--accent); }
.scroll-indicator {
    position: absolute; bottom: 3rem; left: 50%; transform: translateX(-50%);
    display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
    opacity: 0; animation: fadeIn 1s ease forwards 1.5s;
}
.scroll-indicator span { font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase; color: rgba(250,248,245,0.85); text-shadow: 0 1px 12px rgba(18,14,12,0.5); }
.scroll-line { width: 1px; height: 40px; background: rgba(250,248,245,0.7); animation: scrollPulse 2s ease infinite; }

/* ---------- Shared section bits ---------- */
.section-label {
    font-size: 0.75rem; font-weight: 500; letter-spacing: 0.3em;
    text-transform: uppercase; color: var(--accent); margin-bottom: 0.55rem; display: block;
}
.section-title { font-family: var(--serif); font-size: clamp(2rem, 4vw, 2.8rem); font-weight: 400; }
.center { text-align: center; }
.wrap { max-width: 1400px; margin: 0 auto; }

/* ---------- Feed ---------- */
.feed { padding: 3rem 4rem 3.5rem; background: var(--ivory); }
.feed-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.2rem; max-width: 1200px; margin: 1.5rem auto 0; }
.post {
    background: var(--ivory); border: 1px solid var(--stone);
    border-radius: 4px; overflow: hidden; transition: box-shadow .3s ease, transform .3s ease;
}
.post:hover { box-shadow: 0 14px 40px rgba(58,54,51,0.10); transform: translateY(-4px); }
.post img { width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.post-body { padding: 1.4rem 1.6rem 1.8rem; }
.post-date { font-size: 0.7rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--accent); }
.post-body p { margin-top: 0.6rem; color: var(--charcoal); line-height: 1.7; font-size: 0.98rem; }

/* ---------- Warmth ----------
   Two very light touches that make the page feel like a room rather
   than a document. Both are deliberately near-invisible: if you can
   point at them they are too strong.

   1. A fine grain over everything, so large flat areas of ivory have
      some tooth to them instead of reading as flat screen white.
   2. A wash that shifts with the time of day — cooler at breakfast,
      golden in the evening. Applied to backgrounds only, never to
      text, so contrast ratios are untouched. */
.grain {
    /* inset: -50% covered four times the viewport for a texture that never
       moves - four times the pixels to composite, for nothing. */
    position: fixed; inset: 0; pointer-events: none; z-index: 9998;
    opacity: 0.032;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* The daypart wash used to be a sheet of translucent amber over the whole
   viewport. Under multiply that reads as a tint - multiply by a near-white
   colour barely moves anything. I swapped it to plain alpha to save a
   compositing pass, and plain alpha does the opposite: a 26% cream film over
   everything, lifting every black and hazing every photograph. The page went
   foggy at 5pm.

   Neither is right. A wash over the top can only ever fog the pictures, so the
   time of day moves the paper instead - the room warms, the food does not. No
   overlay, no blend mode, nothing to composite.

   These sit after the seasons on purpose: where both set a token, the clock
   wins. */
html[data-daypart="evening"] { --ivory: #FCF6EC; --cream: #F7F0E2; }
html[data-daypart="night"]   { --ivory: #FBF3E7; --cream: #F5EDDD; }

/* ---------- Cheshire Life column ----------
   Nikki writes a monthly column with two recipes an issue. This gathers
   them in one place. The whole section stays hidden until at least one
   recipe is marked as a column recipe, so it simply appears when the
   first one goes in rather than sitting there empty. */
.column-sec { padding: 3rem 4rem 3.5rem; background: var(--ivory); }
.column-head { max-width: 720px; margin: 0 auto 1.9rem; text-align: center; }
.column-rule { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 0.9rem; }
.column-rule::before, .column-rule::after { content: ''; height: 1px; width: 56px; background: var(--stone); }
.column-rule span { font-size: 0.68rem; letter-spacing: 0.32em; text-transform: uppercase; color: var(--warm-grey); }
.column-head h2 { font-family: var(--serif); font-size: clamp(2rem, 4vw, 2.8rem); font-weight: 400; }
.column-head p { margin-top: 1rem; color: var(--warm-grey); line-height: 1.8; font-size: 0.98rem; }
.column-issue { font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-top: 0.6rem; display: block; }
/* Editorial rather than another filled pill, so it reads as a credit. */
.badge.column { background: rgba(250,248,245,0.94); color: var(--charcoal); border: 1px solid var(--accent); }
.column-credit { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.9rem; }

/* ---------- Recipes ---------- */
.recipes { padding: 3rem 4rem 3.5rem; background: var(--cream); }
.filter-tabs { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin: 1.2rem 0 1.6rem; }
.filter-tab {
    font-family: inherit; font-size: 0.78rem; letter-spacing: 0.12em; text-transform: uppercase;
    padding: 0.6rem 1.4rem; border: 1px solid var(--stone); background: transparent;
    color: var(--warm-grey); cursor: pointer; border-radius: 30px; transition: all .3s ease;
}
.filter-tab:hover { border-color: var(--accent); color: var(--charcoal); }
.filter-tab.active { background: var(--charcoal); border-color: var(--charcoal); color: var(--ivory); }
/* Fixed column counts, not auto-fill. auto-fill picks whatever number of
   columns happens to fit, which kept choosing one that didn't divide the
   number of items - so a row was left part empty. Every count below
   divides its section exactly: 6 recipes, 12 feed photos, 6 reels, 4 in
   each landing row. */
.recipe-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; max-width: 1300px; margin: 0 auto; }
.recipe-card {
    background: var(--ivory); overflow: hidden; cursor: pointer; position: relative;
    box-shadow: 0 6px 20px rgba(58,54,51,0.05); transition: box-shadow .3s ease, transform .3s ease;
}
.recipe-card:hover { box-shadow: 0 16px 44px rgba(58,54,51,0.12); transform: translateY(-4px); }
.recipe-card:focus-visible, .related-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.recipe-card .thumb { position: relative; aspect-ratio: 1; overflow: hidden; }
.recipe-card .thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s ease; }
.recipe-card:hover .thumb img { transform: scale(1.05); }
.badge-row { position: absolute; top: 0.8rem; left: 0.8rem; display: flex; gap: 0.4rem; flex-wrap: wrap; }
.badge {
    font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 500;
    padding: 0.3rem 0.6rem; border-radius: 20px; background: rgba(250,248,245,0.92); color: var(--charcoal);
}
.badge.season { background: var(--accent); color: #fff; }
.badge.pinned { background: var(--charcoal); color: var(--ivory); }
.recipe-card .info { padding: 1.2rem 1.3rem 1.5rem; }
.recipe-card .info h4 { font-family: var(--serif); font-size: 1.4rem; font-weight: 400; margin-bottom: 0.5rem; }
.meta-tags { display: flex; gap: 0.8rem; flex-wrap: wrap; }
.meta-tag { font-size: 0.7rem; letter-spacing: 0.06em; color: var(--warm-grey); text-transform: uppercase; }
.meta-tag strong { color: var(--accent); font-weight: 500; }

/* ---------- Recipe detail modal ---------- */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(58,54,51,0.6); z-index: 500;
    display: none; align-items: flex-start; justify-content: center; padding: 3rem 1.5rem; overflow-y: auto;
}
.modal-overlay.open { display: flex; }
.recipe-detail {
    background: var(--ivory); max-width: 820px; width: 100%; border-radius: 6px; overflow: hidden;
    box-shadow: 0 30px 80px rgba(0,0,0,0.3);
}
.recipe-detail .hero-photo { width: 100%; max-height: 380px; object-fit: cover; }
.recipe-detail-body { padding: 2.5rem 3rem 3rem; }
.recipe-detail-body h2 { font-family: var(--serif); font-size: 2.6rem; font-weight: 400; margin-bottom: 0.8rem; }
.detail-meta { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-bottom: 1.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--stone); }
.detail-meta div { font-size: 0.85rem; color: var(--warm-grey); }
.detail-meta strong { display: block; color: var(--accent); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 0.2rem; }
.recipe-story { font-style: italic; color: var(--warm-grey); line-height: 1.9; margin-bottom: 2rem; font-family: var(--serif); font-size: 1.15rem; }
.recipe-columns { display: grid; grid-template-columns: 1fr 1.4fr; gap: 2.5rem; }
.recipe-columns h3 { font-family: var(--serif); font-size: 1.4rem; font-weight: 400; margin-bottom: 1rem; }
.ingredient-list { list-style: none; }
.ingredient-list li { padding: 0.5rem 0; border-bottom: 1px dashed var(--stone); font-size: 0.95rem; }
.step-list { padding-left: 1.2rem; }
.step-list li { padding: 0.5rem 0; line-height: 1.7; }
.detail-actions { display: flex; gap: 0.8rem; margin-top: 2.5rem; flex-wrap: wrap; }
.modal-close {
    position: absolute; top: 1.2rem; right: 1.5rem; font-size: 2rem; color: var(--ivory);
    background: rgba(58,54,51,0.5); border: none; width: 44px; height: 44px; border-radius: 50%;
    cursor: pointer; z-index: 510; line-height: 1;
}

/* ---------- Videos ---------- */
.videos { padding: 3rem 4rem 3.5rem; background: var(--ivory); }
.video-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem; max-width: 1200px; margin: 2rem auto 0; }
.video-embed { position: relative; aspect-ratio: 16/9; background: var(--stone); border-radius: 4px; overflow: hidden; }
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------- Self-hosted reels ----------
   Vertical, because that is how they were filmed. The still is what
   loads; the four-second silent loop only downloads when you hover it
   (or, on a phone, when it scrolls into view), and the full reel only
   when you actually press play. Nothing here costs anything until
   somebody shows interest in it. */
/* Column count and width live in the Design A layer at the end of this file.
   Leaving repeat(6) here as well was a contradiction waiting to bite: there
   are eight reels now, and six does not divide eight. */
.reel-grid { display: grid; gap: 1.25rem; margin: 1.6rem auto 0; }
.reel { cursor: pointer; background: none; border: 0; padding: 0; font-family: inherit; text-align: left; display: block; width: 100%; }
.reel-media {
    position: relative; aspect-ratio: 9/16; border-radius: 5px; overflow: hidden;
    background: #2A2521; box-shadow: 0 10px 30px rgba(20,16,12,0.35);  /* dark: this placeholder sits inside the espresso band */
    transition: box-shadow .45s ease, transform .45s ease;
}
.reel:hover .reel-media, .reel:focus-visible .reel-media { transform: translateY(-5px); box-shadow: 0 22px 48px rgba(58,54,51,0.19); }
.reel:focus { outline: none; }
.reel:focus-visible .reel-media { outline: 2px solid var(--accent); outline-offset: 3px; }
.reel-media img, .reel-loop {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.reel-loop { opacity: 0; transition: opacity .55s ease; }
.reel.is-previewing .reel-loop { opacity: 1; }
.reel-shade { position: absolute; inset: 0; background: linear-gradient(to top, rgba(38,33,30,0.55) 0%, rgba(38,33,30,0.06) 38%, transparent 62%); }
.reel-play {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%) scale(1);
    width: 54px; height: 54px; border-radius: 50%; border: 1px solid rgba(250,248,245,0.75);
    background: rgba(38,33,30,0.34); backdrop-filter: blur(3px);
    display: grid; place-items: center; color: #fff; pointer-events: none;
    transition: transform .45s ease, background .45s ease, opacity .45s ease;
}
.reel:hover .reel-play { transform: translate(-50%,-50%) scale(1.09); background: rgba(196,168,130,0.82); }
.reel-play svg { width: 17px; height: 17px; margin-left: 3px; fill: currentColor; }
.reel-dur {
    position: absolute; right: 0.7rem; top: 0.7rem; font-size: 0.66rem; letter-spacing: 0.08em;
    padding: 0.24rem 0.5rem; border-radius: 20px; background: rgba(38,33,30,0.5); color: #fff;
}
.reel-cap { position: absolute; left: 0.95rem; right: 0.95rem; bottom: 0.9rem; color: #fff; }
.reel-cap h3 { font-family: var(--serif); font-weight: 400; font-size: 1.06rem; line-height: 1.25; }

/* Lightbox for the full reel */
.vl {
    position: fixed; inset: 0; z-index: 3000; display: none; place-items: center;
    background: rgba(28,25,23,0.93); backdrop-filter: blur(6px); padding: 1.5rem;
}
.vl.open { display: grid; }
.vl video { max-width: min(100%, 460px); max-height: 84svh; border-radius: 6px; background: #000; display: block; }
.vl-title { color: var(--ivory); text-align: center; margin-top: 1rem; font-family: var(--serif); font-size: 1.2rem; font-weight: 400; }
.vl-note { color: #B8B3AE; text-align: center; margin-top: 0.4rem; font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; }
.vl-close {
    position: absolute; top: 1.2rem; right: 1.4rem; width: 42px; height: 42px; border-radius: 50%;
    background: rgba(250,248,245,0.12); border: 1px solid rgba(250,248,245,0.28); color: var(--ivory);
    font-size: 1.5rem; line-height: 1; cursor: pointer; transition: background .3s ease;
}
.vl-close:hover { background: rgba(250,248,245,0.24); }
.video-caption { margin-top: 0.8rem; font-family: var(--serif); font-size: 1.2rem; font-style: italic; color: var(--charcoal); }

/* ---------- Featured / Lifestyle ---------- */
.featured { padding: 3.25rem 4rem; background: var(--cream); }
.featured-cta {
    display: inline-block; margin-top: 1.8rem; font-size: 0.78rem; letter-spacing: 0.18em;
    text-transform: uppercase; color: var(--charcoal); text-decoration: none;
    padding-bottom: 0.4rem; border-bottom: 1px solid var(--accent); transition: color .3s ease, border-color .3s ease;
}
.featured-cta:hover { color: var(--accent); border-color: var(--charcoal); }
.featured-content { display: grid; grid-template-columns: 1fr 1fr; gap: 4rem; max-width: 1200px; margin: 0 auto; align-items: center; }
.featured-image { aspect-ratio: 4/5; overflow: hidden; }
.featured-image img { width: 100%; height: 100%; object-fit: cover; }
.featured-text h2 { font-family: var(--serif); font-size: 2.5rem; font-weight: 400; margin-bottom: 1.5rem; }
.featured-text p { color: var(--warm-grey); line-height: 1.9; margin-bottom: 2rem; }

.btn {
    display: inline-block; padding: 1rem 2.5rem; font-size: 0.8rem; font-weight: 500;
    letter-spacing: 0.15em; text-transform: uppercase; text-decoration: none; cursor: pointer;
    color: var(--charcoal); border: 1px solid var(--charcoal); background: transparent;
    font-family: inherit; transition: all 0.3s ease;
}
.btn:hover { background: var(--charcoal); color: var(--ivory); }
.btn.solid { background: var(--charcoal); color: var(--ivory); }
.btn.solid:hover { background: var(--accent); border-color: var(--accent); }

/* ---------- Stay connected (newsletter + reach out) ---------- */
.connect { padding: 3rem 4rem 3.5rem; background: var(--cream); }
/* Grid with auto-fit so it's two columns when there's room and one when not — minmax(min(100%,…)) stops it ever overflowing the viewport. */
.connect-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 2rem; max-width: 1000px; margin: 0 auto; }
.connect-card {
    text-align: center; background: var(--ivory); min-width: 0;
    border: 1px solid var(--stone); border-radius: 8px; padding: 2.5rem 2rem;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.connect-card h3 { font-family: var(--serif); font-size: 1.9rem; font-weight: 400; margin: 0.4rem 0 1rem; }
.connect-card p { color: var(--warm-grey); margin-bottom: 1.6rem; line-height: 1.8; }
.connect-card .freebie { margin-top: 1rem; }
.connect-card .collab-logos { margin-top: 1.6rem; }
.newsletter-form { display: flex; gap: 1rem; max-width: 500px; margin: 0 auto; width: 100%; }
.newsletter-form input {
    flex: 1; min-width: 0; padding: 1rem 1.5rem; border: 1px solid var(--stone); background: transparent;
    font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.3s ease;
}
.newsletter-form input:focus { border-color: var(--accent); }
.newsletter-form button {
    padding: 1rem 2rem; background: var(--charcoal); color: var(--ivory); border: none;
    font-family: inherit; font-size: 0.8rem; font-weight: 500; letter-spacing: 0.1em;
    text-transform: uppercase; cursor: pointer; transition: background 0.3s ease;
}
.newsletter-form button:hover { background: var(--accent); }
.newsletter-form button[disabled] { opacity: 0.55; cursor: default; }
.nl-note {
    margin: 0.9rem auto 0; max-width: 500px; min-height: 1.2em;
    font-size: 0.86rem; line-height: 1.6; color: var(--warm-grey);
}
.nl-note.is-error { color: #9B4A3C; }

/* ---------- Footer ---------- */
footer { padding: 2.25rem 2rem 2.5rem; background: var(--charcoal); text-align: center; }
.footer-logo { font-family: var(--serif); font-size: 1.5rem; font-weight: 400; letter-spacing: 0.15em; text-transform: uppercase; color: var(--ivory); margin-bottom: 1rem; }
.social-links { display: flex; justify-content: center; gap: 2rem; margin-bottom: 1rem; }
.social-links a { color: #B8B3AE; text-decoration: none; font-size: 0.8rem; letter-spacing: 0.1em; text-transform: uppercase; transition: color 0.3s ease; }
.social-links a:hover { color: var(--ivory); }
.copyright { font-size: 0.75rem; color: #B0ABA6; letter-spacing: 0.1em; }

/* ---------- Mobile sticky bottom bar ---------- */
.mobile-bar {
    position: fixed; top: auto; bottom: 0; left: 0; right: 0; z-index: 90;
    display: none; justify-content: space-around; align-items: center;
    height: auto;
    background: rgba(250,248,245,0.96); backdrop-filter: blur(10px);
    border-top: 1px solid var(--stone); padding: 0.6rem 0;
}
.mobile-bar a { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; text-decoration: none; color: var(--charcoal); font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase; }
.mobile-bar svg { width: 22px; height: 22px; stroke: var(--charcoal); fill: none; stroke-width: 1.5; }

/* ---------- Admin panel ---------- */
.admin-fab {
    position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 400;
    width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
    background: var(--charcoal); color: var(--ivory); font-size: 1.4rem;
    box-shadow: 0 8px 24px rgba(0,0,0,0.2); transition: transform .3s ease;
}
.admin-fab:hover { transform: scale(1.08); }
.admin-panel {
    position: fixed; top: 0; right: 0; bottom: 0; width: 440px; max-width: 100vw; z-index: 600;
    background: #fff; box-shadow: -10px 0 40px rgba(0,0,0,0.15); transform: translateX(100%);
    transition: transform .35s ease; overflow-y: auto; padding: 1.5rem;
}
.admin-panel.open { transform: translateX(0); }
.admin-panel h2 { font-family: var(--serif); font-size: 1.8rem; font-weight: 400; margin-bottom: 0.3rem; }
.admin-panel .sub { font-size: 0.8rem; color: var(--warm-grey); margin-bottom: 1.2rem; }
.admin-tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1.2rem; }
.admin-tabs button {
    font-family: inherit; font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase;
    padding: 0.45rem 0.8rem; border: 1px solid var(--stone); background: #fff; color: var(--warm-grey);
    border-radius: 20px; cursor: pointer;
}
.admin-tabs button.active { background: var(--charcoal); color: #fff; border-color: var(--charcoal); }
.admin-section { display: none; }
.admin-section.active { display: block; }
.admin-panel label { display: block; font-size: 0.72rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--warm-grey); margin: 0.9rem 0 0.3rem; }
.admin-panel input, .admin-panel textarea, .admin-panel select {
    width: 100%; padding: 0.65rem 0.8rem; border: 1px solid var(--stone); border-radius: 4px;
    font-family: inherit; font-size: 0.9rem; outline: none;
}
.admin-panel input:focus, .admin-panel textarea:focus, .admin-panel select:focus { border-color: var(--accent); }
.admin-panel textarea { resize: vertical; min-height: 70px; }
.admin-actions { display: flex; gap: 0.6rem; margin-top: 1.2rem; flex-wrap: wrap; }
.admin-btn {
    flex: 1; min-width: 120px; padding: 0.75rem; border: none; border-radius: 4px; cursor: pointer;
    font-family: inherit; font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase;
    background: var(--charcoal); color: #fff;
}
.admin-btn.ghost { background: #fff; color: var(--charcoal); border: 1px solid var(--stone); }
.admin-btn.danger { background: #fff; color: #b5524a; border: 1px solid #e7c9c6; }
.admin-list { margin-top: 1rem; }
.admin-list-item {
    display: flex; align-items: center; gap: 0.7rem; padding: 0.6rem; border: 1px solid var(--stone);
    border-radius: 4px; margin-bottom: 0.5rem; font-size: 0.82rem;
}
.admin-list-item img { width: 40px; height: 40px; object-fit: cover; border-radius: 3px; }
.admin-list-item .grow { flex: 1; min-width: 0; }
.admin-list-item .grow strong { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-list-item button { background: none; border: none; cursor: pointer; color: var(--warm-grey); font-size: 0.95rem; }
.img-hint { font-size: 0.68rem; color: var(--warm-grey); margin-top: 0.25rem; font-style: italic; }
.preview-thumb { width: 60px; height: 60px; object-fit: cover; border-radius: 4px; margin-top: 0.5rem; display: none; }

/* ============================================================
   V2 ADDITIONS
   ============================================================ */

/* ---------- Favourite heart on cards ---------- */
.fav-btn {
    position: absolute; top: 0.8rem; right: 0.8rem; z-index: 3;
    width: 38px; height: 38px; border-radius: 50%; border: none; cursor: pointer;
    background: rgba(250,248,245,0.92); display: flex; align-items: center; justify-content: center;
    transition: transform .25s ease, background .25s ease;
}
.fav-btn:hover { transform: scale(1.12); }
.fav-btn svg { width: 19px; height: 19px; stroke: var(--charcoal); fill: none; stroke-width: 1.6; transition: all .2s ease; }
.fav-btn.on svg { fill: #c2564e; stroke: #c2564e; }

/* ---------- Modal: servings scaler + checklist ---------- */
.scaler { display: inline-flex; align-items: center; gap: 0.6rem; }
.scaler button {
    width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--stone);
    background: var(--ivory); font-size: 1.1rem; line-height: 1; cursor: pointer; color: var(--charcoal);
}
.scaler button:hover { border-color: var(--accent); }
.scaler .serves-now { font-size: 1rem; min-width: 1.2rem; text-align: center; color: var(--charcoal); }
.unit-toggle { display: inline-flex; border: 1px solid var(--stone); border-radius: 20px; overflow: hidden; margin-left: 0.4rem; }
.unit-toggle button { border: none; background: var(--ivory); padding: 0.25rem 0.7rem; font-family: inherit; font-size: 0.72rem; letter-spacing: 0.06em; cursor: pointer; color: var(--warm-grey); }
.unit-toggle button.active { background: var(--charcoal); color: var(--ivory); }
/* The row is a <label> now, not a click handler on the <li>, so the flex
   layout and the pointer belong to the label - that is what makes the whole
   line a target for the checkbox inside it. */
.ingredient-list li label { display: flex; align-items: flex-start; gap: 0.6rem; cursor: pointer; }
.ingredient-list li input { margin-top: 0.4rem; accent-color: var(--accent); flex: 0 0 auto; }
.ingredient-list li input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ingredient-list li.checked span { text-decoration: line-through; color: var(--warm-grey); }
.mini-btn {
    font-family: inherit; font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
    padding: 0.5rem 1rem; border: 1px solid var(--stone); background: var(--ivory); color: var(--charcoal);
    border-radius: 30px; cursor: pointer; transition: all .25s ease;
}
.mini-btn:hover { border-color: var(--accent); color: var(--accent); }

/* ---------- Related recipes ---------- */
.related { margin-top: 2.5rem; border-top: 1px solid var(--stone); padding-top: 1.8rem; }
.related h3 { font-family: var(--serif); font-size: 1.4rem; font-weight: 400; margin-bottom: 1rem; }
.related-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.related-item { cursor: pointer; }
.rel-thumb { aspect-ratio: 4/3; overflow: hidden; border-radius: 4px; }
.rel-thumb img { width: 100%; height: 100%; object-fit: cover; }
/* ---- Baked Feta is a tall portrait; frame each context so both Nikki and the dish show ---- */
.recipe-card .thumb img[src*="21EAF535-1E91-4437-83C2-17485174F42B"] { object-position: center 70%; }
.recipe-detail .hero-photo[src*="21EAF535-1E91-4437-83C2-17485174F42B"] { object-position: center 68%; }
/* "You might also like" tile is a tight 4:3 — zoom into the dish so it fills the frame, no borders. */
.rel-thumb img[src*="21EAF535-1E91-4437-83C2-17485174F42B"] { object-position: center 80%; transform: scale(1.5); transform-origin: center 78%; }
.related-item span { display: block; font-family: var(--serif); font-size: 1rem; margin-top: 0.4rem; }

/* ---------- Cook mode ---------- */
.cook-overlay {
    position: fixed; inset: 0; z-index: 700; background: var(--ivory); display: none;
    flex-direction: column; padding: 2rem; text-align: center;
}
.cook-overlay.open { display: flex; }
.cook-top { display: flex; justify-content: space-between; align-items: center; }
.cook-top .cook-name { font-family: var(--serif); font-size: 1.3rem; font-weight: 400; }
.cook-close { background: none; border: none; font-size: 2rem; cursor: pointer; color: var(--charcoal); line-height: 1; }
.cook-stage { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; max-width: 760px; margin: 0 auto; }
.cook-step-num { font-size: 0.8rem; letter-spacing: 0.25em; text-transform: uppercase; color: var(--accent); margin-bottom: 1.5rem; }
.cook-step-text { font-family: var(--serif); font-size: clamp(1.6rem, 4vw, 2.6rem); font-weight: 400; line-height: 1.4; }
.cook-timer { margin-top: 2rem; display: none; align-items: center; gap: 1rem; justify-content: center; }
.cook-timer.show { display: flex; }
.cook-timer .time { font-family: var(--serif); font-size: 2.4rem; min-width: 5rem; }
.cook-nav { display: flex; gap: 1rem; justify-content: center; align-items: center; padding-top: 1rem; }
.cook-progress { height: 3px; background: var(--stone); border-radius: 3px; margin: 1.2rem auto; max-width: 760px; width: 100%; }
.cook-progress div { height: 100%; background: var(--accent); border-radius: 3px; transition: width .3s ease; }


/* ---------- Toast ---------- */
.toast {
    position: fixed; bottom: 2rem; left: 50%; transform: translateX(-50%) translateY(120%);
    background: var(--charcoal); color: var(--ivory); padding: 0.9rem 1.6rem; border-radius: 30px;
    font-size: 0.85rem; letter-spacing: 0.04em; z-index: 800; opacity: 0; transition: all .35s ease;
}
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }

/* ---------- Instagram-style feed ---------- */
.ig-profile {
    max-width: 935px; margin: 0 auto 2.5rem; display: flex; align-items: center;
    gap: 3rem; padding: 0 1rem;
}
.ig-avatar {
    width: 138px; height: 138px; border-radius: 50%; padding: 4px; flex: 0 0 auto;
    background: linear-gradient(135deg, var(--accent), var(--stone));
}
.ig-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; border: 4px solid var(--ivory); }
.ig-meta { flex: 1; min-width: 0; }
.ig-toprow { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap; }
.ig-handle { font-family: var(--serif); font-size: 1.9rem; font-weight: 400; }
.ig-follow { padding: 0.55rem 1.4rem; font-size: 0.72rem; }
.ig-stats { display: flex; gap: 2.5rem; margin: 1.1rem 0; }
.ig-stats span { font-size: 0.95rem; color: var(--charcoal); }
.ig-stats b { font-weight: 500; }
.ig-bio { color: var(--warm-grey); font-size: 0.95rem; line-height: 1.6; }

.ig-grid {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
    max-width: 935px; margin: 0 auto;
}
/* Live Instagram widget container */
.ig-embed { max-width: 1100px; margin: 1.5rem auto 0; }
.ig-embed iframe { width: 100%; border: 0; }
.ig-tile {
    position: relative; aspect-ratio: 1; overflow: hidden; cursor: pointer;
    background: var(--stone); border: none; padding: 0; display: block;
}
.ig-tile img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
.ig-tile:hover img { transform: scale(1.05); }
.ig-ov {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    background: rgba(38,33,30,0.42); opacity: 0; transition: opacity .3s ease;
}
.ig-tile:hover .ig-ov { opacity: 1; }
.ig-ov svg { width: 30px; height: 30px; stroke: var(--ivory); fill: none; stroke-width: 1.6; }

/* ---------- Instagram post lightbox ---------- */
.post-modal-overlay {
    position: fixed; inset: 0; background: rgba(28,24,22,0.88); z-index: 500;
    display: none; align-items: center; justify-content: center; padding: 2rem;
}
.post-modal-overlay.open { display: flex; }
.post-modal {
    background: var(--ivory); width: 100%; max-width: 940px; max-height: 88vh;
    display: grid; grid-template-columns: 1.35fr 1fr; overflow: hidden; border-radius: 6px;
}
.pm-img { background: #111; display: flex; align-items: center; justify-content: center; min-height: 0; }
.pm-img img { width: 100%; height: 100%; max-height: 88vh; object-fit: contain; }
.pm-side { padding: 2rem; display: flex; flex-direction: column; min-height: 0; }
.pm-head { display: flex; align-items: center; gap: 0.8rem; padding-bottom: 1rem; border-bottom: 1px solid var(--stone); }
.pm-head .av { width: 42px; height: 42px; border-radius: 50%; object-fit: cover; }
.pm-head .nm { font-family: var(--serif); font-size: 1.2rem; }
.pm-caption { margin: 1.4rem 0; line-height: 1.8; color: var(--charcoal); flex: 1; overflow-y: auto; }
.pm-date { font-size: 0.7rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--warm-grey); }
.pm-close { position: fixed; top: 1rem; right: 1.3rem; z-index: 511; background: none; border: none; color: var(--ivory); font-size: 2.4rem; line-height: 1; cursor: pointer; }
.pm-arrow {
    position: fixed; top: 50%; transform: translateY(-50%); z-index: 510; background: none;
    border: none; color: var(--ivory); font-size: 3rem; line-height: 1; cursor: pointer; padding: 0 1rem;
    opacity: 0.8; transition: opacity .2s ease;
}
.pm-arrow:hover { opacity: 1; }
.pm-arrow.prev { left: 0.5rem; }
.pm-arrow.next { right: 0.5rem; }

/* ---------- Announcement bar ---------- */
.announce { display: none; background: var(--charcoal); color: var(--ivory); text-align: center; padding: 0.75rem 2.8rem; font-size: 0.82rem; letter-spacing: 0.04em; position: relative; }
.announce.show { display: block; }
/* The bar's ground is charcoal, and --accent on charcoal is 2.98:1. When
   Nikki sets a link the whole bar becomes that colour, so it needs the lighter
   gold (9.1:1) rather than the one used on paper. */
.announce a { color: #E3B77E; text-decoration: underline; }
.announce .x { position: absolute; right: 0.9rem; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--ivory); cursor: pointer; font-size: 1.2rem; line-height: 1; }

/* ---------- Dietary badges ---------- */
.diet-badges { display: flex; gap: 0.45rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.diet-badge { font-size: 0.62rem; letter-spacing: 0.07em; text-transform: uppercase; font-weight: 500; padding: 0.3rem 0.65rem; border-radius: 20px; background: var(--accent); color: #fff; }
.recipe-card .diet-row { position: absolute; bottom: 0.7rem; left: 0.7rem; display: flex; gap: 0.35rem; flex-wrap: wrap; }
.recipe-card .diet-row .diet-badge { background: rgba(250,248,245,0.92); color: var(--charcoal); }

/* ---------- Recipe detail blocks (notes / storage / nutrition / video) ---------- */
.detail-block { margin-top: 1.8rem; }
.detail-block h3 { font-family: var(--serif); font-size: 1.3rem; font-weight: 400; margin-bottom: 0.6rem; }
.detail-block p { color: var(--warm-grey); line-height: 1.8; white-space: pre-line; }
.nutrition-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.8rem; }
.nutrition-grid div { text-align: center; padding: 0.9rem 0.4rem; border: 1px solid var(--stone); border-radius: 6px; }
.nutrition-grid strong { display: block; font-family: var(--serif); font-size: 1.4rem; color: var(--charcoal); font-weight: 500; }
.nutrition-grid span { font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--warm-grey); }
.detail-video { aspect-ratio: 16/9; margin-top: 0.4rem; border-radius: 6px; overflow: hidden; background: var(--stone); }
.detail-video iframe { width: 100%; height: 100%; border: 0; }

/* ---------- About section ---------- */
.about { padding: 3.25rem 4rem; background: var(--ivory); }
.about-content { display: grid; grid-template-columns: 1fr 1.3fr; gap: 3.5rem; max-width: 1100px; margin: 0 auto; align-items: center; }
.about-photo { aspect-ratio: 1; overflow: hidden; border-radius: 6px; }
.about-photo img { width: 100%; height: 100%; object-fit: cover; }
.about-text h2 { font-family: var(--serif); font-size: 2.4rem; font-weight: 400; margin-bottom: 1.2rem; }
.about-text p { color: var(--warm-grey); line-height: 1.9; }
.about-text p + p { margin-top: 1.1rem; }
.pull-quote {
    font-family: var(--serif); font-size: 1.35rem; font-style: italic; font-weight: 400;
    line-height: 1.5; color: var(--charcoal); margin-top: 1.8rem;
    padding-top: 1.5rem; border-top: 1px solid var(--stone);
}

/* ---------- Reviews ---------- */
.reviews { padding: 4.5rem 4rem; background: var(--ivory); }
.reviews-grid { max-width: 1100px; margin: 2rem auto 0; }   /* layout lives in the Design A layer */
.review-card { background: var(--ivory); padding: 2rem; border-radius: 6px; }
.review-stars { color: var(--accent); letter-spacing: 0.2em; margin-bottom: 0.7rem; }
.review-quote { font-family: var(--serif); font-style: italic; font-size: 1.2rem; line-height: 1.7; color: var(--charcoal); margin-bottom: 1rem; }
.review-name { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--warm-grey); }

/* ---------- Newsletter freebie ---------- */
.freebie { display: none; margin-top: 1.2rem; font-size: 0.85rem; color: var(--accent); text-decoration: underline; }

/* ---------- Rating stars ---------- */
.rating { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--accent); font-size: 0.85rem; }
.rating .count { color: var(--warm-grey); }
.recipe-card .info .rating { margin-bottom: 0.4rem; font-size: 0.8rem; }

/* ---------- Reach out logos ("featured in") ---------- */
.collab-logos { display: flex; gap: 2.5rem; justify-content: center; align-items: center; flex-wrap: wrap; margin-top: 2.5rem; opacity: 0.8; }
.collab-logos .logo-item { font-family: var(--serif); font-style: italic; color: var(--warm-grey); font-size: 1.1rem; }
.collab-logos img { height: 40px; object-fit: contain; }


/* ---------- Private recipe notes ---------- */
.notes-block { margin-top: 1.8rem; }
.notes-block h3 { font-family: var(--serif); font-size: 1.3rem; font-weight: 400; margin-bottom: 0.5rem; }
.notes-block textarea { width: 100%; min-height: 80px; padding: 0.8rem; border: 1px solid var(--stone); border-radius: 6px; font-family: inherit; font-size: 0.92rem; outline: none; resize: vertical; background: var(--ivory); }
.notes-block textarea:focus { border-color: var(--accent); }
.notes-hint { font-size: 0.7rem; color: var(--warm-grey); font-style: italic; margin-top: 0.3rem; }

@media (max-width: 768px) {
    .about-content { grid-template-columns: 1fr; gap: 1.5rem; }
    .nutrition-grid { grid-template-columns: repeat(2, 1fr); }
    .about, .reviews, .connect { padding: 2.75rem 1.5rem; }
    /* Keep all 3 in one row on mobile so none is stranded with blank space beside it — just smaller. */
    .related-row { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
    .related-item span { font-size: 0.8rem; line-height: 1.25; margin-top: 0.3rem; }
    .related h3 { font-size: 1.2rem; }
    .ig-profile { flex-direction: row; gap: 1.5rem; align-items: center; }
    .ig-avatar { width: 86px; height: 86px; }
    .ig-handle { font-size: 1.4rem; }
    .ig-toprow { gap: 0.8rem; }
    .ig-stats { gap: 1.5rem; margin: 0.7rem 0; }
    .ig-bio { display: none; }
    .ig-grid { gap: 3px; }
    .post-modal { grid-template-columns: 1fr; max-height: 92vh; }
    .pm-img img { max-height: 52vh; }
    .pm-arrow { font-size: 2.2rem; padding: 0 0.3rem; }
}
@media print {
    .cook-overlay, .related, .scaler, .unit-toggle, .fav-btn { display: none !important; }
}

/* ---------- Animations ---------- */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
@keyframes scrollPulse { 0%,100% { opacity: 1; transform: scaleY(1); } 50% { opacity: 0.5; transform: scaleY(0.8); } }

/* ---------- Scroll reveal (gentle fade + rise as you scroll) ---------- */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.9s ease, transform 0.9s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
    .reveal { opacity: 1; transform: none; transition: none; }
    /* The scroll cue pulsed forever with no guard, and the hero content slid up
       30px on every load. Both are motion, both were ungated. */
    .scroll-line   { animation: none; }
    .hero-content  { animation-name: fadeIn; }
    .recipe-card:hover .thumb img,
    .ig-tile:hover img,
    .reel:hover .reel-play { transform: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
    nav { padding: 1.5rem 2rem; }
    .nav-links { gap: 2rem; }
    .featured-content { grid-template-columns: 1fr; }
    .recipe-columns { grid-template-columns: 1fr; gap: 1.5rem; }
}
@media (max-width: 768px) {
    nav { padding: 1rem 1.5rem; }
    .logo { font-size: 1.4rem; }
    .nav-links { display: none; }
    .feed, .recipes, .videos, .featured, .column-sec { padding: 2rem 1.25rem 2.25rem; }
    .newsletter-form { flex-direction: column; }
    .recipe-detail-body { padding: 1.8rem; }
    .mobile-bar { display: flex; }
    body { padding-bottom: 64px; }
    .admin-fab { bottom: 78px; }
    footer { padding-bottom: 3rem; }
}

/* ---------- Print: clean, branded, kitchen-friendly recipe ---------- */
.print-brand { display: none; }
@media print {
    body * { visibility: hidden; }
    #recipeModal, #recipeModal * { visibility: visible; }
    #recipeModal { position: absolute; inset: 0; background: #fff; padding: 0; display: block !important; }
    .modal-overlay { background: #fff; padding: 0; }
    .recipe-detail { box-shadow: none; max-width: 100%; border-radius: 0; }
    .recipe-detail .hero-photo { max-height: 240px; }
    .recipe-detail-body { padding: 1.2rem 1.5rem; }
    /* Branded header on the printed sheet */
    .print-brand { display: block; text-align: center; margin-bottom: 1.2rem; padding-bottom: 0.9rem; border-bottom: 2px solid #C4A882; }
    .print-logo { display: block; font-family: 'Cormorant Garamond', serif; font-size: 2rem; font-weight: 400; letter-spacing: 0.18em; text-transform: uppercase; color: #3A3633; }
    .print-sub { font-size: 0.65rem; letter-spacing: 0.18em; text-transform: uppercase; color: #9A9590; }
    /* Hide on-screen-only bits when printing */
    .modal-close, .detail-actions, .admin-fab, .mobile-bar, nav,
    .notes-block, #dVideoWrap, .related, .unit-toggle, .scaler, .fav-btn { display: none !important; }
}

/* ---------- Multi-page additions ----------
   The landing page is an entrance: a greeting, then a few themed rows that
   each hand you on to the page that holds the rest. Inner pages get a compact
   masthead instead of a full-height hero — you already know where you are by
   the time you arrive, so a second 100vh photograph is just a wall. */

.page-head {
    padding: 7rem 4rem 1.75rem;
    text-align: center;
    background: var(--ivory);
}
.page-head h1 {
    font-family: var(--serif); font-weight: 400; line-height: 1.15;
    font-size: clamp(1.9rem, 4vw, 2.7rem);
}
.page-head p {
    max-width: 560px; margin: 0.75rem auto 0;
    color: var(--warm-grey); line-height: 1.75; font-size: 0.95rem;
}

/* A row on the landing page: heading on the left, the way onward on the right. */
.row-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 1.5rem; max-width: 1300px; margin: 0 auto 1.25rem;
}
.row-head h2 { font-family: var(--serif); font-size: clamp(1.5rem, 3vw, 2.05rem); font-weight: 400; }
.row-head .more {
    flex: none; font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--warm-grey); text-decoration: none; padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--stone); transition: color .3s ease, border-color .3s ease;
}
.row-head .more:hover { color: var(--charcoal); border-color: var(--accent); }

/* Landing rows show a handful, not everything. */
.row-recipes { display: grid; gap: 1.5rem; max-width: 1300px; margin: 0 auto; }
.row-reels   { display: grid; gap: 1.25rem; max-width: 1300px; margin: 0 auto; }


/* Landing hero: leave a sliver of the next section showing so it reads as a
   way in rather than a full stop. */
.hero.hero-landing { height: 88svh; }

/* Current page marker in the nav. */
.nav-links a[aria-current="page"], .mobile-menu a[aria-current="page"] { color: var(--accent); }
.nav-links a[aria-current="page"]::after { width: 100%; }

@media (max-width: 768px) {
    .page-head { padding: 5.5rem 1.25rem 1.25rem; }
    .row-head { flex-direction: row; align-items: baseline; }
    .row-head .more { font-size: 0.66rem; }
}


/* =============================================================
   DESIGN A — "TRATTORIA"
   The design Nikki chose. It is a layout, not a palette: espresso bands
   against warm bone, one repeated mark (an arch, borrowed from Italian
   doorways), framed plates instead of cards, and centred section heads
   with a kicker above and a lede below.

   This sits last in the file on purpose. It overrides the older layout on
   equal specificity, so nothing above needed deleting — the recipe modal,
   cook mode, the filters and the CMS all still address the same classes
   they always did.
   ============================================================= */

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 2.5rem; }
section { padding: 5rem 0; }

/* ---- The repeating mark ---- */
.arch { display: block; margin: 0 auto 1rem; width: 26px; height: 32px; }
.arch path { fill: none; stroke: var(--accent); stroke-width: 1.1; }

/* ---- Bands. The page alternates paper and bone, and goes dark twice:
        the hero and Watch. Those are the two moments that should feel
        like evening. ---- */
.band       { background: var(--cream); }
.band-dark  { background: var(--espresso); color: var(--cream); }
.recipes    { background: var(--ivory); }
.feed       { background: var(--cream); }
.featured   { background: var(--ivory); }
.reviews    { background: var(--ivory); }
.connect    { background: var(--cream); padding: 5rem 0; }

/* ---- Section heads ---- */
.sec-head { text-align: center; margin-bottom: 3rem; }
.kicker {
    display: block; font-size: 0.63rem; letter-spacing: 0.4em;
    text-transform: uppercase; color: var(--accent); margin-bottom: 0.9rem;
}
.sec-head h2 {
    font-family: var(--serif); font-weight: 400; line-height: 1.05;
    font-size: clamp(1.9rem, 4vw, 3rem);
    letter-spacing: 0.05em; text-transform: uppercase;
}
.lede { max-width: 54ch; margin: 1.1rem auto 0; color: var(--warm-grey); line-height: 1.85; font-size: 0.97rem; }
.band-dark .kicker { color: #C08A4E; }
.band-dark .lede   { color: #D8CDBB; }
.band-dark .sec-head h2 { color: var(--cream); }
.band-dark .arch path   { stroke: #C08A4E; }
/* The dark band remapped everything except the one link out of the section.
   Gold on espresso is 3.32:1 at 10.9px; the lighter gold above measures
   5.85:1 on the same ground, so reuse it. Same story for the caption on a
   linked video, which inherits charcoal and lands at 1.11:1 - invisible. */
.band-dark .more-link     { color: #C08A4E; }
.band-dark .video-caption { color: var(--cream); }

/* The onward link the concept uses: gold, tracked, underlined. */
.more-link {
    display: block; text-align: center; margin-top: 3.2rem;
    font-size: 0.68rem; letter-spacing: 0.28em; text-transform: uppercase; color: var(--accent);
}
.more-link span { border-bottom: 1px solid currentColor; padding-bottom: 4px; }

/* ---- Hero ---- */
.hero { background: var(--espresso); }
.hero-image { opacity: 0.42; filter: saturate(0.82); }
.hero-video { opacity: 0.42; }
/* A scrim under the type. The clip is busy and light in places, and Bodoni's
   hairlines were disappearing into the worktop. */
.hero-overlay {
    background: radial-gradient(ellipse 70% 52% at 50% 46%, rgba(20,16,12,0.58), rgba(20,16,12,0) 72%);
}
.hero-est {
    display: block; font-size: 0.66rem; letter-spacing: 0.42em; text-transform: uppercase;
    color: #E3B77E; text-shadow: 0 1px 14px rgba(20,16,12,0.75);
}
.hero-title {
    font-family: var(--serif); font-weight: 400; margin: 1.6rem 0 1.2rem;
    font-size: clamp(2.6rem, 8vw, 6.4rem); line-height: 0.94;
    letter-spacing: 0.1em; text-transform: uppercase;
}
.hero-subtitle {
    font-family: var(--serif); font-style: italic; text-transform: none;
    letter-spacing: 0; font-size: clamp(1rem, 2.2vw, 1.45rem); color: #E6DCCB;
}
.hero-subtitle::before, .hero-subtitle::after { content: none; }

/* ---- Display type ---- */
.section-title, h2 { letter-spacing: 0.05em; text-transform: uppercase; }
.logo { font-family: var(--serif); letter-spacing: 0.22em; }

/* ---- The manifesto ---- */
.intro { max-width: 700px; margin: 0 auto; text-align: center; }
.intro p { color: var(--warm-grey); line-height: 1.95; font-size: 1rem; }
.intro p + p { margin-top: 1rem; }
.intro .close {
    font-family: var(--serif); font-style: italic; color: var(--charcoal);
    font-size: clamp(1.3rem, 3vw, 1.9rem); margin-top: 1.8rem; line-height: 1.4;
}

/* ---- Recipes become framed plates. Three to a row, so six cards fill
        two rows exactly. ---- */
.row-recipes { grid-template-columns: repeat(3, 1fr); gap: 2.4rem 2rem; }
.recipe-card { background: transparent; border: 0; box-shadow: none; text-align: center; }
.recipe-card .thumb {
    padding: 0.5rem; border: 1px solid var(--stone); background: var(--ivory);
    transition: border-color .5s ease, transform .5s ease;
}
.recipe-card:hover .thumb { border-color: var(--accent); transform: translateY(-5px); box-shadow: none; }
.recipe-card:hover { transform: none; box-shadow: none; }
.recipe-card .info { padding: 1rem 0 0; }
.recipe-card h4 {
    font-family: var(--serif); font-weight: 400; font-size: 1.08rem;
    letter-spacing: 0.07em; text-transform: uppercase;
}
.recipe-card .meta-tags { justify-content: center; font-size: 0.64rem; letter-spacing: 0.18em; }
.recipe-card .rating { justify-content: center; }

/* ---- The gallery: every photograph, six to a row, each in a hairline
        frame. 24 photographs divide 6, 4, 3 and 2 exactly, so no row is
        ever left part empty at any breakpoint. ---- */
.ig-grid {
    grid-template-columns: repeat(6, 1fr); gap: 0.9rem;
    /* 935px was there to mimic Instagram's column. The gallery is Nikki's own
       now, and it fills the page width like the rest of the layout. */
    max-width: none;
}
.ig-tile {
    padding: 0.35rem; border: 1px solid var(--stone); background: var(--ivory);
    border-radius: 0; aspect-ratio: 1; transition: border-color .4s ease;
}
.ig-tile:hover { border-color: var(--accent); }
.ig-tile:hover img { transform: none; }
/* The fake-Instagram chrome is the least Trattoria thing on the page.
   Reduced to a single centred line: the handle, and a way to follow. */
.ig-profile {
    display: block; text-align: center; background: none; border: 0;
    box-shadow: none; padding: 0; margin: 0 auto 2rem; max-width: none;
}
.ig-avatar, .ig-stats, .ig-bio { display: none; }
.ig-toprow { display: block; }
.ig-handle { font-family: var(--serif); font-size: 1rem; letter-spacing: 0.18em; text-transform: uppercase; }
.ig-follow.btn {
    display: block; margin: 0.7rem auto 0; background: none; border: 0; padding: 0;
    color: var(--accent); font-size: 0.66rem; letter-spacing: 0.26em; text-transform: uppercase;
    border-bottom: 1px solid currentColor; width: fit-content; border-radius: 0;
}

/* ---- Reels: six to a row, nine-by-sixteen ---- */
.row-reels { grid-template-columns: repeat(6, 1fr); gap: 1.6rem; }
.reel-media { border-radius: 0; background: #2A2521; }
.reel-cap h3 { font-size: 0.92rem; }

/* ---- The story: asymmetric, with the gold rule ---- */
.story { display: grid; grid-template-columns: 400px minmax(0, 1fr); gap: 3.5rem; align-items: center; }
.story-media { position: relative; margin: 0; }
.story-media img { width: 100%; }
.story-media::after {
    content: ''; position: absolute; inset: 0.7rem;
    border: 1px solid rgba(255,255,255,0.28); pointer-events: none;
}
.story-text h2 {
    font-family: var(--serif); font-weight: 400; line-height: 1.05;
    font-size: clamp(1.9rem, 4vw, 3rem); letter-spacing: 0.05em; text-transform: uppercase;
}
.story .rule { width: 54px; height: 1px; background: var(--accent); margin: 1.4rem 0; }
.story-text p { color: var(--warm-grey); line-height: 1.85; font-size: 0.97rem; max-width: 54ch; }
.featured-cta {
    display: inline-block; margin-top: 1.8rem; font-size: 0.66rem; letter-spacing: 0.28em;
    text-transform: uppercase; color: var(--accent);
    border-bottom: 1px solid currentColor; padding-bottom: 5px;
}

/* ---- Reviews. The count is Nikki's, so this is capped at three rather
        than fluid, and a short row centres instead of stranding. ---- */
/* Nikki decides how many reviews there are, so a fixed three columns is only
   ever right by luck - four would strand one on its own. Wrap and centre, the
   same treatment the recipe library gets. */
.reviews-grid {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: 2rem; grid-template-columns: none;
}
.reviews-grid > * { flex: 0 1 calc((100% - 4rem) / 3); max-width: calc((100% - 4rem) / 3); }
@media (max-width: 1000px) { .reviews-grid > * { flex-basis: calc((100% - 2rem) / 2); max-width: calc((100% - 2rem) / 2); } }
@media (max-width: 640px)  { .reviews-grid > * { flex-basis: 100%; max-width: 100%; } }

/* ---- Newsletter: one hairline, no box ---- */
.subscribe { margin-bottom: 0; }
.sub-form {
    display: flex; gap: 0; max-width: 460px; margin: 2rem auto 0;
    border-bottom: 1px solid var(--stone); background: none; box-shadow: none; padding: 0;
}
.sub-form input[type="email"] {
    flex: 1; min-width: 0; border: 0; background: transparent; border-radius: 0;
    padding: 0.9rem 0.2rem; font-family: inherit; font-size: 0.95rem; color: var(--charcoal);
}
.sub-form input[type="email"]:focus { outline: none; }
.sub-form button {
    border: 0; background: transparent; border-radius: 0; font-family: inherit;
    font-size: 0.66rem; letter-spacing: 0.24em; text-transform: uppercase;
    color: var(--accent); cursor: pointer; padding: 0 0.4rem;
}
.collab-wrap { margin-top: 4rem; }
.collab-wrap .connect-card {
    max-width: 620px; margin: 0 auto; text-align: center;
    background: none; border: 1px solid var(--stone); box-shadow: none;
}

/* ---- Footer ---- */
footer { background: var(--espresso); }
.footer-strap {
    margin-top: 0.8rem; font-size: 0.66rem; letter-spacing: 0.16em;
    text-transform: uppercase; color: #9C8F80;
}

/* ---- Breakpoints. Every count below still divides 6 recipes, 24
        photographs and 6 reels exactly. ---- */
@media (max-width: 1150px) {
    .row-reels { grid-template-columns: repeat(3, 1fr); }
    .ig-grid   { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 860px) {
    .wrap { padding: 0 1.3rem; }
    section { padding: 3.2rem 0; }
    .row-recipes, .row-reels { grid-template-columns: repeat(2, 1fr); }
    .ig-grid { grid-template-columns: repeat(3, 1fr); }
    .reviews-grid { grid-template-columns: 1fr; }
    .story { grid-template-columns: 1fr; gap: 1.8rem; }
    .story-media { max-width: 320px; margin: 0 auto; }
    .story-text { text-align: center; }
    .story-text p { margin: 0 auto; }
    .story .rule { margin: 1.4rem auto; }
}
@media (max-width: 560px) {
    .ig-grid { grid-template-columns: repeat(2, 1fr); }
}

/* The hero still fades in via an animation, and an animation beats a plain
   declaration - so .hero-image { opacity: .42 } above was being overridden
   back to 1 the moment the fade finished. The fade has to land on 0.42. */
@keyframes heroFade { to { opacity: 0.42; } }
.hero-image { animation: heroFade 1.5s ease forwards 0.3s; }

/* Six reels to a row makes each one narrow, and the longer dish names were
   running up over the play button. Two lines, then ellipsis. */
.reel-cap h3 {
    font-size: 0.84rem; line-height: 1.3;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.reel-shade { background: linear-gradient(to top, rgba(20,16,12,0.86) 0%, rgba(20,16,12,0.28) 34%, transparent 60%); }

/* The story photograph is the one image on the page sized by width alone. */
.story-media img { width: 100%; height: auto; }

/* ---- About. This carries the manifesto, so it gets the intro treatment:
        a framed portrait, the gold rule, and the closing line in italic
        display type the way the concept sets its sign-off. ---- */
.about { background: var(--cream); padding: 5rem 0; }
.about-content {
    /* No max-width here: the element also carries .wrap, and overriding it with
       "none" let the whole row run off the right of the viewport. */
    grid-template-columns: 400px minmax(0, 1fr); gap: 3.5rem; align-items: center;
}
.about-photo {
    aspect-ratio: 4/5; border-radius: 0; overflow: visible;
    padding: 0.5rem; border: 1px solid var(--stone); background: var(--ivory); margin: 0;
}
.about-text h2 {
    font-family: var(--serif); font-weight: 400; line-height: 1.05;
    font-size: clamp(1.9rem, 4vw, 3rem); letter-spacing: 0.05em; text-transform: uppercase;
    margin-bottom: 0;
}
.about-text .rule { width: 54px; height: 1px; background: var(--accent); margin: 1.4rem 0; }
.about-text p { font-size: 0.97rem; line-height: 1.85; max-width: 56ch; }
.about-text p:last-child {
    font-family: var(--serif); font-style: italic; color: var(--charcoal);
    font-size: clamp(1.15rem, 2.4vw, 1.6rem); line-height: 1.45; margin-top: 1.6rem;
}
@media (max-width: 860px) {
    .about-content { grid-template-columns: 1fr; gap: 1.8rem; }
    .about-photo { max-width: 320px; margin: 0 auto; }
    .about-text { text-align: center; }
    .about-text p { margin-left: auto; margin-right: auto; }
    .about-text .rule { margin: 1.4rem auto; }
}

/* Dish names run to one or two lines, which dropped the meta row of the
   longer ones below its neighbours and left the grid raggedly baselined.
   Reserve two lines for every title so the meta always aligns across a row. */
/* Reserving two lines only worked while every name fitted in two. Real recipe
   names run to one, two or three lines, so instead the card is a column and the
   meta row is pushed to the bottom of it - cards in a row stretch to the same
   height, so the meta always lines up however long the names are. */
.recipe-card { display: flex; flex-direction: column; }
.recipe-card .info { display: flex; flex-direction: column; flex: 1 1 auto; }
.recipe-card .meta-tags { margin-top: auto; padding-top: 0.55rem; }

/* Six reels to a row leaves each one about 160px wide, and an overlaid title
   had to be clipped to "Slow-braised..." to stay off the play button. The name
   sits under the frame instead - the same way the recipe plates are labelled,
   and with the full width of the tile to use. */
.reel-cap {
    position: static; margin-top: 0.85rem; text-align: center; color: inherit;
}
.reel-cap h3 {
    font-family: var(--serif); font-weight: 400; font-size: 0.82rem;
    line-height: 1.35; letter-spacing: 0.04em; text-transform: uppercase;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.band-dark .reel-cap h3, .videos .reel-cap h3 { color: var(--cream); }
/* The shade under the play button no longer has a caption to lift, so it can
   go back to being subtle. */
.reel-shade { background: linear-gradient(to top, rgba(20,16,12,0.42) 0%, rgba(20,16,12,0.10) 40%, transparent 66%); }

/* ---- Nav. The concept inverts itself with mix-blend-mode: difference. That
        looks lovely and costs far too much: a position:fixed element with a
        blend mode forces the browser to re-composite it against the whole page
        on every scroll frame, and with the grain and daywash layers over the
        top the page visibly juddered while scrolling. Two states get the same
        picture for nothing - light over the dark hero, a solid bar past it.

        Scoped to #navbar, not bare nav: the bottom mobile bar is a <nav> too,
        and it was being inverted along with the header. ---- */
#navbar {
    background: none; box-shadow: none; backdrop-filter: none;
    padding: 1.4rem 2.5rem; color: var(--ivory);
}
/* The mark is always there in the concept, not revealed on scroll. */
.logo, #navbar.scrolled .logo {
    opacity: 1; pointer-events: auto; color: var(--ivory);
    font-size: 1.15rem; letter-spacing: 0.24em;
    text-shadow: 0 1px 12px rgba(20,16,12,0.55);
}
.nav-links { gap: 2.4rem; }
.nav-links a, .nav-links a[aria-current="page"] {
    color: var(--ivory); font-size: 0.7rem; letter-spacing: 0.22em;
    text-shadow: 0 1px 12px rgba(20,16,12,0.55);
}
.nav-links a::after, .nav-links a[aria-current="page"]::after { background: currentColor; }
#navbar .nav-toggle span { background: var(--ivory); }

/* The hero is the full view in the concept, with the nav floating on top of
   it rather than sitting above it. */
.hero.hero-landing { height: 92svh; }

/* Past the hero it becomes a plain bone bar. Opaque rather than blurred -
   a backdrop-filter on a fixed bar is another per-frame cost for an effect
   nobody can see against a flat background. */
#navbar.scrolled {
    color: var(--charcoal); background: var(--ivory);
    box-shadow: 0 1px 0 var(--stone); backdrop-filter: none;
}
#navbar.scrolled .logo, #navbar.scrolled .nav-links a { color: var(--charcoal); text-shadow: none; }
#navbar.scrolled .nav-links a[aria-current="page"] { color: var(--accent); }
#navbar.scrolled .nav-links a[aria-current="page"]::after { background: var(--accent); }
#navbar.scrolled .nav-toggle span { background: var(--charcoal); }
/* Pages without a hero start in the bar state, so they never blend. */
.page-head { padding-top: 7rem; }
.page-head h1 { letter-spacing: 0.05em; text-transform: uppercase; }

/* The fixed nav must not sit on top of the heading an anchor jumps to. */
section[id], header[id] { scroll-margin-top: 84px; }

/* A left-aligned section head should not centre its arch in the column. */
.about-text .arch { margin-left: 0; margin-right: 0; }
/* The hairline before the sign-off predates the re-skin; bring it onto the
   Trattoria rule colour so it reads as intended rather than as a stray line. */
.about-text p:last-child { border-top-color: var(--stone); }

/* ---- The gallery goes full bleed. It sits outside .wrap in the markup, so
        it only needs its own gutters cleared. Eight across once there is room
        for it - 24 photographs divide 8, 6, 4, 3 and 2, so every one of these
        fills its rows exactly. ---- */
.ig-grid { padding: 0 0.9rem; gap: 0.9rem; }
@media (min-width: 1500px) {
    .ig-grid { grid-template-columns: repeat(8, 1fr); }
}

/* Every section still carried 4rem of side padding from the old layout, on top
   of the gutters .wrap already provides - which squeezed the content column on
   mid-width screens and, on the feed, stopped the gallery reaching the edges.
   .wrap governs the gutters now; sections only own their vertical rhythm. */
.recipes, .videos, .featured, .reviews, .feed, .connect, .about { padding: 5rem 0; }
/* The gallery is the exception that proves it: no gutters at all, side to side. */
.ig-grid { padding: 0; }
@media (max-width: 860px) {
    .recipes, .videos, .featured, .reviews, .feed, .connect, .about { padding: 3.2rem 0; }
}

/* ---- Landscape films. One to a row, built to 16:9, so they are never
        cropped into the portrait reel shape and no row is left part empty
        whatever the count. ---- */
.film-grid { display: grid; grid-template-columns: 1fr; gap: 2.4rem; margin: 0 auto 3rem; }
.film .reel-media { aspect-ratio: 16 / 9; }
.film .reel-media img, .film .reel-loop { aspect-ratio: 16 / 9; }
.film .reel-cap h3 {
    font-size: 1.15rem; -webkit-line-clamp: 2;
}
.film .reel-play { width: 62px; height: 62px; }
.film .reel-play svg { width: 22px; height: 22px; }
@media (max-width: 860px) {
    .film-grid { gap: 1.6rem; margin-bottom: 2rem; }
    .film .reel-cap h3 { font-size: 1rem; }
}

/* ---- The recipe library is the one grid whose count nobody controls: Nikki
        adds recipes, and the category filters cut it to whatever they cut it
        to. A fixed column count can only ever be right by luck, so this wraps
        and centres instead - a short last row sits in the middle and reads as
        deliberate rather than as a gap. (The grid-template-columns rules
        higher up are inert on a flex container; they are left alone rather
        than half-removed.) ---- */
.recipe-grid {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: 2.4rem 2rem; max-width: 1300px; margin: 0 auto;
}
.recipe-grid > .recipe-card {
    flex: 0 1 calc((100% - 4rem) / 3); max-width: calc((100% - 4rem) / 3);
}
.recipe-grid > p { flex: 1 0 100%; }
@media (max-width: 1150px) {
    .recipe-grid > .recipe-card { flex-basis: calc((100% - 2rem) / 2); max-width: calc((100% - 2rem) / 2); }
}
@media (max-width: 700px) {
    .recipe-grid > .recipe-card { flex-basis: 100%; max-width: 100%; }
}

/* A recipe written before it has been photographed still gets a card, rather
   than a broken image icon. */
.no-photo {
    display: flex; align-items: center; justify-content: center; text-align: center;
    aspect-ratio: 1; padding: 1.5rem; background: var(--cream);
    font-family: var(--serif); font-size: 1.05rem; line-height: 1.35;
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--warm-grey);
}
/* Her own reel, playing inside the recipe. */
#dVideo video { width: 100%; display: block; background: #1E1813; }

/* Ingredient group headings - "For the mash" - are labels, not items. */
.ing-head {
    list-style: none; cursor: default; padding-left: 0; margin-top: 1.1rem;
    font-size: 0.66rem; letter-spacing: 0.22em; text-transform: uppercase;
    color: var(--accent); font-weight: 500;
}
.ing-head:first-child { margin-top: 0; }

/* ---- Dish names. Reserving space for the longest name in a row left a hole
        under every shorter one. Two lines, always: short names still occupy
        two, long ones stop at two. Every card is the same shape, so nothing
        has to stretch to match its neighbour. ---- */
.recipe-card h4 {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; line-height: 1.25; min-height: 2.5em;
    font-size: 1rem; letter-spacing: 0.06em;
}

/* ---- Her own reel inside a recipe. .detail-video is 16:9 with overflow
        hidden, built for a YouTube iframe - a nine-by-sixteen reel dropped in
        there was cropped to a letterbox slice through the middle of the frame,
        which is why it only looked right once it was made fullscreen. A file
        keeps its own shape instead. ---- */
.detail-video.is-file { aspect-ratio: auto; overflow: visible; background: transparent; }
.detail-video.is-file video {
    width: 100%; height: auto; display: block;
    background: var(--espresso); border-radius: 6px;
}
.detail-video.is-portrait { max-width: 300px; margin-left: auto; margin-right: auto; }

/* ---- The sign-up was a single hairline, which read as decoration rather than
        as somewhere to type. It gets a box and a solid button. ---- */
.sub-form {
    border: 1px solid var(--stone); border-bottom: 1px solid var(--stone);
    background: var(--ivory); padding: 0.3rem 0.3rem 0.3rem 1.1rem;
    align-items: center; transition: border-color .3s ease;
}
.sub-form:focus-within { border-color: var(--accent); }
.sub-form input[type="email"] { padding: 0.8rem 0.2rem; }
/* No opacity here. The 0.8 composited --warm-grey down to about 3.55:1, and
   this placeholder is doing real work - it is the only thing on screen telling
   you what the box is for. */
.sub-form input[type="email"]::placeholder { color: var(--warm-grey); opacity: 1; }
.sub-form button {
    background: var(--charcoal); color: var(--ivory);
    padding: 0.85rem 1.5rem; letter-spacing: 0.24em; transition: background .3s ease;
}
.sub-form button:hover { background: var(--accent); }
@media (max-width: 480px) {
    .sub-form { padding-left: 0.8rem; }
    .sub-form button { padding: 0.8rem 1rem; letter-spacing: 0.16em; }
}

/* The bottom bar is a <nav> as well, which is how it ended up inverted when the
   header nav was blending. Solid, and no backdrop-filter: that is a per-frame
   cost on a fixed element for a blur nobody sees against flat paper. */
.mobile-bar { background: var(--ivory); backdrop-filter: none; }

/* ============================================================
   THE PHOTOGRAPHS TURN ON A CUBE
   Swiping does not slide one picture off and another on - it turns a solid.
   The photograph you are looking at is the front face; the next one is the
   face to its right, the previous one the face to its left. Dragging rotates
   the whole thing about its Y axis, so you see the two faces meet at the
   corner, in perspective, the way a story does.

   The cube's half-depth has to equal half its width or the corners come
   apart, and that is a pixel measurement - so --pmW is set from JS whenever
   the stage is sized, and every face reads it.
   ============================================================ */
.post-modal {
    background: none; border-radius: 0; overflow: visible; display: block;
    width: min(940px, 92vw); height: min(620px, 82vh);
    max-width: none; max-height: none;
    perspective: 1600px;
}
.pm-stage {
    position: relative; width: 100%; height: 100%;
    transform-style: preserve-3d;
    transition: transform .5s cubic-bezier(.22,.61,.36,1);
    touch-action: none;        /* the drag is ours, not the browser's */
    cursor: grab;
}
.pm-stage:active { cursor: grabbing; }
.pm-face { position: absolute; inset: 0; backface-visibility: hidden; }
.pm-face.cur  { transform: rotateY(0deg)   translateZ(calc(var(--pmW, 900px) / 2)); }
.pm-face.next { transform: rotateY(90deg)  translateZ(calc(var(--pmW, 900px) / 2)); }
.pm-face.prev { transform: rotateY(-90deg) translateZ(calc(var(--pmW, 900px) / 2)); }

.pm-card {
    width: 100%; height: 100%; background: var(--ivory);
    display: grid; grid-template-columns: 1.35fr 1fr;
    overflow: hidden; border-radius: 6px;
    /* No drop shadow. Two faces of a cube share an edge, and a 90px blur cast
       across that seam reads as a gap between two flat cards - which is the
       one thing the whole effect is trying not to look like. */
}

/* A face turning away from the light goes darker, the way a real one would.
   Without it the cube reads as two pictures on hinges; with it, as a solid.
   The stage sets these each frame from the angle it is at.

   It hangs off .pm-card, not .pm-face. On the face it is a sibling of the card
   inside a preserve-3d context, where it gets sorted in 3D and occludes the
   photograph - at opacity 0, with nothing visibly there. The card is a plain
   2D box, so inside it the overlay behaves like an overlay. */
.pm-card { position: relative; }
.pm-card::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: #14100C;
    transition: opacity .5s cubic-bezier(.22,.61,.36,1);
}
.pm-face.cur .pm-card::after { opacity: var(--shadeCur, 0); }
.pm-face.prev .pm-card::after, .pm-face.next .pm-card::after { opacity: var(--shadeSide, 0.5); }
/* Mid-drag the shading has to keep up with the finger, not ease after it. */
.pm-stage.dragging .pm-card::after { transition: none; }
.pm-card .pm-img { background: var(--espresso); min-height: 0; }
/* contain, not cover: her photographs are the point, and cropping them to fit
   a fixed pane would cut the top off half of them. */
.pm-card .pm-img img {
    width: 100%; height: 100%; object-fit: contain;
    max-height: none; user-select: none; -webkit-user-drag: none;
}
.pm-card .pm-side { min-height: 0; overflow-y: auto; }
.pm-card .pm-caption { flex: 0 1 auto; }

@media (max-width: 700px) {
    .post-modal { width: 94vw; height: 86vh; perspective: 1100px; }
    .pm-card { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
    .pm-card .pm-side { padding: 1.1rem 1.2rem 1.4rem; }
    .pm-card .pm-caption { margin: 0.7rem 0; line-height: 1.6; }
    .pm-card .pm-head { padding-bottom: 0.7rem; }
    .pm-card .pm-head .av { width: 34px; height: 34px; }
}
/* Turning a solid is the whole point, so if motion is unwelcome there is no
   half-measure - the faces just swap. */
@media (prefers-reduced-motion: reduce) {
    .pm-stage { transition: none; }
}

/* ---- The films run the full width of the page, like the gallery. They are
        the only other block that is all picture, and boxing them into the text
        column left them stranded in the middle of a very wide band. ---- */
.row-reels, .reel-grid, .film-grid { max-width: none; padding: 0; }
/* A 16:9 film at full width is over 1000px tall on a wide screen - taller than
   the window. But capping the height of a box with an aspect-ratio caps its
   width too, which left the film 973px wide in a 1553px row with a slab of
   empty band beside it. Drop the ratio, take the full width, and let the
   height be whichever is smaller: a comfortable slice of the window, or the
   16:9 height that width implies. Crops rather than shrinks, so it reads as a
   cinema band across the page. */
.film .reel-media {
    aspect-ratio: auto; width: 100%; max-height: none;
    height: min(72vh, 56.25vw);
}
.film .reel-media img, .film .reel-loop { object-fit: cover; }
@media (max-width: 860px) {
    .row-reels, .reel-grid, .film-grid { padding: 0 0.6rem; }
}

/* ---- Recipes take the full page too. A 1rem gutter rather than flush to the
        edge: the gallery is a contact sheet and looks deliberate flush, but a
        recipe card has a hairline frame around it, and a frame touching the
        edge of the screen reads as cropped. ---- */
.recipe-grid, .row-recipes { max-width: none; padding: 0 1rem; }

/* The landing row: six recipes, six across, one clean row mirroring the six
   reels below it. Every step down still divides six exactly. */
.row-recipes { grid-template-columns: repeat(6, 1fr); gap: 2.4rem 1.4rem; }
@media (max-width: 1500px) { .row-recipes { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 860px)  { .row-recipes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .row-recipes { grid-template-columns: 1fr; } }

/* The library: four across on a wide screen. Still wrapping and centring, so
   any number of recipes - and any subset a filter leaves behind - fills its
   rows and a short last row sits in the middle. */
.recipe-grid { gap: 2.6rem 1.4rem; }
.recipe-grid > .recipe-card {
    flex-basis: calc((100% - 4.2rem) / 4); max-width: calc((100% - 4.2rem) / 4);
}
@media (max-width: 1500px) {
    .recipe-grid > .recipe-card { flex-basis: calc((100% - 2.8rem) / 3); max-width: calc((100% - 2.8rem) / 3); }
}
@media (max-width: 1150px) {
    .recipe-grid > .recipe-card { flex-basis: calc((100% - 1.4rem) / 2); max-width: calc((100% - 1.4rem) / 2); }
}
@media (max-width: 700px) {
    .recipe-grid > .recipe-card { flex-basis: 100%; max-width: 100%; }
}

/* ---- Eight reels now, not six. The library grid and the landing row need
        different counts because they hold different numbers: the landing shows
        six, the videos page shows all eight. Both divide exactly at every
        step. ---- */
.reel-grid { grid-template-columns: repeat(8, 1fr); }
@media (max-width: 1500px) { .reel-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 860px)  { .reel-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .reel-grid { grid-template-columns: repeat(2, 1fr); } }

/* ---- The frames around photographs go darker than the rules do. A 1px line
        at --stone is almost invisible on bone, so the framed-plate idea the
        whole design rests on was barely reading. ---- */
.recipe-card .thumb,          /* the plates */
.ig-tile,                     /* the gallery */
.about-photo {                /* her portrait */
    border-color: var(--frame);
}
