/* ============================================================================
   DK Food Junction - public site
   ----------------------------------------------------------------------------
   Design tokens first, then components. Every class name the views already use
   is kept, so this file can be swapped without touching a single view.

   Palette comes from the brand moodboard: forest green leads, orange and
   yellow are the accents, on warm off-white rather than flat grey.
   ============================================================================ */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700;800&family=Inter:wght@400;500;600&display=swap');

:root {
    /* Brand */
    --brand: #0F5132;
    --brand-600: #14663C;
    --brand-dark: #0A3B24;
    --brand-soft: #EAF2EC;

    --accent: #EF6820;
    --accent-dark: #D2540F;
    --accent-soft: #FEEFE4;

    --yellow: #F9C21A;
    --yellow-soft: #FEF6DC;
    --lime: #8CC63F;
    --red: #D0342C;

    /* Neutrals - warm, not grey */
    --ink: #14201A;
    --ink-2: #3D4A43;
    --ink-soft: #6B7872;
    --line: #E7EAE7;
    --line-soft: #F1F3F1;
    --bg: #FFFFFF;
    --bg-alt: #F8FAF8;
    --cream: #FBF7EF;

    /* Shape */
    --r-xs: 8px;
    --r-sm: 12px;
    --r: 18px;
    --r-lg: 26px;
    --r-pill: 999px;

    /* Depth - layered, never a single hard drop */
    --sh-xs: 0 1px 2px rgba(20, 32, 26, .05);
    --sh-sm: 0 2px 8px rgba(20, 32, 26, .06), 0 1px 2px rgba(20, 32, 26, .04);
    --sh: 0 8px 24px rgba(20, 32, 26, .08), 0 2px 6px rgba(20, 32, 26, .04);
    --sh-lg: 0 20px 48px rgba(20, 32, 26, .12), 0 4px 12px rgba(20, 32, 26, .06);
    --sh-brand: 0 10px 30px rgba(15, 81, 50, .22);

    /* Motion */
    --ease: cubic-bezier(.4, 0, .2, 1);
    --t: 220ms var(--ease);
}

/* ============================================================================
   The responsive scale
   ----------------------------------------------------------------------------
   Every display size and every band of vertical space on the site comes from
   these, and nowhere else. Change a number here and the whole site moves with
   it, in step.

   The old sizes were written as clamp(min, vw, max), which reads well but has
   one flaw that turned out to matter: a vw clamp stops growing once it hits
   its ceiling, and the hero hit its ceiling at 1231px wide. From there up,
   every screen got exactly the same 64px headline - so a 1366x768 laptop was
   shown type meant for a 1920x1080 monitor, on a screen with 40% less room.
   That is what "everything looks big on my laptop" was.

   Two things fix it. Bands that keep going past 1231px, so a desktop is bigger
   than a laptop rather than identical to it. And a height band, because a
   laptop and a desktop differ far more in height than in width: 1366x768 and
   1920x1080 are two thirds of a screen apart vertically. Nothing measured in
   vw can see that, which is why no amount of width tuning ever fixed it.
   ========================================================================= */

:root {
    /* Display type */
    /* How tall the sticky header is. Measured by site.js at every width;
       this is the fallback for the moment before it runs. Anything that
       sticks below the header reads it rather than guessing zero. */
    --header-h: 66px;

    --t-hero: 2.05rem;   /* the home page headline */
    --t-h1:   1.6rem;    /* a page heading */
    --t-h2:   1.45rem;   /* a section heading */
    --t-h3:   1.25rem;   /* a panel or player heading */
    --t-stat: 1.7rem;    /* the big numbers */

    /* Vertical rhythm */
    --y-hero: 2.4rem;
    --y-sect: 2.2rem;
    --y-head: 1.7rem;
}

@media (min-width: 576px) {
    :root {
        --t-hero: 2.3rem; --t-h1: 1.75rem; --t-h2: 1.55rem; --t-h3: 1.3rem; --t-stat: 1.85rem;
        --y-hero: 2.8rem; --y-sect: 2.5rem; --y-head: 1.9rem;
    }
}

/* Tablet, portrait. */
@media (min-width: 768px) {
    :root {
        --t-hero: 2.6rem; --t-h1: 1.95rem; --t-h2: 1.7rem; --t-h3: 1.4rem; --t-stat: 2rem;
        --y-hero: 3.2rem; --y-sect: 2.9rem; --y-head: 2.1rem;
    }
}

/* Tablet landscape and the smallest laptops. */
@media (min-width: 992px) {
    :root {
        --t-hero: 2.9rem; --t-h1: 2.1rem; --t-h2: 1.85rem; --t-h3: 1.5rem; --t-stat: 2.1rem;
        --y-hero: 3.6rem; --y-sect: 3.2rem; --y-head: 2.3rem;
    }
}

/* Laptop. */
@media (min-width: 1280px) {
    :root {
        --t-hero: 3.1rem; --t-h1: 2.25rem; --t-h2: 1.95rem; --t-h3: 1.55rem; --t-stat: 2.2rem;
        --y-hero: 3.8rem; --y-sect: 3.4rem; --y-head: 2.4rem;
    }
}

/* Desktop. Room to be generous again. */
@media (min-width: 1600px) {
    :root {
        --t-hero: 3.5rem; --t-h1: 2.5rem; --t-h2: 2.15rem; --t-h3: 1.65rem; --t-stat: 2.4rem;
        --y-hero: 4.4rem; --y-sect: 3.8rem; --y-head: 2.7rem;
    }
}

@media (min-width: 1900px) {
    :root {
        --t-hero: 3.8rem; --t-h1: 2.7rem; --t-h2: 2.3rem; --t-h3: 1.75rem; --t-stat: 2.6rem;
        --y-hero: 4.8rem; --y-sect: 4.2rem; --y-head: 3rem;
    }
}

/* The one that actually fixes the laptop.

   A wide but short screen - 1366x768, 1440x810, a browser with the dev tools
   docked - has plenty of room across and very little down. Width alone says
   "this is a desktop" and hands it desktop type; the height says otherwise.
   This comes last so it wins over the width bands above it. */
@media (min-width: 992px) and (max-height: 860px) {
    :root {
        --t-hero: 2.7rem; --t-h1: 2rem; --t-h2: 1.75rem; --t-h3: 1.45rem; --t-stat: 2rem;
        --y-hero: 2.9rem; --y-sect: 2.7rem; --y-head: 1.9rem;
    }
}

/* Shorter still, which is a laptop with a toolbar or two open. */
@media (min-width: 992px) and (max-height: 700px) {
    :root {
        --t-hero: 2.4rem; --t-h1: 1.85rem; --t-h2: 1.6rem; --t-h3: 1.35rem; --t-stat: 1.85rem;
        --y-hero: 2.4rem; --y-sect: 2.3rem; --y-head: 1.6rem;
    }
}

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

html { scroll-behavior: smooth; }

body {
    margin: 0;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--ink-2);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6, .navbar-brand, .hero-title, .stat-value {
    font-family: 'Plus Jakarta Sans', 'Inter', sans-serif;
    color: var(--ink);
    letter-spacing: -.02em;
    line-height: 1.15;
}

a { text-decoration: none; transition: color var(--t); }

img { max-width: 100%; }

::selection { background: var(--yellow); color: var(--brand-dark); }

:focus-visible {
    outline: 3px solid rgba(249, 194, 26, .55);
    outline-offset: 2px;
    border-radius: var(--r-xs);
}

/* ---------------------------------------------------------------- Buttons */

.btn {
    border-radius: var(--r-pill);
    font-weight: 600;
    letter-spacing: -.01em;
    padding: .6rem 1.4rem;
    transition: transform var(--t), box-shadow var(--t), background var(--t), color var(--t), border-color var(--t);
}

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

.btn-lg { padding: .85rem 2rem; font-size: 1.02rem; }
.btn-sm { padding: .42rem 1rem; font-size: .87rem; }

.btn-brand {
    background: var(--brand);
    border: 1px solid var(--brand);
    color: #fff;
    box-shadow: var(--sh-sm);
}

.btn-brand:hover {
    background: var(--brand-600);
    border-color: var(--brand-600);
    color: #fff;
    box-shadow: var(--sh-brand);
    transform: translateY(-2px);
}

.btn-outline-brand {
    border: 1.5px solid rgba(15, 81, 50, .28);
    color: var(--brand);
    background: transparent;
}

.btn-outline-brand:hover {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
    transform: translateY(-2px);
    box-shadow: var(--sh-brand);
}

.btn-link { color: var(--ink-soft); font-weight: 500; }
.btn-link:hover { color: var(--brand); }

/* ---------------------------------------------------------------- Header */

.site-header {
    position: sticky;
    top: 0;
    z-index: 200;
    background: rgba(255, 255, 255, .82);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--line-soft);
}

.site-header::before {
    content: "";
    display: block;
    height: 3px;
    background: linear-gradient(90deg, var(--yellow), var(--accent) 55%, var(--brand));
}

.site-header .navbar { padding-top: .7rem; padding-bottom: .7rem; }

.navbar-brand {
    display: flex;
    align-items: center;
    gap: .7rem;
    font-weight: 800;
    font-size: 1.06rem;
    color: var(--ink);
}

.brand-logo {
    width: 44px;
    height: 44px;
    /* The logo is a round badge, so the ring follows the circle. */
    border-radius: 50%;
    object-fit: cover;
    display: block;
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--yellow), var(--sh-sm);
}

.brand-text { letter-spacing: -.03em; }

.site-header .nav-link {
    color: var(--ink-2);
    font-weight: 500;
    font-size: .95rem;
    padding: .5rem .9rem;
    border-radius: var(--r-pill);
    transition: var(--t);
}

.site-header .nav-link:hover { color: var(--brand); background: var(--brand-soft); }

.site-header .btn-brand {
    background: var(--yellow);
    border-color: var(--yellow);
    color: var(--brand-dark);
    font-weight: 700;
    box-shadow: 0 6px 18px rgba(249, 194, 26, .35);
}

.site-header .btn-brand:hover {
    background: #FFD24D;
    border-color: #FFD24D;
    color: var(--brand-dark);
    box-shadow: 0 10px 26px rgba(249, 194, 26, .45);
}

/* The hamburger.
   Bootstrap 5.1 only paints its toggler icon under .navbar-light, and this
   navbar does not use that class, so the button was rendering completely
   blank on phones. The icon is drawn here instead, which also means it can
   turn into a cross when the menu is open. */
.navbar-toggler {
    border: 1.5px solid rgba(15, 81, 50, .18);
    border-radius: var(--r-sm);
    padding: .55rem .6rem;
    background: #fff;
    box-shadow: var(--sh-xs) !important;
    transition: var(--t);
}

.navbar-toggler:hover { border-color: rgba(15, 81, 50, .38); }

.navbar-toggler-icon {
    background-image: none !important;
    width: 22px;
    height: 14px;
    position: relative;
    display: block;
}

.navbar-toggler-icon::before,
.navbar-toggler-icon::after {
    content: "";
    position: absolute;
    left: 0; right: 0;
    height: 2px;
    border-radius: 2px;
    background: var(--brand);
    transition: transform var(--t), top var(--t), box-shadow var(--t);
}

/* Top bar, with the middle one drawn by its shadow. */
.navbar-toggler-icon::before { top: 0; box-shadow: 0 6px 0 var(--brand); }
.navbar-toggler-icon::after  { top: 12px; }

.navbar-toggler[aria-expanded="true"] .navbar-toggler-icon::before {
    top: 6px; transform: rotate(45deg); box-shadow: none;
}

.navbar-toggler[aria-expanded="true"] .navbar-toggler-icon::after {
    top: 6px; transform: rotate(-45deg);
}

/* ---------------------------------------------------------------- Hero */

.hero {
    position: relative;
    padding: var(--y-hero) 0 calc(var(--y-hero) * .9);
    overflow: hidden;
    background:
        radial-gradient(1100px 460px at 12% -10%, rgba(249, 194, 26, .30), transparent 62%),
        radial-gradient(900px 420px at 92% 6%, rgba(239, 104, 32, .18), transparent 60%),
        radial-gradient(760px 520px at 60% 110%, rgba(15, 81, 50, .10), transparent 65%),
        var(--cream);
}

.hero-kicker {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    background: #fff;
    border: 1px solid rgba(239, 104, 32, .22);
    color: var(--accent-dark);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: .7rem;
    font-weight: 700;
    padding: .38rem .9rem;
    border-radius: var(--r-pill);
    margin-bottom: 1.2rem;
    box-shadow: var(--sh-xs);
}

.hero-kicker::before {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--accent);
}

.hero-title {
    font-size: var(--t-hero);
    font-weight: 800;
    letter-spacing: -.035em;
    margin-bottom: 1.1rem;
}

.hero-title::after {
    content: "";
    display: block;
    width: 84px;
    height: 6px;
    margin-top: 1.3rem;
    border-radius: var(--r-pill);
    background: linear-gradient(90deg, var(--yellow), var(--accent));
}

.hero-text {
    color: var(--ink-soft);
    font-size: 1.1rem;
    max-width: 34rem;
    margin-bottom: 0;
}

.hero-actions { display: flex; gap: .8rem; flex-wrap: wrap; margin-top: 1.4rem; }

.hero-video {
    border-radius: var(--r-lg);
    overflow: hidden;
    box-shadow: var(--sh-lg);
    background: #000;
    transform: rotate(-.6deg);
    transition: transform var(--t);
}

.hero-video:hover { transform: rotate(0deg) scale(1.01); }
.hero-video iframe { border: 0; }

.hero-video-caption {
    background: #fff;
    padding: 1rem 1.1rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    font-family: 'Plus Jakarta Sans', sans-serif;
}

.hero-empty {
    background: rgba(255, 255, 255, .75);
    backdrop-filter: blur(8px);
    border: 1.5px dashed rgba(15, 81, 50, .2);
    border-radius: var(--r-lg);
    padding: 2.5rem 2rem;
    text-align: center;
}

.hero-empty h5 { font-weight: 700; }
.hero-empty p { color: var(--ink-soft); }

/* When there is no video to show yet, the logo carries the space instead. */
.hero-empty-logo {
    width: 168px;
    height: 168px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    margin: 0 auto 1.25rem;
    background: #fff;
    box-shadow:
        0 0 0 5px #fff,
        0 0 0 10px rgba(249, 194, 26, .9),
        var(--sh-lg);
}

/* ---------------------------------------------------------------- Sections */

/* Sections used to be 5.5rem top and bottom - eleven rems of nothing between
   one idea and the next, which on a laptop meant a whole screen of cream
   between two rows of cards. Enough to separate, not enough to lose people. */
.section { padding: var(--y-sect) 0; }
.section-alt { background: var(--bg-alt); }

.section-strip {
    padding: 2.5rem 0;
    background: linear-gradient(180deg, #fff, var(--yellow-soft));
    border-top: 1px solid rgba(249, 194, 26, .3);
    border-bottom: 1px solid rgba(249, 194, 26, .3);
}

/* The facts band under the hero.
   It used to stack each number above its label inside a four column grid,
   which cost most of a screen to say four short things. Number and label now
   share a line and the whole band is about the height of a menu bar. */
.stat-strip {
    padding: .95rem 0;
    background: linear-gradient(180deg, #fff, var(--yellow-soft));
    border-top: 1px solid rgba(249, 194, 26, .3);
    border-bottom: 1px solid rgba(249, 194, 26, .3);
}

.stat-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .35rem 2.4rem;
}

.stat {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    white-space: nowrap;
}

.stat .stat-value { font-size: 1.5rem; line-height: 1.1; }
.stat .stat-label { font-size: .85rem; }

.section-head { text-align: center; margin-bottom: 2rem; max-width: 42rem; margin-left: auto; margin-right: auto; }

.section-head h2 {
    font-weight: 800;
    font-size: var(--t-h2);
    margin-bottom: .6rem;
}

.section-head h2::after {
    content: "";
    display: block;
    width: 54px;
    height: 5px;
    margin: 1rem auto 0;
    border-radius: var(--r-pill);
    background: linear-gradient(90deg, var(--yellow), var(--accent));
}

.section-head p { color: var(--ink-soft); margin: .9rem 0 0; font-size: 1.03rem; }

.page-head {
    /* A page head is a title and a line of explanation. It does not need the
       height of a hero to say so. */
    padding: var(--y-head) 0 calc(var(--y-head) * .84);
    background:
        radial-gradient(700px 300px at 8% 0%, rgba(249, 194, 26, .22), transparent 60%),
        var(--cream);
    border-bottom: 1px solid var(--line);
}

.page-head h1 { font-weight: 800; font-size: var(--t-h1); margin-bottom: .5rem; }
.page-head p { color: var(--ink-soft); margin: 0; font-size: 1.03rem; }

.stat-value { font-size: var(--t-stat); font-weight: 800; color: var(--accent); letter-spacing: -.04em; }
.stat-label { color: var(--ink-soft); font-size: .88rem; font-weight: 500; }

/* ---------------------------------------------------------------- Cards */

.category-card,
.video-card,
.course-card,
.restaurant-card,
.contact-box,
.card-form,
.panel-lite,
.status-card,
.empty-state,
.filter-bar,
.info-panel,
.nearby-card,
.related-item,
.owner-box,
.map-wrap,
.qr-box,
.map-pick,
.photo-slot,
.preview-box {
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    box-shadow: var(--sh-xs);
}

.category-card {
    display: block;
    height: 100%;
    padding: 1.7rem;
    color: var(--ink);
    transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}

.category-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--sh);
    border-color: rgba(249, 194, 26, .55);
}

.category-card h5 { font-weight: 700; margin-bottom: .4rem; }
.category-card p { color: var(--ink-soft); font-size: .93rem; margin-bottom: .7rem; }

.category-count {
    color: var(--accent-dark);
    font-weight: 700;
    font-size: .82rem;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}

.category-count::after { content: "\2192"; transition: transform var(--t); }
.category-card:hover .category-count::after { transform: translateX(4px); }

.video-card,
.restaurant-card {
    display: block;
    height: 100%;
    overflow: hidden;
    color: var(--ink);
    transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}

.video-card:hover,
.restaurant-card:hover {
    transform: translateY(-5px);
    box-shadow: var(--sh);
    border-color: rgba(249, 194, 26, .55);
}

.restaurant-card { display: flex; flex-direction: column; }

.video-thumb, .restaurant-thumb {
    position: relative;
    aspect-ratio: 16/9;
    background: var(--brand-soft);
    overflow: hidden;
}

.video-thumb img, .restaurant-thumb img {
    width: 100%; height: 100%;
    display: block;
    transition: transform 500ms var(--ease);
}

/* A YouTube thumbnail is always the same shape and arrives with black bars
   baked into it, so filling the frame is right - it trims the bars off. */
.video-thumb img { object-fit: cover; }

/* A kitchen's photo is whatever they had on their phone: a menu banner, a
   shopfront taken portrait, a square logo. Cropping those to a letterbox cuts
   the top and bottom off the very thing being shown, so the whole picture is
   shown and the frame is padded around it instead. Nothing is ever cut off,
   and nothing is ever squashed out of shape.

   The padding used to be a flat grey bar, which is what made a row of cards
   look like three unrelated blocks - one edge to edge, one with wide margins,
   one nearly square. The gap is now filled by the same photo, blurred and
   scaled to cover, so every card reads as one full frame in its own colours
   while the real picture sits whole on top of it. */
.restaurant-thumb { background: var(--bg-alt); }
.restaurant-thumb img { object-fit: contain; }

.photo-fit { position: absolute; inset: 0; overflow: hidden; }

/* Written with the frame in front of them on purpose: ".restaurant-thumb img"
   above sets width, height and object-fit, and a single class would lose to it
   and leave the backdrop contained instead of covering. */
.restaurant-thumb .photo-blur,
.gallery-slide .photo-blur {
    /* Deliberately bigger than the frame it sits in. A blur samples past the
       element's own edges and fades to transparent there, so at exactly 100%
       the frame ends in a pale halo - which looks worse than the flat bar it
       replaced. Overhanging puts that soft edge outside the crop. */
    position: absolute;
    top: -20%; left: -20%;
    width: 140%; height: 140%;
    object-fit: cover;

    /* The site-wide "img { max-width: 100% }" was silently clamping this back
       to the frame width, so the overhang existed on paper and not on screen -
       which is why the right edge kept fading. */
    max-width: none;

    /* The overhang has to clear roughly three times the blur radius, or the
       fade to transparent creeps back inside the frame and leaves a pale rim
       down the edges. A fifth of the frame comfortably clears 18px. */
    filter: blur(18px) saturate(1.3) brightness(.9);
    background: none;
}

.restaurant-thumb .photo-real,
.gallery-slide .photo-real {
    position: relative;
    width: 100%; height: 100%;
    object-fit: contain;
    background: none;
}

/* Somebody who has not added a photo yet keeps the initial, and it fills the
   same frame - so a row with one photoless kitchen in it still lines up. */

.video-card:hover .video-thumb img { transform: scale(1.06); }

.restaurant-thumb-empty {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 2.8rem; font-weight: 800;
    color: var(--brand);
    background: linear-gradient(135deg, var(--brand-soft), var(--yellow-soft));
}

.play-badge {
    position: absolute; inset: 0; margin: auto;
    width: 58px; height: 58px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .92);
    color: var(--accent);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.15rem;
    box-shadow: var(--sh);
    transition: transform var(--t), background var(--t), color var(--t);
}

.video-card:hover .play-badge { transform: scale(1.12); background: var(--accent); color: #fff; }

.ribbon {
    position: absolute; top: .8rem; left: .8rem;
    background: var(--yellow);
    color: var(--brand-dark);
    border-radius: var(--r-pill);
    padding: .2rem .8rem;
    font-size: .72rem; font-weight: 800;
    letter-spacing: .02em;
    box-shadow: var(--sh-sm);
}

.video-body, .restaurant-body { padding: 1.3rem; }
.restaurant-body { display: flex; flex-direction: column; flex: 1; }

.video-body h6, .restaurant-body h5 {
    font-weight: 700;
    margin: .6rem 0 .45rem;
    letter-spacing: -.02em;
}

.video-meta, .restaurant-meta {
    display: flex; gap: .55rem;
    align-items: center; flex-wrap: wrap;
    color: var(--ink-soft);
    font-size: .84rem;
}

.badge-soft {
    display: inline-block;
    background: var(--yellow-soft);
    color: #7A5B00;
    border-radius: var(--r-pill);
    padding: .2rem .7rem;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .01em;
}

.restaurant-owner { font-size: .9rem; margin: .7rem 0 .3rem; }
.restaurant-desc { font-size: .92rem; color: var(--ink-soft); margin-bottom: .5rem; }
.restaurant-address { font-size: .85rem; color: var(--ink-soft); margin-bottom: 1rem; }
.restaurant-actions { display: flex; gap: .45rem; flex-wrap: wrap; margin-top: auto; }

/* The cards divide the row between them: one training takes the whole width,
   two split it, three or more sit three to a row and wrap. The minmax floor
   keeps a card from ever being squeezed under a readable width - which is also
   what stops a fourth column appearing on a wide screen: each column must be
   at least a third of the row, so three is the most that fit. */
.course-grid {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: repeat(auto-fit, minmax(max(300px, calc((100% - 3rem) / 3)), 1fr));
}

@media (max-width: 575.98px) {
    .course-grid { grid-template-columns: 1fr; }
}

.course-card {
    height: 100%;
    padding: 1.9rem;
    position: relative;
    overflow: hidden;
    transition: transform var(--t), box-shadow var(--t);
}

.course-card::before {
    content: "";
    position: absolute;
    top: 0; bottom: 0; left: 0;
    width: 5px;
    background: linear-gradient(180deg, var(--yellow), var(--accent));
}

.course-card:hover { transform: translateY(-4px); box-shadow: var(--sh); }
.course-card h5 { font-weight: 700; margin-bottom: .5rem; }
.course-card p { color: var(--ink-soft); font-size: .94rem; }

.course-meta { list-style: none; padding: 0; margin: 1.2rem 0; font-size: .89rem; }

.course-meta li {
    display: flex; justify-content: space-between;
    padding: .5rem 0;
    border-bottom: 1px solid var(--line-soft);
}

.course-meta span { color: var(--ink-soft); }

/* ---------------------------------------------------------------- Video detail */

.back-link {
    display: inline-flex; align-items: center; gap: .35rem;
    color: var(--ink-soft); font-size: .9rem; font-weight: 500;
}

.back-link:hover { color: var(--brand); }

.player-frame { border-radius: var(--r-lg); overflow: hidden; background: #000; box-shadow: var(--sh-lg); }
.player-frame iframe { border: 0; }

.player-info { padding-top: 1.8rem; }
.player-info h1 { font-size: var(--t-h3); font-weight: 800; margin-bottom: .7rem; }
.player-desc { color: var(--ink-soft); margin: 1.2rem 0; white-space: pre-line; }

.side-heading { font-weight: 700; margin-bottom: 1.1rem; font-size: 1.05rem; }

.related-list { display: flex; flex-direction: column; gap: .7rem; }

.related-item {
    display: flex; gap: .85rem; align-items: center;
    padding: .6rem;
    color: var(--ink);
    transition: var(--t);
}

.related-item:hover { border-color: rgba(249, 194, 26, .6); box-shadow: var(--sh-sm); transform: translateX(3px); }
.related-item img { width: 100px; height: 58px; object-fit: cover; border-radius: var(--r-xs); }
.related-item strong { display: block; font-size: .9rem; line-height: 1.35; font-weight: 600; }
.related-item small { color: var(--ink-soft); }

/* ---------------------------------------------------------------- Forms */

.form-control, .form-select {
    border-radius: var(--r-sm);
    border: 1.5px solid var(--line);
    padding: .68rem .95rem;
    font-size: .95rem;
    transition: border-color var(--t), box-shadow var(--t);
}

.form-control:focus, .form-select:focus {
    border-color: var(--brand);
    box-shadow: 0 0 0 4px rgba(15, 81, 50, .1);
}

.form-label { font-weight: 600; font-size: .88rem; color: var(--ink); margin-bottom: .35rem; }
.form-text { color: var(--ink-soft); font-size: .82rem; }
.req { color: var(--accent); }

.filter-bar { padding: 1.15rem; background: var(--bg-alt); }
.card-form { padding: 1.4rem; }
.contact-box { padding: 1.4rem; background: var(--cream); border-color: rgba(249, 194, 26, .3); }
.contact-box h5 { font-weight: 700; margin-bottom: .8rem; }

/* Each contact detail is a row you can tap: call, chat, mail, navigate. */
.contact-line {
    display: grid;
    grid-template-columns: 42px 1fr;   /* fixed icon column keeps every row lined up */
    align-items: center;
    column-gap: .9rem;
    padding: .8rem 0;
    border-bottom: 1px solid rgba(15, 81, 50, .1);
    color: var(--ink);
    font-weight: 600;
    transition: color var(--t);
}

.contact-line:last-of-type { border-bottom: none; }
.contact-line:hover { color: var(--brand); }
.contact-line:hover .contact-ico { border-color: rgba(15, 81, 50, .35); box-shadow: var(--sh-sm); }

/* The text column only. The icon span keeps its own layout, which is why this
   deliberately does not match .contact-ico - a plain "span" rule outranks it
   and would knock the icon out of the middle of its circle. */
.contact-line > span:not(.contact-ico) { display: block; min-width: 0; overflow-wrap: anywhere; }

.contact-line small {
    display: block;
    color: var(--ink-soft);
    font-weight: 600;
    font-size: .7rem;
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: .08em;
}

.contact-line .contact-ico {
    width: 42px; height: 42px;
    border-radius: 50%;
    background: #fff;
    border: 1px solid rgba(15, 81, 50, .14);
    display: flex; align-items: center; justify-content: center;
    box-shadow: var(--sh-xs);
    transition: var(--t);
}

.contact-line .contact-ico svg { width: 19px; height: 19px; fill: var(--brand); display: block; }
.contact-line .contact-ico.ico-whatsapp svg { fill: #25D366; }

/* The icon row is a section of its own, not a stray line under the details. */
.contact-social {
    margin-top: 1.4rem;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(15, 81, 50, .12);
}

.social-label {
    display: block;
    margin-bottom: .7rem;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--ink-soft);
}

.footer-social .social-label { color: rgba(255, 255, 255, .5); }

/* ------------------------------------------------------ Social icon buttons

   This row appears twice: on the dark footer and on the cream contact card.
   Both looks are driven by custom properties rather than by extra selectors.
   That matters - the earlier version styled the contact card with
   ".contact-social .social-btn", which outranked the hover rules, so hovering
   left a white circle with a white icon in it and the icon disappeared.
   Variables inherit, so nothing has to out-shout anything else.            */

.social-row { display: flex; gap: .6rem; flex-wrap: wrap; }

.social-btn {
    width: 40px; height: 40px;
    border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--social-rest, rgba(255, 255, 255, .1));
    border: 1px solid var(--social-edge, rgba(255, 255, 255, .18));
    box-shadow: var(--social-shadow, none);
    transition: var(--t);
}

.social-btn svg {
    width: 18px; height: 18px;
    display: block;
    fill: var(--social-ink, #fff);
    transition: fill var(--t);
}

/* Hover fills the circle with the platform's own colour, icon always white. */
.social-btn:hover {
    background: var(--social-hover, var(--brand));
    border-color: transparent;
    transform: translateY(-3px);
    box-shadow: 0 8px 20px var(--social-glow, rgba(20, 32, 26, .25));
}

.social-btn:hover svg { fill: #fff; }

.social-whatsapp  { --social-hover: #25D366; --social-glow: rgba(37, 211, 102, .4); }
.social-youtube   { --social-hover: #FF0000; --social-glow: rgba(255, 0, 0, .35); }
.social-instagram { --social-hover: linear-gradient(45deg, #F58529, #DD2A7B 50%, #8134AF); --social-glow: rgba(221, 42, 123, .38); }
.social-facebook  { --social-hover: #1877F2; --social-glow: rgba(24, 119, 242, .35); }
.social-web       { --social-hover: var(--brand); --social-glow: rgba(15, 81, 50, .35); }

/* On the light contact card the resting state flips to white with green ink. */
.contact-social {
    --social-rest: #fff;
    --social-edge: rgba(15, 81, 50, .16);
    --social-ink: var(--brand);
    --social-shadow: var(--sh-xs);
}

/* ------------------------------------------------------ Floating WhatsApp */

.whatsapp-float {
    position: fixed;
    right: 1.15rem;
    bottom: 1.15rem;
    z-index: 300;
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding: .7rem .85rem;
    border-radius: var(--r-pill);
    background: #25D366;
    color: #fff;
    font-weight: 700;
    font-size: .92rem;
    box-shadow: 0 10px 30px rgba(37, 211, 102, .45);
    transition: var(--t);
}

.whatsapp-float svg { width: 26px; height: 26px; fill: #fff; flex: 0 0 auto; }
.whatsapp-float span { max-width: 0; overflow: hidden; white-space: nowrap; transition: max-width var(--t); }
.whatsapp-float:hover { color: #fff; transform: translateY(-3px); box-shadow: 0 14px 36px rgba(37, 211, 102, .55); }
.whatsapp-float:hover span { max-width: 9rem; }

.empty-state { text-align: center; padding: 2.4rem 1.5rem; border-style: dashed; margin-top: 1.2rem; }
.empty-state h5 { font-weight: 700; }
.empty-state p { color: var(--ink-soft); margin: 0; }

.alert { border: none; border-radius: var(--r-sm); font-size: .93rem; }
.alert-success { background: #E7F6EC; color: #14603A; }
.alert-danger { background: #FDECEA; color: #A32118; }
.alert-warning { background: var(--yellow-soft); color: #7A5B00; }
.alert-info { background: #E9F1FB; color: #1F4E85; }

.content-body { max-width: 46rem; font-size: 1.03rem; }

/* A course description written in the admin editor: modest headings, lists
   and links inside a card, sized to sit under the short description. */
.course-desc { color: var(--ink-2); font-size: .93rem; }
.course-desc h4 { font-size: 1rem; font-weight: 800; margin: .7rem 0 .3rem; }
.course-desc p { margin: 0 0 .5rem; }
.course-desc ul, .course-desc ol { margin: 0 0 .5rem; padding-left: 1.2rem; }
.course-desc li { margin-bottom: .2rem; }
.course-desc a { color: var(--brand); font-weight: 600; }
.content-body h4 { font-weight: 700; margin-top: 2rem; }
.content-body img { border-radius: var(--r); }

/* ---------------------------------------------------------------- CTA */

.cta {
    color: #fff;
    background:
        radial-gradient(700px 300px at 20% 0%, rgba(249, 194, 26, .22), transparent 60%),
        linear-gradient(135deg, var(--brand-dark), var(--brand-600));
}

.cta h2 { color: #fff; font-weight: 800; font-size: var(--t-h2); }
.cta p { color: rgba(255, 255, 255, .8); font-size: 1.05rem; }

.cta .btn-brand {
    background: var(--yellow);
    color: var(--brand-dark);
    border-color: var(--yellow);
    font-weight: 700;
    box-shadow: 0 10px 30px rgba(249, 194, 26, .3);
}

.cta .btn-brand:hover { background: #FFD24D; border-color: #FFD24D; color: var(--brand-dark); }

/* ---------------------------------------------------------------- Restaurants */

/* The map.

   Everything the map needs to say about itself is said on the map - a count, a
   way back to the whole picture, a word about the wheel. The grey caption bar
   that used to sit underneath said the same things while taking a strip of the
   page and making the map look like a picture of a map. */

.map-wrap {
    position: relative;
    overflow: hidden;
    padding: 0;
    border-radius: var(--r-lg);
    box-shadow: var(--sh);
}

#restaurantMap {
    height: 540px;
    width: 100%;
    background: var(--bg-alt);
}

/* A hairline inside the rounded corner. Without it a pale map and a white page
   run into each other and the card loses its edge. */
.map-wrap::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    border: 1px solid rgba(20, 32, 26, .09);
    pointer-events: none;
    z-index: 500;
}

.map-chip,
.map-reset {
    position: absolute;
    z-index: 600;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .85rem;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 4px 14px rgba(20, 32, 26, .14);
    font-size: .84rem;
    font-weight: 700;
    color: var(--ink);
    border: 1px solid rgba(20, 32, 26, .06);
}

.map-chip { top: .9rem; left: .9rem; }

.map-chip-dot {
    width: .55rem;
    height: .55rem;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.map-reset {
    top: .9rem;
    right: .9rem;
    cursor: pointer;
    color: var(--brand);
    transition: background var(--t), box-shadow var(--t), transform var(--t);
}

.map-reset:hover {
    background: #fff;
    box-shadow: 0 6px 18px rgba(20, 32, 26, .18);
    transform: translateY(-1px);
}

.map-reset svg { width: 15px; height: 15px; }

/* Says why the wheel is not zooming, and gets out of the way the moment it is.
   Transparent to the pointer except for the notice itself, so the map is not
   behind a sheet of glass. */
.map-veil {
    position: absolute;
    inset: 0;
    z-index: 550;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 1.1rem;
    pointer-events: none;
    transition: opacity var(--t);
}

.map-veil span {
    pointer-events: auto;
    cursor: pointer;
    padding: .45rem .9rem;
    border-radius: var(--r-pill);
    background: rgba(20, 32, 26, .78);
    color: #fff;
    font-size: .8rem;
    font-weight: 600;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.map-veil.is-gone { opacity: 0; pointer-events: none; }

/* No wheel to explain on a phone, and the notice would only be sitting on top
   of the map taking up a third of it. */
@media (hover: none) and (pointer: coarse) {
    .map-veil { display: none; }
}

/* Leaflet's own furniture, in the site's shapes rather than 2011's. */
.leaflet-container { font-family: 'Inter', sans-serif; }

.leaflet-control-zoom {
    border: none !important;
    border-radius: var(--r-sm) !important;
    overflow: hidden;
    box-shadow: 0 4px 14px rgba(20, 32, 26, .16) !important;
}

.leaflet-control-zoom a {
    width: 34px;
    height: 34px;
    line-height: 34px;
    color: var(--brand);
    background: rgba(255, 255, 255, .94);
    border-bottom: 1px solid var(--line-soft);
    font-size: 1.15rem;
    font-weight: 700;
}

.leaflet-control-zoom a:hover { background: #fff; color: var(--accent-dark); }
.leaflet-control-zoom a:last-child { border-bottom: none; }

/* The map credit, folded away.

   OpenStreetMap and CARTO give the tiles away on the condition they are
   credited, so the line cannot simply be deleted - but it does not have to sit
   across the corner of the map either. It becomes a small "i" and opens on
   hover, or on a tap on a phone. */
.leaflet-control-attribution {
    position: relative;

    /* An explicit width, not just a max: the control is floated, so with the
       text shoved off to the left by the indent it would shrink to fit nothing
       and the "i" would have no box to sit in. */
    width: 22px;
    max-width: 22px;
    height: 22px;
    margin: 6px !important;
    padding: 0 !important;
    overflow: hidden;
    white-space: nowrap;
    text-indent: -999px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .88) !important;
    box-shadow: 0 1px 4px rgba(20, 32, 26, .16);
    font-size: .68rem !important;
    line-height: 22px !important;
    color: var(--ink-soft) !important;
    cursor: pointer;
    transition: max-width 240ms var(--ease), border-radius 240ms var(--ease);
}

.leaflet-control-attribution::before {
    content: 'i';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-indent: 0;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    font-size: .72rem;
    color: var(--ink-soft);
}

.leaflet-control-attribution:hover,
.leaflet-control-attribution.is-open {
    width: auto;
    max-width: 320px;
    padding: 0 .6rem !important;
    text-indent: 0;
    border-radius: var(--r-pill);
    cursor: default;
}

.leaflet-control-attribution:hover::before,
.leaflet-control-attribution.is-open::before { content: none; }

.leaflet-control-attribution a { color: var(--brand) !important; }

/* ---- the tiles, taken down a little ----

   The map used to draw Carto's Voyager tiles, which say the same things as
   OpenStreetMap but say them quietly, so a pin was the loudest thing on the
   map. Carto now want an API key and print "API KEY REQUIRED" across every
   tile without one, so the map is back on OpenStreetMap's own tiles - which
   are free and need nothing, but are drawn for reading a map rather than for
   sitting behind something.

   So the quiet is done here instead. Only the tile pane is touched: pins,
   popups, the zoom buttons and the credit each sit in a pane of their own and
   keep their full colour. */
.leaflet-tile-pane {
    filter: saturate(.82) brightness(1.03);
}

/* ---- the map is one layer, not eleven ----

   Leaflet gives its own insides z-indexes of their own, up to 1000: the
   controls are 800, the corners they sit in are 1000, the pins are 600, a
   popup is 700. And .leaflet-container has no z-index at all, so it never
   becomes a layer of its own and none of that is contained - every one of
   those numbers competes with the rest of the page.

   The top menu is below all of them, so scrolling any page with a map on it
   slid the zoom buttons, the pins and the credit straight over it.

   A z-index of 0 on something already positioned is what makes it a stacking
   context: it folds all of Leaflet's layers into one, sitting exactly where
   the map sits and no higher. The chip, the reset button and the notice about
   the scroll wheel are siblings of the map rather than children of it, so
   they still sit over the top of it as they did. */
.leaflet-container {
    position: relative;
    z-index: 0;
}

/* The zoom buttons on a touch screen.

   Leaflet's own .leaflet-touch rule pins them at 30px and outranks a plain
   .leaflet-control-zoom a, so the site's styling never reached them. 30px is
   the same miss-waiting-to-happen the calculator's plus and minus were: on
   glass a control wants 40. */
@media (pointer: coarse) {
    .leaflet-touch .leaflet-control-zoom a,
    .leaflet-control-zoom a {
        width: 40px;
        height: 40px;
        line-height: 40px;
        font-size: 1.25rem;
    }
}

/* ---- the pins ----

   Drawn, not loaded: see pinIcon() on the kitchens page for why. */

.pin-icon { background: none; border: none; }

.pin-mark {
    display: block;
    width: 32px;
    height: 42px;
    filter: drop-shadow(0 3px 5px rgba(20, 32, 26, .3));
    transform-origin: 50% 100%;
    transition: transform 180ms var(--ease), filter 180ms var(--ease);
}

/* Grows from the point it is standing on, so the pin gets bigger without
   wandering off the address it marks. */
.pin-icon:hover .pin-mark {
    transform: scale(1.18);
    filter: drop-shadow(0 5px 9px rgba(20, 32, 26, .38));
}

.pin-icon svg { width: 100%; height: 100%; display: block; }

/* ---- the popup ---- */

.leaflet-popup-content-wrapper {
    border-radius: var(--r) !important;
    box-shadow: var(--sh-lg) !important;
    padding: 0 !important;
    overflow: hidden;
    border: 1px solid var(--line);
}

.leaflet-popup-content {
    margin: 0 !important;
    width: auto !important;
    font-family: 'Inter', sans-serif;
}

.leaflet-popup-tip { box-shadow: none; border: 1px solid var(--line); }

.leaflet-popup-close-button {
    width: 26px !important;
    height: 26px !important;
    top: 6px !important;
    right: 6px !important;
    border-radius: 50%;
    background: rgba(255, 255, 255, .9) !important;
    color: var(--ink-2) !important;
    font-size: 1rem !important;
    line-height: 24px !important;
    box-shadow: 0 1px 4px rgba(20, 32, 26, .18);
}

.pin-popup { min-width: 210px; font-size: .88rem; }

.pin-photo { height: 118px; background: var(--bg-alt); }
.pin-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pin-text { padding: .75rem .9rem .85rem; }
.pin-text strong { display: block; font-size: .98rem; line-height: 1.3; color: var(--ink); }

.pin-flag {
    display: inline-block;
    margin-bottom: .3rem;
    padding: .1rem .5rem;
    border-radius: var(--r-pill);
    background: var(--accent-soft);
    color: var(--accent-dark);
    font-size: .68rem;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.pin-cuisine { color: var(--accent-dark); font-weight: 700; font-size: .78rem; margin-top: .15rem; }

/* A cloud kitchen: takeaway and delivery, nowhere to sit. Green rather than
   the cuisine's yellow, so it reads as a different kind of fact - what you
   can do there, not what they cook - and the same mark on the card, the
   kitchen page and the pin, so it is learned once. */
.badge-takeaway {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    background: var(--brand-soft, #EAF2EC);
    color: var(--brand-dark, #0A3B24);
    border: 1px solid rgba(15, 81, 50, .18);
    border-radius: var(--r-pill);
    padding: .2rem .7rem;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .01em;

    /* Allowed to wrap. With the Tamil beside it the mark is wider than a
       phone's meta row, and a pill that will not break pushes the city off
       the edge of the screen. */
    flex-wrap: wrap;
    line-height: 1.35;
}

.badge-takeaway small { font-size: .7rem; font-weight: 600; opacity: .8; }

/* ---- the help line ----

   "Stuck? WhatsApp us." Quiet on purpose: it sits under a form as a way out,
   not a call to action, and the green of WhatsApp does the pointing. */
.help-note {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    margin-top: 1rem;
    padding: .7rem .9rem;
    border: 1px solid rgba(37, 211, 102, .35);
    border-radius: var(--r-sm);
    background: #F0FBF4;
    font-size: .86rem;
    line-height: 1.45;
    color: var(--ink-2);
}

.help-note .help-note-icon { flex-shrink: 0; color: #1FA855; margin-top: .1rem; display: inline-flex; }
.help-note a { color: #14603A; font-weight: 700; white-space: nowrap; }
.help-note a:hover { color: var(--brand-dark); }

/* Inside a payment window it is the last thing before the buttons, and the
   window already has its own frame. */
.help-note.is-plain { border: 0; background: none; padding: 0; margin-top: .6rem; }

/* ---- ordering online ----

   One button per place a kitchen takes orders, in that app's own colour so
   it is recognised before it is read. The same buttons on the kitchen page,
   the card in the list and the map popup, smaller in the popup. */
.order-row {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: .2rem 0 1rem;
}

.order-btn {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 40px;
    padding: .45rem .95rem;
    border-radius: var(--r-pill);
    font-size: .86rem;
    font-weight: 800;
    letter-spacing: .01em;
    color: #fff !important;
    text-decoration: none !important;
    box-shadow: var(--sh-xs);
    transition: transform var(--t), box-shadow var(--t), filter var(--t);
}

.order-btn:hover { transform: translateY(-1px); box-shadow: var(--sh-sm); filter: brightness(1.05); }

.order-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .22);
    font-size: .8rem;
    font-weight: 900;
    line-height: 1;
}

/* The colour is each app's own and comes with it from Settings, inline on
   the button. This is only the fallback for an app saved without one. */
.order-btn { background: var(--brand); }

/* In the popup: smaller, and only the app's name - the popup is 280px wide
   and "Order on Swiggy" three times over would be three lines. */
.pin-order { display: flex; flex-wrap: wrap; gap: .35rem; margin: .5rem 0 .1rem; }
.pin-order .order-btn { min-height: 30px; padding: .25rem .65rem; font-size: .76rem; gap: .3rem; }
.pin-order .order-mark { width: 18px; height: 18px; font-size: .68rem; }

/* On the list card the row sits above the phone and WhatsApp chips. */
.restaurant-card .order-row { margin: .6rem 0 .4rem; }
.restaurant-card .order-btn { min-height: 34px; padding: .32rem .8rem; font-size: .8rem; }

.pin-takeaway { color: var(--brand-dark, #0A3B24); font-weight: 700; font-size: .76rem; margin-top: .2rem; }
.pin-address { color: var(--ink-soft); margin: .35rem 0 0; line-height: 1.4; }

.pin-actions { display: flex; gap: .4rem; margin-top: .7rem; }

.pin-btn {
    flex: 1;
    text-align: center;
    padding: .35rem .5rem;
    border-radius: var(--r-pill);
    border: 1px solid var(--brand);
    color: var(--brand) !important;
    font-weight: 700;
    font-size: .8rem;
    text-decoration: none !important;
    transition: background var(--t), color var(--t);
}

.pin-btn:hover { background: var(--brand-soft); }

.pin-btn-go { background: var(--brand); color: #fff !important; }
.pin-btn-go:hover { background: var(--brand-dark); color: #fff !important; }

/* A map worth this much height on a laptop is most of a phone screen. */
@media (max-width: 767px) {
    #restaurantMap { height: 380px; }
    .map-chip, .map-reset { padding: .4rem .7rem; font-size: .78rem; }
    .map-chip { top: .6rem; left: .6rem; }
    .map-reset { top: .6rem; right: .6rem; }
}

.restaurant-hero { width: 100%; border-radius: var(--r-lg); margin-bottom: 1.4rem; object-fit: contain; background: var(--bg-alt); max-height: 380px; box-shadow: var(--sh); }
.restaurant-title { font-size: var(--t-h2); font-weight: 800; }
.restaurant-body-text { color: var(--ink-soft); white-space: pre-line; }
.lead-text { font-size: 1.08rem; color: var(--ink-2); }

.thumb-strip { display: flex; gap: .55rem; margin: -.4rem 0 1.5rem; flex-wrap: wrap; }

.thumb {
    width: 92px; height: 64px;
    padding: 0; overflow: hidden;
    border: 2px solid transparent;
    border-radius: var(--r-xs);
    background: none; cursor: pointer;
    box-shadow: var(--sh-xs);
    transition: var(--t);
}

.thumb img { width: 100%; height: 100%; object-fit: contain; background: var(--bg-alt); display: block; }
.thumb:hover { transform: translateY(-2px); box-shadow: var(--sh-sm); }
.thumb.active { border-color: var(--yellow); }

.owner-box { display: flex; align-items: center; gap: .9rem; padding: 1rem 1.2rem; margin: 1.3rem 0; background: var(--cream); border-color: rgba(249, 194, 26, .3); }

.owner-avatar {
    width: 46px; height: 46px; border-radius: 50%;
    background: linear-gradient(135deg, var(--brand), var(--brand-600));
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 700;
    flex-shrink: 0;
}

.owner-box small { display: block; color: var(--ink-soft); font-size: .83rem; }

.info-panel { overflow: hidden; position: sticky; top: 100px; padding: 0; box-shadow: var(--sh-sm); }
.detail-map { height: 250px; width: 100%; }
.info-body { padding: 1.4rem; }

.info-row { display: flex; flex-direction: column; padding: .5rem 0; border-bottom: 1px solid var(--line-soft); font-size: .93rem; }
.info-row:last-of-type { border-bottom: none; }

.info-label { color: var(--ink-soft); font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; font-weight: 700; margin-bottom: .15rem; }
.info-actions { margin-top: 1.2rem; }

.nearby-card { display: block; padding: 1rem 1.2rem; color: var(--ink); transition: var(--t); }
.nearby-card:hover { border-color: rgba(249, 194, 26, .6); box-shadow: var(--sh-sm); transform: translateY(-2px); }
.nearby-card strong { font-weight: 700; }
.nearby-card small { display: block; color: var(--ink-soft); font-size: .83rem; }

/* ---------------------------------------------------------------- Student portal */

.panel-lite { padding: 1.3rem; margin-bottom: 1rem; }
.panel-lite h5 { font-weight: 700; margin-bottom: .7rem; }

.status-card { padding: 1.1rem 1.3rem; margin-bottom: 1rem; border-left: 5px solid var(--line); }
.status-card h5 { font-weight: 800; margin: .2rem 0 .5rem; }
.status-card p { color: var(--ink-soft); margin: 0; font-size: .94rem; }

.status-label { font-size: .7rem; text-transform: uppercase; letter-spacing: .09em; font-weight: 700; color: var(--ink-soft); }

.status-pending { border-left-color: var(--yellow); background: var(--yellow-soft); }
.status-approved { border-left-color: var(--brand); background: var(--brand-soft); }
.status-rejected, .status-suspended { border-left-color: var(--red); background: #FDECEA; }

.status-line { display: inline-block; padding: .28rem .85rem; border-radius: var(--r-pill); font-size: .8rem; font-weight: 700; background: var(--line-soft); color: var(--ink-soft); }
.status-line.status-Approved { background: #DCFCE7; color: #14603A; }
.status-line.status-Pending { background: var(--yellow); color: var(--brand-dark); }
.status-line.status-Rejected { background: #FDECEA; color: #A32118; }

.shop-name { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 700; font-size: 1.1rem; margin-bottom: .5rem; }

.how-list { padding-left: 1.2rem; font-size: .93rem; color: var(--ink-soft); }
.how-list li { margin-bottom: .45rem; }

/* The old price, struck through, next to the offer badge. */
.fee-was { text-decoration: line-through; color: var(--ink-soft); }

.fee-off {
    display: inline-block;
    margin-left: .45rem;
    padding: .12rem .55rem;
    border-radius: var(--r-pill);
    background: var(--yellow);
    color: var(--brand-dark);
    font-size: .74rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .04em;
}

.pay-row { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 1rem; }

/* Paying on the page: the one big button. */
.pay-online {
    padding: 1rem;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: #fff;
    margin-bottom: 1rem;
}

.pay-online .btn-lg { font-size: 1.02rem; padding: .8rem 1rem; }


.qr-box { display: inline-block; max-width: 100%; padding: 1.1rem; text-align: center; }
.qr-box canvas { max-width: 100%; height: auto; }
.qr-box small { display: block; margin-top: .5rem; color: var(--ink-soft); }

.map-pick { overflow: hidden; padding: 0; }
#pickMap { height: 260px; width: 100%; }
.map-pick small { display: block; padding: .6rem 1rem; background: var(--bg-alt); color: var(--ink-soft); font-size: .83rem; }

.photo-slot { padding: .7rem; }

.photo-preview {
    aspect-ratio: 4/3;
    border-radius: var(--r-sm);
    background: var(--bg-alt);
    border: 1.5px dashed var(--line);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden; cursor: pointer;
    transition: var(--t);
}

.photo-preview:hover { border-color: var(--accent); background: var(--accent-soft); }
.photo-preview img { width: 100%; height: 100%; object-fit: contain; }
.photo-empty { color: var(--ink-soft); font-size: .88rem; font-weight: 600; }
.photo-actions { display: flex; gap: .4rem; margin-top: .6rem; flex-wrap: wrap; }
.photo-actions .btn { flex: 1 1 auto; }

/* Rotate / crop, on a photo that is already uploaded. Hidden while the slot is
   empty - there is nothing to turn. */
.photo-edit.is-hidden { display: none; }

/* Four controls under a 108px tile do not fit on one line, and squeezing them
   until they do makes each one too small for a thumb. */
.page-tile .page-tools { flex-wrap: wrap; }
.photo-note { margin-top: .4rem; font-size: .78rem; color: var(--ink-soft); min-height: 1rem; }
.photo-note.ok { color: #14603A; }
.photo-note.warn { color: #A32118; }

/* What the map found, when it disagrees with what was typed. A suggestion, not
   a correction - the name in the box is somebody's own answer and replacing it
   silently is how "Karur" becomes "Karur District" overnight. */
.pin-found { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .8rem; }

.pin-offer {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .3rem .6rem;
    border: 1px dashed var(--line);
    border-radius: var(--r-pill);
    background: var(--bg-alt);
    font-size: .82rem;
    color: var(--ink-soft);
}

.pin-offer button {
    border: 0;
    background: transparent;
    padding: 0;
    font: inherit;
    font-weight: 800;
    color: var(--brand);
    text-decoration: underline;
    cursor: pointer;
}

.pin-offer button:hover { color: var(--accent-dark, var(--brand)); }

/* The calculator holds more than one recipe. One tap between them, and the one
   you are on is obvious - otherwise the amounts on screen belong to a recipe
   you have to guess at. */
.recipe-switch { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1rem; }

.recipe-tab {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .42rem .95rem;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
    color: var(--ink-soft);
    font: inherit;
    font-size: .86rem;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    transition: var(--t);
}

.recipe-tab:hover { border-color: var(--brand); color: var(--brand); }

.recipe-tab.is-on {
    border-color: var(--brand);
    background: var(--brand);
    color: #fff;
}

.recipe-count {
    font-size: .72rem; font-weight: 800;
    padding: 0 .4rem;
    border-radius: var(--r-pill);
    background: rgba(0, 0, 0, .12);
}

.recipe-tab.is-on .recipe-count { background: rgba(255, 255, 255, .25); }

.section-label { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 700; font-size: .8rem; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-soft); margin-bottom: .7rem; }

/* ---------------------------------------------------------------- Menu and offers

   Used twice: on the kitchen page, where anyone can read it, and on the
   student's own screen, where the same rows grow buttons. Keeping one set of
   classes means a dish looks the same in both places, which is the point - a
   student editing their menu should be looking at their menu.
   ---------------------------------------------------------------- */

.menu-group { margin-bottom: 1.8rem; }
.menu-group:last-child { margin-bottom: 0; }

.menu-group-name {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-weight: 800; font-size: 1rem;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--brand);
    padding-bottom: .5rem; margin-bottom: .9rem;
    border-bottom: 2px solid var(--line);
}

.dish {
    display: flex; gap: 1rem; align-items: flex-start;
    padding: .85rem 0;
    border-bottom: 1px solid var(--line-soft);
}

.dish:last-child { border-bottom: 0; }

.dish-photo {
    flex: 0 0 76px; width: 76px; height: 76px;
    border-radius: var(--r-sm); overflow: hidden;
    background: var(--bg-alt);
}

.dish-photo img { width: 100%; height: 100%; object-fit: contain; display: block; }

.dish-main { flex: 1 1 auto; min-width: 0; }

.dish-name {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-weight: 700; font-size: 1rem; margin: 0 0 .2rem;
    display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
}

.dish-desc { color: var(--ink-soft); font-size: .88rem; margin: 0; }

.dish-side { flex: 0 0 auto; text-align: right; }
.dish-price { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 800; font-size: 1rem; white-space: nowrap; }

/* The green and red squares an Indian menu uses. Not decoration - people scan
   for them, and a wrong one is a real problem for somebody. */
.veg-mark {
    display: inline-block; width: 13px; height: 13px;
    border: 2px solid #14803C; border-radius: 3px;
    position: relative; flex: 0 0 auto;
}

.veg-mark::after {
    content: ''; position: absolute;
    top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 6px; height: 6px; border-radius: 50%;
    background: #14803C;
}

.veg-mark.non-veg { border-color: #A32118; }
.veg-mark.non-veg::after { background: #A32118; }

.dish.is-out { opacity: .55; }

.sold-out {
    display: inline-block; padding: .1rem .5rem;
    border-radius: var(--r-pill);
    background: #FDECEA; color: #A32118;
    font-size: .68rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .05em;
}

.dish-order { margin-top: .5rem; }
/* ---- made to order ----

   A dish that is cooked because somebody asked, not one sitting on the
   counter. The tag sits beside the name rather than at the bottom of the card:
   somebody scanning a menu for what they can eat in ten minutes needs to know
   before they have read the description. */
.pre-tag {
    display: inline-block;
    padding: .1rem .5rem;
    border-radius: var(--r-pill);
    background: var(--yellow-soft);
    color: #8A5B00;
    font-size: .68rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .05em;
    vertical-align: middle;
}

.dish-pre {
    margin: .25rem 0 0;
    font-size: .8rem;
    font-weight: 600;
    color: #8A5B00;
}

/* The box on the editing form, folded shut until the dish is marked made to
   order - the notice and the smallest order say nothing about a dish that is
   simply on the counter. */
.preorder-box {
    padding: .75rem .9rem;
    border: 1px dashed var(--line);
    border-radius: var(--r-sm);
    background: var(--bg-alt);
}

.preorder-more { margin-top: .7rem; }


/* ---- offers ---- */

.offer-strip { display: flex; gap: .9rem; flex-wrap: wrap; margin-bottom: 1.6rem; }

.offer-card {
    flex: 1 1 240px;
    padding: 1rem 1.2rem;
    border-radius: var(--r);
    background: var(--yellow-soft);
    border: 1.5px dashed var(--yellow);
}

.offer-title { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 800; margin: 0 0 .25rem; }
.offer-details { color: var(--ink-2); font-size: .89rem; margin: 0; }

.offer-code {
    display: inline-block; margin-top: .5rem;
    padding: .2rem .7rem; border-radius: var(--r-xs);
    background: #fff; border: 1px dashed var(--ink-soft);
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-weight: 700; font-size: .85rem; letter-spacing: .05em;
}

.offer-when { display: block; margin-top: .45rem; color: var(--ink-soft); font-size: .78rem; }

/* ---- open now ---- */

.open-state {
    display: inline-flex; align-items: center; gap: .45rem;
    padding: .3rem .85rem; border-radius: var(--r-pill);
    font-size: .82rem; font-weight: 700;
    background: var(--line-soft); color: var(--ink-soft);
}

.open-state .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.open-state.is-open { background: #DCFCE7; color: #14603A; }
.open-state.is-shut { background: #FDECEA; color: #A32118; }

/* Not open yet. Neither the green of open nor the red of shut - a kitchen
   that opens next month is not "closed", it is not here yet - so it gets the
   amber the site uses for "waiting". */
.open-state.is-soon { background: var(--yellow-soft); color: #7A5B00; }
.open-state small { font-weight: 600; opacity: .85; }

/* On a card in the list, rather than on the kitchen's own page. Smaller, and
   with today's hours under it for anyone deciding whether to go now or later. */
.restaurant-hours {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .4rem .6rem;
    margin: -.15rem 0 .5rem;
}

.restaurant-hours .open-state { padding: .18rem .6rem; font-size: .76rem; }
.restaurant-hours .open-state .dot { width: 7px; height: 7px; }
.restaurant-hours .open-state small { font-size: .72rem; }

.hours-today { font-size: .76rem; color: var(--ink-soft); }

/* The week on a kitchen's own page. Seven rows beats one long sentence, and it
   is the only shape that can show a split day without becoming a puzzle. */
.info-row-week { display: block; }

.week-hours { width: 100%; margin-top: .35rem; font-size: .85rem; }

.week-hours th {
    width: 3.2rem;
    padding: .2rem .5rem .2rem 0;
    font-weight: 600;
    color: var(--ink-soft);
    text-align: left;
    vertical-align: top;
}

.week-hours td { padding: .2rem 0; color: var(--ink-2); }

/* Today is the row somebody is looking for, so it is the one that stands out. */
.week-hours tr.is-today th,
.week-hours tr.is-today td { font-weight: 800; color: var(--brand); }

.week-hours tr.is-shut td { color: var(--ink-soft); }

/* The same thing inside a map popup, where the space is tighter. */
.pin-open {
    display: inline-block;
    margin-top: .25rem;
    padding: .1rem .5rem;
    border-radius: var(--r-pill);
    font-size: .72rem;
    font-weight: 700;
}

.pin-open span { font-weight: 600; opacity: .85; }
.pin-open.is-open { background: #DCFCE7; color: #14603A; }
.pin-open.is-soon { background: var(--yellow-soft); color: #7A5B00; }
.pin-open.is-shut { background: #FDECEA; color: #A32118; }

/* ---- the student's own editing screen ---- */

.menu-editor .dish { align-items: center; }
.menu-editor .dish-actions { display: flex; gap: .35rem; flex-wrap: wrap; justify-content: flex-end; margin-top: .4rem; }

.menu-form { padding: 1.2rem; border-radius: var(--r); background: var(--bg-alt); border: 1px solid var(--line); margin-bottom: 1.4rem; }
.menu-form h6 { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 800; margin-bottom: .9rem; }

.menu-empty { text-align: center; padding: 1.5rem 1rem; color: var(--ink-soft); }

/* ---------------------------------------------------------------- The menu card, as a book

   A printed menu is a physical thing with pages, and a column of photographs
   down a web page is not how anybody has ever read one. The leaf pivots on its
   left edge - the edge a page is actually bound on - and the page underneath is
   already there.
   ---------------------------------------------------------------- */

.book { position: relative; margin-bottom: 1.2rem; outline: none; }

.book-stage {
    position: relative;
    aspect-ratio: 3 / 4;
    max-width: 460px;
    margin: 0 auto;
    perspective: 1800px;
    cursor: zoom-in;
    touch-action: pan-y;
}

.book-leaf {
    position: absolute; inset: 0;
    transform-origin: left center;
    transform-style: preserve-3d;
    transition: transform .62s cubic-bezier(.44, .09, .2, 1), visibility 0s;
    border-radius: var(--r-sm);
}

/* A finished page is hidden rather than left lying to the left of the book -
   there is no left hand page to lay it on, this is one page wide. The delay is
   what lets the turn be seen before it goes. */
.book-leaf.turned {
    transform: rotateY(-180deg);
    visibility: hidden;
    transition: transform .62s cubic-bezier(.44, .09, .2, 1), visibility 0s .62s;
}

.book-face {
    position: absolute; inset: 0;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    border-radius: var(--r-sm);
    overflow: hidden;
    background: var(--bg-alt);
    box-shadow: 0 6px 24px rgba(20, 32, 26, .16);
}

.book-face img { width: 100%; height: 100%; object-fit: contain; background: #fff; display: block; }

/* The back of the page. Paper, and the shadow of the spine down the edge it
   turns on, which is the thing that makes it read as paper rather than a card. */
.book-back {
    transform: rotateY(180deg);
    background:
        linear-gradient(270deg, rgba(20, 32, 26, .10), rgba(20, 32, 26, 0) 14%),
        var(--cream);
}

.book-bar {
    display: flex; align-items: center; justify-content: center; gap: .5rem;
    margin-top: .9rem;
}

.book-bar.is-single .book-arrow { display: none; }

.book-arrow, .book-zoom {
    width: 38px; height: 38px;
    border-radius: 50%;
    border: 1.5px solid var(--line);
    background: #fff;
    color: var(--brand);
    font-size: 1.2rem; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: var(--t);
}

.book-arrow:hover:not(:disabled), .book-zoom:hover { border-color: var(--brand); background: var(--brand-soft); }
.book-arrow:disabled { opacity: .35; }

.book-zoom { font-size: .95rem; }

.book-count { min-width: 8.5rem; text-align: center; color: var(--ink-soft); font-size: .85rem; font-weight: 600; }

/* ---- full screen ---- */

body.book-open { overflow: hidden; }

.book-full {
    position: fixed; inset: 0; z-index: 2000;
    background: rgba(10, 18, 14, .93);
    display: flex; align-items: center; justify-content: center;
    padding: 3.5rem 1rem 4rem;
    cursor: zoom-out;
}

.book-full img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--r-sm); background: #fff; }

.book-full-close {
    position: absolute; top: 1rem; right: 1rem;
    width: 42px; height: 42px; border-radius: 50%;
    border: 0; background: rgba(255, 255, 255, .16); color: #fff;
    font-size: 1.6rem; line-height: 1;
}

.book-full-arrow {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 46px; height: 46px; border-radius: 50%;
    border: 0; background: rgba(255, 255, 255, .16); color: #fff;
    font-size: 1.6rem; line-height: 1;
    cursor: pointer;
}

.book-full-prev { left: 1rem; }
.book-full-next { right: 1rem; }

.book-full-close:hover, .book-full-arrow:hover { background: rgba(255, 255, 255, .3); }

.book-full-count {
    position: absolute; bottom: 1.2rem; left: 50%; transform: translateX(-50%);
    color: rgba(255, 255, 255, .8); font-size: .85rem; font-weight: 600;
}

/* ---- the pages, while they are being managed ---- */

.page-strip { display: flex; gap: .7rem; flex-wrap: wrap; }

.page-tile { width: 108px; }

.page-shot {
    width: 108px; height: 140px;
    object-fit: contain;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--bg-alt);
    display: block;
    cursor: zoom-in;
}

.page-tile .page-no { display: block; text-align: center; font-size: .74rem; color: var(--ink-soft); font-weight: 700; margin-top: .3rem; }
.page-tile .page-tools { display: flex; gap: .2rem; justify-content: center; margin-top: .25rem; }

/* Three buttons under a 108px tile. At the default small size they overflow and
   spill under the tile beside them, which reads as one tile having six
   buttons - so they are cut down to what an icon actually needs. */
.page-tile .page-tools .btn {
    flex: 0 0 auto;
    min-width: 0;
    padding: .12rem .35rem;
    font-size: .72rem;
    line-height: 1.2;
}

.page-add {
    width: 108px; height: 140px;
    border-radius: var(--r-sm);
    border: 1.5px dashed var(--line);
    background: var(--bg-alt);
    color: var(--ink-soft);
    font-size: .82rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center; text-align: center;
    padding: .5rem;
    transition: var(--t);
}

.page-add:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-dark); }

/* ---------------------------------------------------------------- Videos

   Two sets: the tiles a kitchen arranges its own videos with, and the grid the
   public sees. The editor tiles are shared with the admin panel, which is why
   they live in both stylesheets - the two screens are meant to look like the
   place they are in, not like each other. */

.vid-strip { display: flex; gap: .7rem; flex-wrap: wrap; margin-bottom: 1rem; }

.vid-tile { width: 150px; }

.vid-art {
    position: relative;
    display: block;
    width: 150px;
    height: 90px;
    border-radius: var(--r-sm);
    overflow: hidden;
    border: 1px solid var(--line);
    background: var(--bg-alt);
}

.vid-shot { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Instagram gives no thumbnail away without its script, so the tile is a mark
   rather than an empty grey box pretending a picture failed to load. */
.vid-shot-ig {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    color: #fff;
    background: linear-gradient(135deg, #F9C21A 0%, #EF6820 45%, #C13584 100%);
}

.vid-badge {
    position: absolute;
    left: .35rem;
    bottom: .35rem;
    padding: .05rem .4rem;
    border-radius: var(--r-pill);
    background: rgba(20, 32, 26, .78);
    color: #fff;
    font-size: .62rem;
    font-weight: 800;
    letter-spacing: .03em;
}

.vid-name {
    font-size: .76rem;
    font-weight: 700;
    color: var(--ink-2);
    margin-top: .3rem;
    text-align: center;

    /* One line. A pasted title can be a whole sentence and would otherwise
       make one tile twice the height of the row it is in. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.vid-tools { display: flex; gap: .2rem; justify-content: center; margin-top: .25rem; }

.vid-tools .btn {
    flex: 0 0 auto;
    min-width: 0;
    padding: .12rem .35rem;
    font-size: .72rem;
    line-height: 1.2;
}

.vid-form { padding-top: .3rem; }
.vid-fields { display: flex; gap: .5rem; flex-wrap: wrap; align-items: flex-end; }
.vid-fields .vid-f-url { flex: 1 1 230px; min-width: 0; }
.vid-fields .vid-f-title { flex: 1 1 140px; min-width: 0; }
.vid-fields .vid-f-go { flex: 0 0 auto; min-width: 88px; }


.vid-hint { min-height: 1.1rem; margin-top: .35rem; font-size: .78rem; color: var(--ink-soft); }
.vid-hint.is-ok { color: #14603A; }
.vid-hint.is-bad { color: #A32118; }

/* ---- what the public sees ---- */

.vid-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 1rem;
}

.vid-card {
    border: 1px solid var(--line);
    border-radius: var(--r);
    overflow: hidden;
    background: #fff;
    box-shadow: var(--sh-xs);
}

/* The button and the played iframe are the same size, so pressing play does
   not make the page jump under the reader's thumb. */
.vid-card .vid-play,
.vid-card iframe {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: none;
    padding: 0;
    background: var(--bg-alt);
}

.vid-play {
    position: relative;
    cursor: pointer;
    overflow: hidden;
}

.vid-play img { width: 100%; height: 100%; object-fit: cover; display: block; }

.vid-play-mark {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: rgba(20, 32, 26, .72);
    color: #fff;
    font-size: 1.15rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: .2rem;
    transition: background var(--t), transform var(--t);
}

.vid-play:hover .vid-play-mark { background: var(--accent); transform: scale(1.08); }

/* Scoped to .vid-card so it outranks the shared .vid-card .vid-play rule
   above, which would otherwise win on specificity and leave the tile grey
   with white writing on it. */
.vid-card .vid-play-ig {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    background: linear-gradient(135deg, #F9C21A 0%, #EF6820 45%, #C13584 100%);
    color: #fff !important;
    text-decoration: none !important;
}

.vid-ig-mark {
    width: 52px; height: 52px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .22);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.15rem;
    padding-left: .2rem;
}

.vid-ig-word { font-size: .82rem; font-weight: 700; }

.vid-cap {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    padding: .6rem .8rem;
}

.vid-cap-name {
    font-weight: 700;
    font-size: .88rem;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vid-cap-src { margin-left: auto; font-size: .76rem; font-weight: 700; color: var(--brand); white-space: nowrap; }

/* ---------------------------------------------------------------- Footer */

.site-footer {
    background: var(--brand-dark);
    color: rgba(255, 255, 255, .72);
    padding: 2.6rem 0 1.2rem;
    position: relative;
}

.site-footer::before {
    content: "";
    position: absolute; top: 0; left: 0; right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--yellow), var(--accent) 55%, var(--lime));
}

.footer-logo { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; margin-bottom: 1rem; box-shadow: 0 0 0 3px rgba(249, 194, 26, .8); }
.footer-brand { color: #fff; font-weight: 800; }
.footer-text { color: rgba(255, 255, 255, .6); font-size: .93rem; max-width: 26rem; }

.footer-heading { color: var(--yellow); font-weight: 700; font-size: .78rem; text-transform: uppercase; letter-spacing: .09em; margin-bottom: 1rem; }

.footer-links { list-style: none; padding: 0; margin: 0; font-size: .92rem; }
.footer-links li { margin-bottom: .55rem; }
.footer-links a { color: rgba(255, 255, 255, .72); }

/* Contact rows in the footer carry a small icon so the channel is obvious
   before you read the value. */
.footer-links a { display: inline-flex; align-items: center; gap: .55rem; }

.li-ico {
    width: 16px; height: 16px;
    flex: 0 0 auto;
    fill: var(--yellow);
    opacity: .85;
    display: block;
    transition: var(--t);
}

.li-ico.ico-wa { fill: #25D366; opacity: 1; }
.footer-links a:hover .li-ico { opacity: 1; transform: scale(1.08); }

/* A long email or address has to be allowed to break, or it pushes the whole
   page sideways on a phone. */
.footer-links a span { min-width: 0; overflow-wrap: anywhere; }
.footer-links a:hover { color: var(--yellow); }

.footer-social {
    margin-top: 1.6rem;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(255, 255, 255, .1);
}

.footer-bottom {
    border-top: 1px solid rgba(255, 255, 255, .1);
    margin-top: 2.5rem; padding-top: 1.3rem;
    display: flex; justify-content: space-between; align-items: center;
    flex-wrap: wrap; gap: .75rem 1.5rem;
    font-size: .86rem; color: rgba(255, 255, 255, .55);
}

.footer-bottom a { color: rgba(255, 255, 255, .55); }
.footer-bottom a:hover { color: var(--yellow); }

/* Build credit. One line on a wide screen, centred and stacked on a phone.
   Everything sits on the same optical line: same font size, icons sized to
   the text, and one flex row so nothing drifts up or down. */
.footer-credit {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .4rem .55rem;
    line-height: 1.5;
}

.footer-credit a {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    color: rgba(255, 255, 255, .82);
    font-weight: 600;
    transition: var(--t);
}

.footer-credit svg { width: 13px; height: 13px; display: block; flex: 0 0 auto; }

.credit-name svg { fill: #25D366; }

.credit-sep { color: rgba(255, 255, 255, .35); }
.credit-site { color: rgba(255, 255, 255, .82); font-weight: 700; }
.footer-bottom .credit-site:hover { color: var(--yellow); text-decoration: underline; }

/* Scoped under .footer-bottom on purpose: the generic ".footer-bottom a:hover"
   rule above turns every footer link yellow, and it outranks a bare
   ".credit-name:hover". That is what left the chip yellow-on-yellow with the
   text invisible. */
.footer-bottom .credit-name:hover { color: #25D366; }

/* The number reads as a small chip so it does not crowd the name. */
.credit-phone {
    padding: .16rem .65rem;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: var(--r-pill);
}

.credit-phone svg { fill: var(--yellow); }

.footer-bottom .credit-phone:hover {
    color: var(--brand-dark);
    background: var(--yellow);
    border-color: var(--yellow);
}

.footer-bottom .credit-phone:hover svg { fill: var(--brand-dark); }

/* ---------------------------------------------------------------- Reveal on scroll
   Nothing is hidden until the script confirms it can reveal it again, so with
   JavaScript off the page is simply visible. */

body.reveal-on .reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 600ms var(--ease), transform 600ms var(--ease);
}

body.reveal-on .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
    body.reveal-on .reveal { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------- Responsive */

@media (max-width: 991px) {
    .whatsapp-float { right: .85rem; bottom: .85rem; padding: .7rem; }
    .whatsapp-float span { display: none; }
    .hero { padding: 2.4rem 0 2.2rem; }
    .hero-empty-logo { width: 132px; height: 132px; }
    .section { padding: 2.2rem 0; }
    .page-head { padding: 1.7rem 0 1.4rem; }
    .info-panel { position: static; }
    .hero-video { transform: none; }

    /* The open menu is a card of its own rather than links floating on the page. */
    .navbar-collapse {
        margin-top: .85rem;
        padding: .5rem;
        background: #fff;
        border: 1px solid var(--line);
        border-radius: var(--r);
        box-shadow: var(--sh);
    }

    .site-header .nav-link {
        display: block;
        padding: .72rem .9rem;
        border-radius: var(--r-sm);
        font-size: 1rem;
    }

    .site-header .navbar-nav .nav-item + .nav-item .nav-link {
        border-top: 1px solid var(--line-soft);
    }

    .site-header .btn-brand,
    .site-header .btn-outline-brand {
        display: block;
        width: 100%;
        text-align: center;
        margin: .55rem 0 .25rem;
    }

    /* Room for fingers, and for the floating WhatsApp button. */
    .site-footer { padding-bottom: 4.5rem; }

    .footer-bottom {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: .85rem;
    }

    .footer-credit { justify-content: center; }

    /* Footer links were only 15px tall - too small to hit with a thumb. */
    .footer-links li { margin-bottom: .15rem; }
    .footer-links a { padding: .42rem 0; }
    .back-link { padding: .35rem 0; }
    .credit-name { padding: .25rem 0; }
    .contact-line { padding: .85rem .2rem; }
}

@media (max-width: 575px) {
    .hero-actions .btn { width: 100%; }
    .social-btn { width: 46px; height: 46px; }
    .social-btn svg { width: 21px; height: 21px; }

    /* Two per line on a phone, still on one line each. */
    .stat-row {
        justify-content: space-between;
        gap: .5rem 1rem;
    }

    .stat { flex: 0 0 calc(50% - .5rem); }
    .stat .stat-value { font-size: 1.3rem; }
    .stat .stat-label { font-size: .78rem; white-space: normal; }
}

/* ------------------------------------------------------------- Help line */

/* "Any trouble?" on the sign up page. Two full width tap targets rather than
   a phone number in a sentence: somebody stuck halfway through registering
   should not have to select and copy anything. */
.help-line {
    margin-top: 1.1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
}

.help-title {
    display: block;
    font-weight: 700;
    color: var(--ink);
    margin-bottom: .55rem;
}

.help-btn {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .6rem .85rem;
    border-radius: var(--r-sm);
    border: 1.5px solid var(--line);
    background: #fff;
    font-weight: 600;
    font-size: .92rem;
    color: var(--ink-2);
    transition: var(--t);
}

.help-btn + .help-btn { margin-top: .45rem; }

.help-btn svg {
    width: 20px;
    height: 20px;
    flex: 0 0 20px;
    fill: currentColor;
}

/* Driven by a custom property so the hover state cannot end up with an
   invisible icon: the whole button inherits one colour. */
.help-whatsapp { --tone: #25D366; }

.help-btn svg { color: var(--tone); }

.help-btn:hover {
    background: var(--tone);
    border-color: var(--tone);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: var(--sh-sm);
}

.help-btn:hover svg { color: #fff; }

/* ---------------------------------------------------------- Opening hours */

/* The editor used on the admin kitchen form and on the student's own page.
   One row per line: the day, the two times, and a closed switch when the
   week is being set day by day. */
.hours-editor .hours-row {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .25rem 0;
    flex-wrap: wrap;
}

.hours-editor .hours-day {
    flex: 0 0 4.5rem;
    font-size: .88rem;
    font-weight: 600;
}

.hours-editor .hours-to {
    font-size: .82rem;
    opacity: .7;
}

.hours-editor input[type="time"] {
    flex: 0 1 8.5rem;
    min-width: 7rem;
}

.hours-editor .hours-closed {
    margin-left: .25rem;
}

/* A day that is shut has nothing to say, so it fades back. */
.hours-editor .hours-row.is-closed .hours-open,
.hours-editor .hours-row.is-closed .hours-close,
.hours-editor .hours-row.is-closed .hours-to {
    opacity: .45;
}

.hours-editor .hours-preview {
    margin-top: .4rem;
    font-weight: 600;
}
/* ---- periods within a day ----

   A day is a list now, not one pair of times, so the times stack in their own
   column beside the day name and the closed switch stays put beside them
   however many there are. */
.hours-editor .hours-shifts {
    flex: 1 1 16rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: .3rem;
}

.hours-editor .hours-shift {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.hours-editor .hours-drop {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    line-height: 1;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: #fff;
    color: var(--ink-soft);
    font-size: 1rem;
    cursor: pointer;
    transition: var(--t);
}

.hours-editor .hours-drop:hover:not(:disabled) { border-color: #D0342C; color: #D0342C; }

/* The only period of a day cannot go: a day with no times and no Closed tick
   would say nothing at all. */
.hours-editor .hours-drop:disabled { opacity: .3; cursor: default; }

.hours-editor .hours-add {
    align-self: flex-start;
    padding: .1rem .5rem;
    border: 1px dashed var(--line);
    border-radius: var(--r-pill, 999px);
    background: none;
    color: var(--brand);
    font-size: .76rem;
    font-weight: 700;
    cursor: pointer;
    transition: var(--t);
}

.hours-editor .hours-add:hover:not(:disabled) { border-color: var(--brand); background: var(--brand-soft, #EAF2EC); }
.hours-editor .hours-add:disabled { opacity: .35; cursor: default; }

.hours-editor .hours-shifts.is-off { opacity: .45; pointer-events: none; }

.hours-editor .hours-tip { margin-top: .2rem; opacity: .75; }


@media (max-width: 575.98px) {
    /* Two times plus a checkbox will not fit across a phone, so the day sits
       on its own line above them. */
    .hours-editor .hours-day { flex: 0 0 100%; }
    .hours-editor .hours-shifts { flex: 0 0 100%; }
    .hours-editor input[type="time"] { flex: 1 1 0; min-width: 0; }
    .hours-editor .hours-closed { flex: 0 0 100%; margin-left: 0; }
}

/* ------------------------------------------------------------- Date range */

/* One box for both ends of a range, with a way back to empty.
   Two date inputs side by side read as two separate questions, and people
   answered the first and left the second. */
.range-wrap { position: relative; }

.range-wrap .form-control { padding-right: 2.4rem; cursor: pointer; background-color: #fff; }

.range-clear {
    position: absolute;
    top: 50%;
    right: .5rem;
    transform: translateY(-50%);
    width: 1.6rem;
    height: 1.6rem;
    line-height: 1;
    font-size: 1.15rem;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--ink-soft);
    cursor: pointer;
    transition: var(--t);
}

.range-clear:hover { background: var(--line); color: var(--ink); }

/* The calendar itself, in the brand's colours rather than flatpickr's blue.

   Every selector below is deliberately prefixed with .flatpickr-calendar. The
   library's stylesheet is loaded per page, which means it arrives AFTER this
   file, so a bare .flatpickr-day rule would lose on source order. The extra
   class outranks it whichever way round the two files end up. */
.flatpickr-calendar { font-family: 'Inter', sans-serif; border-radius: var(--r-sm); }

.flatpickr-calendar .flatpickr-day.selected,
.flatpickr-calendar .flatpickr-day.startRange,
.flatpickr-calendar .flatpickr-day.endRange {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
}

.flatpickr-calendar .flatpickr-day.selected:hover,
.flatpickr-calendar .flatpickr-day.startRange:hover,
.flatpickr-calendar .flatpickr-day.endRange:hover {
    background: var(--brand-600);
    border-color: var(--brand-600);
    color: #fff;
}

/* The days between the two ends. The shadows fill the gaps between cells so
   the range reads as one continuous band. */
.flatpickr-calendar .flatpickr-day.inRange,
.flatpickr-calendar .flatpickr-day.inRange:hover {
    background: var(--brand-soft);
    border-color: var(--brand-soft);
    box-shadow: -5px 0 0 var(--brand-soft), 5px 0 0 var(--brand-soft);
    color: var(--ink);
}

.flatpickr-calendar .flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)) {
    box-shadow: -10px 0 0 var(--brand);
}

.flatpickr-calendar .flatpickr-day.today { border-color: var(--yellow); }

.flatpickr-calendar .flatpickr-day.today:hover {
    background: var(--yellow);
    border-color: var(--yellow);
    color: var(--ink);
}

.flatpickr-calendar .flatpickr-day:hover { background: var(--line-soft); }

.flatpickr-calendar .flatpickr-months .flatpickr-month { color: var(--ink); }
.flatpickr-calendar .flatpickr-current-month .flatpickr-monthDropdown-months { font-weight: 700; }

/* ============================================================================
   Recipe calculator
   ----------------------------------------------------------------------------
   The original of this screen came as a standalone page in its own dark red
   theme. Everything here is the site's own palette instead, so a student who
   walks in from the kitchens page does not feel handed to another website.

   The one thing kept from the original is the shape: a sticky bar you set the
   weight in, a summary of the six numbers you shout across a kitchen, then the
   full list.
   ============================================================================ */

.calc-bar {
    position: sticky;

    /* Below the header, not behind it.

       This used to be top: 0, the same as the header - and the header has the
       higher z-index, so scrolling the ingredient list slid the weight box,
       the plus and minus buttons and Save my amounts underneath it. They were
       still on the page and still taking taps, but the header was on top of
       them, so nothing happened when you pressed one. */
    top: calc(var(--header-h, 66px) + .4rem);
    z-index: 20;
    padding: 1.1rem 1.2rem;
    margin-bottom: 1.4rem;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--cream);
    box-shadow: var(--sh-sm);
}

.calc-inputs {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: .8rem;
    max-width: 560px;
    margin: 0 auto;
}

/* A recipe with no head count has only the weight box. Without this the
   panel would keep the 1fr of a three column grid and sit half width,
   pushed to the left of an empty bar. */
.calc-inputs.is-single {
    grid-template-columns: minmax(0, 300px);
    justify-content: center;
}

.calc-panel {
    padding: .7rem .6rem;
    text-align: center;
    border: 2px solid var(--line);
    border-radius: var(--r-sm);
    background: #fff;
    transition: border-color var(--t), box-shadow var(--t);
}

.calc-panel.is-active {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(15, 81, 50, .1);
}

.calc-panel-label { font-size: .72rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--brand); }
.calc-panel-sub { font-size: .7rem; color: var(--ink-soft); margin-bottom: .4rem; }

.calc-step {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
}

.calc-step button {
    width: 34px; height: 34px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 2px solid var(--brand);
    background: #fff;
    color: var(--brand);
    font-size: 1.15rem; font-weight: 800; line-height: 1;
    cursor: pointer;
    transition: var(--t);
}

.calc-step button:hover { background: var(--brand); color: #fff; }

.calc-step input {
    width: 84px; height: 44px;
    border: 1px solid var(--line);
    border-radius: var(--r-xs);
    background: var(--bg-alt);
    color: var(--ink);
    font-size: 1.35rem; font-weight: 800;
    text-align: center;
    outline: none;
}

.calc-step input:focus { border-color: var(--brand); background: #fff; }
.calc-step input::-webkit-inner-spin-button, .calc-step input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

.calc-sync { color: var(--accent); font-size: 1.3rem; text-align: center; }

.calc-badge {
    display: block;
    max-width: 560px;
    margin: .9rem auto 0;
    padding: .45rem 1.1rem;
    border-radius: var(--r-pill);
    background: var(--brand);
    color: #fff;
    font-size: .85rem; font-weight: 700;
    text-align: center;
}

.calc-tools { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin-top: .9rem; }

.calc-hint {
    max-width: 620px;
    margin: .8rem auto 0;
    padding: .55rem .9rem;
    border: 1px solid var(--line);
    border-radius: var(--r-xs);
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-size: .8rem;
    text-align: center;
}

/* ---- the six numbers ---- */

.calc-summary {
    display: grid;

    /* Fits whatever is there rather than a fixed six. The recipe decides how
       many of these tiles exist, and a fixed count left the last one stranded
       on a row of its own. */
    grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
    gap: .8rem;
    padding: 1.1rem 1.2rem;
    margin-bottom: 1.4rem;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    box-shadow: var(--sh-xs);
}

.calc-sum { text-align: center; }
.calc-sum-val { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 800; font-size: 1.15rem; color: var(--accent); letter-spacing: -.03em; }
.calc-sum-lbl { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-soft); }
.calc-sum-ta { font-size: .72rem; color: var(--ink-soft); }

/* ---- the list ---- */

.calc-card { padding: 0; overflow: hidden; }

.calc-card-head {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .9rem 1.2rem;
    background: var(--brand-soft);
    border-bottom: 1px solid var(--line);
}

.calc-card-head .calc-card-icon { font-size: 1.4rem; }
.calc-card-head h5 { margin: 0; font-weight: 800; font-size: 1rem; }
.calc-card-head small { display: block; color: var(--ink-soft); font-size: .78rem; font-weight: 500; }

.calc-list { padding: .8rem; }

.calc-row {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .6rem .8rem;
    margin-bottom: .4rem;
    border: 1px solid var(--line);
    border-radius: var(--r-xs);
    background: #fff;
    transition: var(--t);
}

.calc-row:last-child { margin-bottom: 0; }
.calc-row:hover { border-color: rgba(15, 81, 50, .25); box-shadow: var(--sh-xs); }

.calc-icon { flex-shrink: 0; width: 34px; text-align: center; font-size: 1.4rem; line-height: 1; }
.calc-names { flex: 1; min-width: 0; }
.calc-ta { font-weight: 700; color: var(--ink); font-size: .93rem; }
.calc-en { color: var(--ink-soft); font-size: .8rem; }
.calc-note { color: var(--ink-soft); font-size: .72rem; font-style: italic; }

.calc-qty { flex-shrink: 0; text-align: right; }
.calc-val { font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 800; font-size: 1rem; color: var(--brand); }
.calc-sub { color: var(--ink-soft); font-size: .74rem; }

/* A heading with no amount, e.g. "choose one of the two below". */
.calc-row.is-label {
    background: transparent;
    border: none;
    border-bottom: 1px dashed var(--line);
    border-radius: 0;
    padding: .7rem .2rem .3rem;
    margin-bottom: .3rem;
}

.calc-row.is-label:hover { box-shadow: none; }
.calc-row.is-label .calc-ta { color: var(--accent-dark); font-size: .87rem; font-weight: 800; }
.calc-row.is-label .calc-icon { font-size: 1.1rem; }

/* What to do at this step, as opposed to what to put in it.

   Not the small italic grey that an ingredient's note gets: this is a line
   somebody reads with their hands full, and some steps - the last one of the
   salna - are nothing but this. */
.calc-how {
    margin-top: .45rem;
    padding: .6rem .85rem;
    border-left: 3px solid var(--brand);
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    background: var(--brand-soft);
    color: var(--ink-2);
    font-size: .88rem;
    font-style: normal;
    line-height: 1.5;
}

/* One of a set of choices. */
.calc-row.is-alt { margin-left: 1rem; background: var(--bg-alt); }
.calc-row.is-alt .calc-val { color: var(--accent-dark); }

/* Changed by this student. */
.calc-row.is-edited { border-color: var(--yellow); background: var(--yellow-soft); }
.calc-row.is-edited .calc-val { color: var(--brand-dark); }
.calc-edited { font-size: .66rem; font-weight: 800; letter-spacing: .05em; color: var(--accent-dark); text-transform: uppercase; }

.calc-edit { display: flex; align-items: center; justify-content: flex-end; gap: .35rem; }

.calc-edit input {
    width: 86px; height: 36px;
    border: 2px solid var(--brand);
    border-radius: var(--r-xs);
    background: #fff;
    color: var(--ink);
    font-weight: 800; font-size: .95rem;
    text-align: right;
    padding: 0 .5rem;
    outline: none;
}

.calc-edit input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(239, 104, 32, .15); }
.calc-edit input::-webkit-inner-spin-button, .calc-edit input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.calc-edit-unit { min-width: 28px; font-size: .75rem; font-weight: 700; color: var(--ink-soft); text-align: left; }

/* The grinding tip, which is worked out rather than typed. */
.calc-tip {
    padding: 1rem 1.2rem;
    margin-bottom: 1.4rem;
    border: 1px solid var(--line);
    border-left: 5px solid var(--yellow);
    border-radius: var(--r);
    background: var(--yellow-soft);
    font-size: .88rem;
}

.calc-tip h6 { font-weight: 800; font-size: .9rem; margin-bottom: .5rem; }
.calc-tip p { margin: 0 0 .3rem; }
.calc-tip p:last-child { margin-bottom: 0; }
.calc-tip .calc-tip-en { color: var(--ink-soft); font-size: .82rem; }

@media (max-width: 575px) {
    .calc-bar {
        padding: .9rem .7rem;

        /* Not sticky on a phone.

           Stacked, with buttons big enough to hit, the bar is a third of a
           phone screen. Pinned under the header it would leave three
           ingredients visible at a time. It scrolls away instead and the
           list gets the screen, which is what somebody standing at a stove
           is actually reading. */
        position: static;
    }

    /* One under the other. Side by side there is about 140px for each panel
       on a 360px phone, and two buttons and a number box do not fit in it
       at any size a thumb can hit - which is how the plus and minus ended up
       at 30px, half of what they should be. */
    .calc-inputs {
        grid-template-columns: minmax(0, 1fr);
        gap: .5rem;
        max-width: 340px;
    }

    .calc-sync { transform: rotate(90deg); font-size: 1rem; line-height: 1; }

    /* Stacked, the bar is the tallest thing on the page, so everything that
       is not a control gives up what it can. The label above each box
       already says which is which. */
    .calc-panel { padding: .5rem .6rem; }
    .calc-panel-sub { display: none; }
    .calc-badge { margin-top: .6rem; }
    .calc-tools { margin-top: .6rem; }

    /* 44px is the size Apple asks for and the size a thumb needs. */
    .calc-step { gap: .6rem; }
    .calc-step input { width: 110px; height: 44px; font-size: 1.25rem; }
    .calc-step button { width: 44px; height: 44px; font-size: 1.25rem; }
    .calc-summary { grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); gap: .5rem; }

    /* On a phone the amount drops under the name rather than squeezing it. */
    .calc-row { flex-wrap: wrap; }
    .calc-row .calc-qty { width: 100%; text-align: left; padding-left: 2.6rem; }
    .calc-row .calc-edit { justify-content: flex-start; }
    .calc-row.is-alt { margin-left: .5rem; }
}

/* ============================================================================
   Photo slider and the full size view
   ----------------------------------------------------------------------------
   A kitchen can have three photos. Only the first was ever visible before, on
   the card and on the detail page alike, which made the other two pointless to
   upload.
   ============================================================================ */

.gallery {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: var(--brand-soft);
}

.gallery-track {
    display: flex;
    height: 100%;
    transition: transform 380ms var(--ease);
    will-change: transform;
}

/* Positioned, so a photo laid over it with position:absolute anchors to THIS
   slide and travels with it. Without this the nearest positioned ancestor is
   .gallery itself, every slide's photo stacks in the same spot, and sliding
   moves the track while the pictures stay where they are - you press the arrow
   and nothing appears to change. */
.gallery-slide { position: relative; flex: 0 0 100%; height: 100%; }

.gallery-slide img {
    display: block;
    width: 100%;
    height: 100%;

    /* Whole photo, padded. See .restaurant-thumb img above. */
    object-fit: contain;
    background: var(--bg-alt);
}

/* The hover zoom is gone from kitchen cards: it pushed a contained photo past
   its own padding and clipped the edges, which is the cropping this was meant
   to stop. */

.gallery-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 34px; height: 34px;
    display: flex; align-items: center; justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(20, 32, 26, .45);
    color: #fff;
    font-size: 1.5rem; line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--t), background var(--t);
    z-index: 2;
}

.gallery-prev { left: .5rem; }
.gallery-next { right: .5rem; }

.gallery:hover .gallery-nav,
.gallery:focus-within .gallery-nav { opacity: 1; }

.gallery-nav:hover { background: var(--brand); }

.gallery-dots {
    position: absolute;
    left: 0; right: 0; bottom: .55rem;
    display: flex; justify-content: center; gap: .3rem;
    z-index: 2;
}

.gallery-dot {
    width: 7px; height: 7px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, .55);
    box-shadow: 0 0 0 1px rgba(20, 32, 26, .25);
    cursor: pointer;
    transition: var(--t);
}

.gallery-dot.is-on { background: var(--yellow); width: 18px; border-radius: var(--r-pill); }

.gallery-count {
    position: absolute;
    top: .55rem; right: .55rem;
    padding: .1rem .5rem;
    border-radius: var(--r-pill);
    background: rgba(20, 32, 26, .5);
    color: #fff;
    font-size: .68rem; font-weight: 700;
    letter-spacing: .04em;
    z-index: 2;
}

.gallery-expand {
    position: absolute;
    top: .5rem; left: .5rem;
    width: 30px; height: 30px;
    display: flex; align-items: center; justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(20, 32, 26, .45);
    color: #fff;
    font-size: .95rem; line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--t), background var(--t);
    z-index: 2;
}

.gallery:hover .gallery-expand,
.gallery:focus-within .gallery-expand { opacity: 1; }
.gallery-expand:hover { background: var(--brand); }

/* Touch has no hover, so the controls simply stay put rather than never
   appearing at all. */
@media (hover: none) {
    .gallery-nav, .gallery-expand { opacity: 1; }
}

/* The big photo on a kitchen's own page. */
.gallery-hero {
    aspect-ratio: 16/10;
    max-height: 380px;
    border-radius: var(--r-lg);
    box-shadow: var(--sh);
    margin-bottom: 1.4rem;
}

.gallery-hero .gallery-slide img { cursor: zoom-in; }

/* ---- full size ---- */

body.lightbox-open { overflow: hidden; }

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: none;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: 1.5rem;
    background: rgba(10, 18, 14, .93);
    backdrop-filter: blur(2px);
}

.lightbox.is-open { display: flex; }

.lightbox-figure {
    margin: 0;
    max-width: min(1100px, 92vw);
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .6rem;
}

.lightbox-figure img {
    max-width: 100%;
    max-height: 80vh;
    object-fit: contain;
    border-radius: var(--r-sm);
    box-shadow: var(--sh-lg);
}

.lightbox-figure figcaption {
    color: rgba(255, 255, 255, .8);
    font-size: .85rem;
    text-align: center;
}

.lightbox-nav, .lightbox-close {
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    cursor: pointer;
    transition: background var(--t);
}

.lightbox-nav { width: 44px; height: 44px; font-size: 1.9rem; line-height: 1; }
.lightbox-nav:hover, .lightbox-close:hover { background: var(--brand); }

.lightbox-close {
    position: absolute;
    top: 1rem; right: 1rem;
    width: 40px; height: 40px;
    font-size: 1.7rem; line-height: 1;
}

@media (max-width: 575px) {
    .lightbox { padding: .8rem; gap: .2rem; }
    .lightbox-nav { width: 36px; height: 36px; font-size: 1.5rem; }
    .gallery-hero { aspect-ratio: 4/3; }
}

/* ---------------------------------------------------------------- Reaching a kitchen

   On the card in the list. The number used to be a link that said "Call",
   which is a word rather than a phone number, and WhatsApp was not offered at
   all even when the kitchen had given us one. */

.reach-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin: .2rem 0 .9rem;
}

.reach-chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .28rem .7rem .28rem .5rem;
    border: 1px solid rgba(15, 81, 50, .2);
    border-radius: var(--r-pill);
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-size: .8rem;
    font-weight: 700;
    white-space: nowrap;
    transition: var(--t);
}

.reach-chip svg { width: 15px; height: 15px; fill: var(--brand); flex-shrink: 0; }

.reach-chip:hover {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
    box-shadow: var(--sh-sm);
}

.reach-chip:hover svg { fill: #fff; }

.reach-wa { background: #E7F9EE; border-color: rgba(37, 211, 102, .35); color: #0B6B33; }
.reach-wa svg { fill: #25D366; }
.reach-wa:hover { background: #25D366; border-color: #25D366; color: #fff; }

.reach-social { display: inline-flex; gap: .3rem; margin-left: auto; }

.reach-ico {
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: #fff;
    transition: var(--t);
}

.reach-ico svg { width: 14px; height: 14px; fill: var(--ink-soft); transition: fill var(--t); }
.reach-ico:hover { transform: translateY(-2px); border-color: transparent; box-shadow: var(--sh-sm); }
.reach-ico:hover svg { fill: #fff; }

.reach-instagram:hover { background: linear-gradient(45deg, #F58529, #DD2A7B 50%, #8134AF); }
.reach-facebook:hover { background: #1877F2; }
.reach-youtube:hover { background: #FF0000; }
.reach-web:hover { background: var(--brand); }

@media (max-width: 575px) {
    /* On a phone the icons drop under the numbers rather than being pushed
       off to a corner of their own. */
    .reach-social { margin-left: 0; }
}

/* A kitchen in the student's own list. One card each, because each is sent,
   paid for and approved separately from the others. */
.kitchen-row { padding: 1.2rem 1.3rem; }
.kitchen-row .shop-name { font-size: 1.02rem; }

.fee-line {
    padding: .5rem .8rem;
    border-radius: var(--r-xs);
    background: var(--cream);
    border: 1px dashed rgba(239, 104, 32, .35);
    color: var(--ink-2);
    font-size: .85rem;
}

/* The three ways of saying where a kitchen is. Side by side on purpose: a
   student standing in their kitchen should not have to read past a paragraph
   about copying links to find the button that just asks their phone. */
.loc-ways {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}

/* The Recipes menu in the header. Bootstrap's own dropdown, dressed to match
   the rest of the navigation rather than arriving as a grey box. */
/* The account menu. One control carrying the greeting, the last sign-in, the
   way in to your own pages and the way out - which is a lot less header than
   the three separate things it replaces. */
.who-toggle { display: inline-flex; align-items: center; gap: .45rem; }
.who-toggle .who-name { font-weight: 700; }

.who-dot {
    width: 26px; height: 26px; flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: var(--brand); color: #fff;
    font-size: .78rem; font-weight: 800;
}

.who-menu { min-width: 15rem; }

.who-head { padding: .55rem .95rem .35rem; display: flex; flex-direction: column; line-height: 1.3; }
.who-hi { font-size: .88rem; color: var(--ink-2); }
.who-hi strong { font-weight: 800; color: var(--ink); }
.who-last { font-size: .74rem; color: var(--ink-soft); }
.who-last:empty { display: none; }

/* Inside the stacked phone menu a right-aligned dropdown has nothing to hang
   off, so it reads as a plain block like everything else around it. */
@media (max-width: 991.98px) {
    .who-nav .dropdown-menu { border: 0; box-shadow: none; padding-left: .4rem; }
    .who-menu { min-width: 0; }
}

.site-header .dropdown-menu {
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    box-shadow: var(--sh);
    padding: .4rem;
    margin-top: .4rem;
    min-width: 12rem;
}

.site-header .dropdown-item {
    border-radius: var(--r-xs);
    padding: .5rem .8rem;
    font-weight: 600;
    font-size: .93rem;
    color: var(--ink-2);
}

.site-header .dropdown-item:hover,
.site-header .dropdown-item:focus {
    background: var(--brand-soft);
    color: var(--brand-dark);
}

/* Inside the collapsed menu on a phone there is no floating panel, so the
   items simply indent under Recipes. */
@media (max-width: 991.98px) {
    .site-header .dropdown-menu {
        border: none;
        box-shadow: none;
        padding: 0 0 0 .8rem;
        margin: 0;
        background: transparent;
    }
}

/* ---------------------------------------------------------------- Stepper

   A long form taken a few questions at a time. The track along the top is the
   map: where you are, what is done, what is left. */

.stepper-track {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-bottom: 1.4rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--line);
}

/* The track stays put while the questions under it scroll, so "which step am
   I on" never needs a scroll up to answer. It sits below the site header,
   which is sticky itself and would otherwise cover it. */
.stepper-track.is-stuck {
    position: sticky;
    top: 81px;
    z-index: 6;
    background: #fff;
    margin: -1.4rem -1.4rem 1.1rem;
    padding: 1.1rem 1.4rem .8rem;
    border-radius: var(--r-lg, 16px) var(--r-lg, 16px) 0 0;
}

.stepper-step {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .35rem .8rem .35rem .4rem;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
    color: var(--ink-soft);
    font-size: .82rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: var(--t);
}

.stepper-step:disabled { opacity: .5; cursor: default; }
.stepper-step:not(:disabled):hover { border-color: rgba(15, 81, 50, .35); }

.stepper-num {
    width: 22px; height: 22px;
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: var(--line-soft);
    color: var(--ink-soft);
    font-size: .74rem; font-weight: 800;
}

.stepper-step.is-on {
    border-color: var(--brand);
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-weight: 800;
}

.stepper-step.is-on .stepper-num { background: var(--brand); color: #fff; }

.stepper-step.is-done { color: var(--brand); }
.stepper-step.is-done .stepper-num { background: var(--brand); color: #fff; }

/* One row of controls, and it is the only way to save. Either stuck to the
   bottom of the page or dropped into a modal footer that stays put - a save
   button you have to go looking for is a form people abandon. */
.stepper-foot {
    display: flex;
    align-items: center;
    gap: .8rem;
}

.stepper-foot.is-stuck {
    position: sticky;
    bottom: 0;
    z-index: 6;
    margin: 1.2rem -1.4rem -1.4rem;
    padding: .8rem 1.4rem;
    background: #fff;
    border-top: 1px solid var(--line);
    border-radius: 0 0 var(--r-lg, 16px) var(--r-lg, 16px);
    box-shadow: 0 -6px 18px rgba(16, 24, 40, .06);
}

.stepper-foot .stepper-next { margin-left: auto; }
.stepper-foot .is-hidden { display: none; }
.stepper-foot.is-busy { opacity: .85; }

/* Where you are, in words as well as a number - the number alone tells you how
   far, but not what you are looking at. */
.stepper-where { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.stepper-where-num { color: var(--ink-soft); font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.stepper-where-name { font-weight: 700; font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* On a phone the track becomes a single line that scrolls, so five steps do
   not push the form itself off the screen. */
@media (max-width: 575px) {
    .stepper-track {
        flex-wrap: nowrap;
        overflow-x: auto;
        padding-bottom: .8rem;
        -webkit-overflow-scrolling: touch;
    }

    .stepper-step { flex-shrink: 0; }

    /* The button keeps its full width and its own line. Back and the step name
       share the line above it, because the thing being reached for with a thumb
       should be the biggest target on the bar. */
    .stepper-foot { flex-wrap: wrap; gap: .5rem .8rem; }
    .stepper-foot .stepper-back { order: 1; }
    .stepper-foot .stepper-where { order: 2; margin-left: auto; text-align: right; }
    .stepper-foot .stepper-next { order: 3; width: 100%; margin-left: 0; }
}

/* The three photo slots inside the Photos step. They used to sit in a narrow
   column beside the form, which kept them small; a full width step let each
   one grow to the width of the page. */
.photo-row .photo-slot { height: 100%; }
.photo-row .photo-preview { aspect-ratio: 4/3; max-height: 220px; }

/* The two ways of sending the registration fee. A list rather than a sentence,
   because somebody is about to copy one of these into a payment app and a
   number buried in prose is a number typed wrongly. */
.pay-to { list-style: none; padding: 0; margin: 0 0 .9rem; }

.pay-to li {
    display: flex;
    align-items: baseline;
    gap: .6rem;
    flex-wrap: wrap;
    padding: .5rem .8rem;
    margin-bottom: .4rem;
    border: 1px solid var(--line);
    border-left: 4px solid var(--brand);
    border-radius: var(--r-xs);
    background: var(--bg-alt);
}

.pay-to span { color: var(--ink-soft); font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; min-width: 8.5rem; }
.pay-to strong { font-size: 1.02rem; letter-spacing: .01em; color: var(--ink); overflow-wrap: anywhere; }

/* ---------------------------------------------------------------- The pin you asked for

   Tapping "Show on map" centres the map, which in a street with four kitchens
   on it lands four identical pins in the middle of the screen and points at
   none of them. So the one you asked for glows.

   A filter rather than a transform: Leaflet positions every marker with a
   transform of its own, and animating that walks the pin off the map.
   ---------------------------------------------------------------- */

.pin-flash {
    animation: pinFlash 1.1s ease-out 2;
    z-index: 1000 !important;
}

@keyframes pinFlash {
    0%, 100% { filter: none; }

    45% {
        filter:
            drop-shadow(0 0 6px rgba(239, 104, 32, .95))
            drop-shadow(0 0 16px rgba(239, 104, 32, .75));
    }
}

/* The drawn pin can do more than glow: it can lean up out of the map, from the
   point it stands on, the way somebody raises a hand. */
.pin-flash .pin-mark { animation: pinLift 1.1s ease-out 2; }

@keyframes pinLift {
    0%, 100% { transform: scale(1); }
    45%      { transform: scale(1.28) translateY(-3px); }
}

/* Somebody who has asked their phone to stop animating things still gets told
   which pin it is - it simply stays lit rather than pulsing. */
@media (prefers-reduced-motion: reduce) {
    .pin-flash {
        animation: none;
        filter: drop-shadow(0 0 6px rgba(239, 104, 32, .95));
    }

    .pin-flash .pin-mark { animation: none; transform: scale(1.2); }
}

/* How many of the kitchens are showing, once a filter has narrowed them. */
.pin-count { display: inline-block; margin-left: .4rem; font-weight: 700; color: var(--brand); }

/* ---------------------------------------------------------------- Training dates

   The two questions the phone rings about - when is the next one, is there room -
   answered on the card itself. The seats left is the button, because the number
   IS the reason to tap it.
   ---------------------------------------------------------------- */

.batch-list { margin: 1rem 0 .2rem; border-top: 1px solid var(--line); }

.batch-row {
    display: flex; align-items: center; justify-content: space-between; gap: .8rem;
    padding: .7rem 0;
    border-bottom: 1px solid var(--line-soft);
}

.batch-row:last-child { border-bottom: 0; }
.batch-row strong { display: block; font-weight: 700; font-size: .95rem; }
.batch-row small { display: block; color: var(--ink-soft); font-size: .8rem; }
.batch-row.is-full { opacity: .55; }

/* "6 places left" is three words, and a button that wraps them onto two lines
   in a narrow card reads as an error rather than a label. It keeps its line and
   the date beside it gives way instead. */
.batch-row .btn { white-space: nowrap; flex: 0 0 auto; }

.batch-full {
    font-size: .78rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .05em;
    color: var(--ink-soft);
}

/* How full a batch is, on the admin list. A number tells you; a bar tells you
   at a glance which Saturday needs filling. */
.fill-bar {
    height: 8px; border-radius: 999px;
    background: var(--line-soft); overflow: hidden;
    min-width: 90px;
}

.fill-bar span { display: block; height: 100%; background: var(--brand); border-radius: 999px; }
.fill-bar.is-full span { background: var(--accent); }

/* ---- the line under a phone box ----
   Three things it can say, and they read very differently. A problem is red
   and stops the save. A warning is amber and does not - it is about a number
   that was saved years ago and is only being pointed at. A hint is grey and is
   just telling you what is about to happen to what you typed. */
.phone-note { font-size: .82rem; line-height: 1.35; margin-top: .3rem; }
.phone-note:empty { display: none; }
.phone-bad  { color: #c0392b; }
.phone-warn { color: #9a6200; }
.phone-hint { color: var(--ink-soft); }

.form-control.is-invalid {
    border-color: #c0392b;
    background-image: none;
}

.form-control.is-invalid:focus {
    border-color: #c0392b;
    box-shadow: 0 0 0 .2rem rgba(192, 57, 43, .15);
}

/* ---- the box that is not really there ----
   Off the side of the page rather than display:none, which is the first thing
   a bot checks for. It still exists, still has a label, and is still filled in
   by anything reading the form as markup - which is exactly the point. */
.hp-wrap {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* ============================================================================
   Made for a thumb
   ----------------------------------------------------------------------------
   Measuring the buttons on a phone turned up small ones everywhere: the
   .btn-sm pairs on the kitchen cards at 36px, the menu button at 34px, and the
   date "clear" at 26px. They are fine to click with a mouse and awkward to hit
   with a thumb, which is the difference between a page that works on a phone
   and one that only looks like it does.

   Scoped to a coarse pointer, so nothing changes on a laptop. Height only -
   the padding and the type stay exactly as designed, so nothing is redrawn,
   the target is simply tall enough to land on.
   ========================================================================= */

@media (pointer: coarse) {
    .btn,
    .navbar-toggler,
    .map-reset,
    .range-clear {
        min-height: 40px;
    }

    /* Never smaller than 16px on a touch screen.

       Safari on iPhone zooms the whole page in whenever you tap a text box
       whose text is under 16px, and it does not zoom back out afterwards.
       Every box on this site was .95rem - 15.2px - so tapping any of them
       threw the page sideways and left the button you were aiming for off the
       edge of the screen. It reads as the page breaking, and it happens on
       iPhone only: nothing else does this.

       16px flat rather than a fraction, because that is the number Safari
       measures against. Boxes that are already bigger are left alone. */
    .form-control,
    .form-select,
    .calc-edit input {
        font-size: 16px;
    }

    /* Room for the taller text, so the box does not crop it. */
    .calc-edit input { height: 42px; }


    /* A button whose height is doing the work needs its label centred in it,
       or the text sits at the top of a taller box. */
    .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* The small ones are small for a reason - they sit in rows - so they get
       the minimum that is still reliably hittable rather than the full 40. */
    .btn-sm { min-height: 38px; }

    /* A button that fills its row is already easy to hit; keeping it inline-flex
       would shrink it to its text. */
    .btn.w-100, .btn.d-block, .d-grid > .btn { display: flex; width: 100%; }
}

/* ---- the popups ----
   SweetAlert's own look is close to the site already; these few lines make it
   the site's rather than close to it - the heading face, the corner radius and
   the pill buttons the rest of the pages use. */
.dk-swal {
    border-radius: var(--r, 18px) !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

.dk-swal .swal2-title {
    font-family: 'Plus Jakarta Sans', 'Inter', sans-serif;
    font-weight: 800;
    letter-spacing: -.02em;
    font-size: 1.25rem;
    line-height: 1.3;
    color: var(--ink, #14201A);
}

.dk-swal .swal2-html-container {
    font-size: .95rem;
    line-height: 1.55;
    color: var(--ink-soft, #6B7872);
    margin-top: .4rem;
}

.dk-swal .swal2-actions { gap: .6rem; margin-top: 1.2rem; }

.dk-swal .swal2-styled {
    border-radius: var(--r-pill, 999px);
    font-weight: 600;
    padding: .58rem 1.4rem;
    box-shadow: none;
    min-height: 40px;
}

.dk-swal .swal2-styled:focus { box-shadow: 0 0 0 3px rgba(249, 194, 26, .45); }

.dk-swal .swal2-textarea,
.dk-swal .swal2-input {
    border-radius: var(--r-sm, 12px);
    border: 1px solid var(--line, #E7EAE7);
    box-shadow: none;
    font-size: .95rem;
}

.dk-swal .swal2-textarea:focus,
.dk-swal .swal2-input:focus {
    border-color: var(--brand, #0F5132);
    box-shadow: 0 0 0 3px rgba(15, 81, 50, .12);
}

.dk-swal .swal2-validation-message { border-radius: var(--r-sm, 12px); font-size: .85rem; }

/* On a phone a popup should not touch the edges of the screen. */
@media (max-width: 575.98px) {
    .swal2-popup.dk-swal { width: calc(100vw - 2rem); padding: 1.25rem; }
    .dk-swal .swal2-title { font-size: 1.1rem; }
    .dk-swal .swal2-actions { flex-direction: column-reverse; width: 100%; }
    .dk-swal .swal2-styled { width: 100%; margin: 0; }
}

/* ============================================================================
   The photograph in the hero
   ----------------------------------------------------------------------------
   What replaced the embedded video. The picture is doing the persuading now,
   so everything here is in service of it: the frame keeps out of the way, the
   depth comes from two soft layers rather than one hard drop shadow, and the
   only two pieces of text sit on the image rather than in a bar beneath it,
   which keeps the whole block short enough for a laptop screen.
   ========================================================================= */

.hero-shot {
    position: relative;
    margin: 0;
}

/* A warm halo behind the card, tinted from the brand. It reads as light
   falling on the photo rather than as a border around it. */
.hero-shot::before {
    content: "";
    position: absolute;
    inset: 6% -4% -8% 2%;
    border-radius: var(--r-lg);
    background:
        radial-gradient(60% 70% at 30% 30%, rgba(249, 194, 26, .38), transparent 70%),
        radial-gradient(70% 70% at 80% 80%, rgba(239, 104, 32, .28), transparent 72%);
    filter: blur(28px);
    z-index: 0;
    pointer-events: none;
}

.hero-shot-frame {
    position: relative;
    z-index: 1;
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--cream);

    /* Two layers. A close one that seats the card on the page and a wide soft
       one underneath it - a single hard shadow always looks stuck on. */
    box-shadow:
        0 1px 2px rgba(20, 32, 26, .10),
        0 18px 44px rgba(20, 32, 26, .16);

    /* A hairline of white inside the edge, which is what stops a photograph
       with pale kitchen walls bleeding into a pale page. */
    outline: 5px solid #fff;
    outline-offset: -5px;
}

.hero-shot-frame img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1.75 / 1;
    object-fit: cover;

    /* Very slightly warmer and more contrasted than the file, which lifts the
       copper of the pot without touching skin tones. */
    filter: saturate(1.04) contrast(1.02);
}

/* ---- the caption ---- */

/* Sat on the picture rather than under it. A caption bar of its own would add
   sixty pixels to a hero that has just been cut down to fit a laptop. */
.hero-shot-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    padding: 2.2rem .95rem .7rem;
    color: #fff;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .01em;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .5);

    /* Only as dark as it needs to be to hold small white text. */
    background: linear-gradient(180deg, transparent, rgba(12, 22, 16, .62));
}

/* ---- smaller screens ---- */

@media (max-width: 991.98px) {
    /* Below the text rather than beside it, and a little breathing room from
       the buttons above. */
    .hero-shot { margin-top: .4rem; }

    /* The halo is a desktop flourish. On a phone it only costs a repaint. */
    .hero-shot::before { display: none; }

    .hero-shot-frame {
        outline-width: 4px;
        outline-offset: -4px;
        box-shadow: 0 1px 2px rgba(20, 32, 26, .10), 0 10px 26px rgba(20, 32, 26, .14);
    }
}

@media (max-width: 575.98px) {
    .hero-shot-caption { font-size: .76rem; padding: 1.8rem .75rem .6rem; }
}

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

/* ---- buying the recipes on their own ----
   The price and the button on one line, so the offer reads as one thing rather
   than as a paragraph with a button after it. */
.recipes-offer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .9rem 1rem;
    border: 1px solid rgba(249, 194, 26, .5);
    border-radius: var(--r-sm);
    background: linear-gradient(180deg, #fff, var(--yellow-soft));
}

.recipes-price { display: flex; flex-direction: column; line-height: 1.2; }

.recipes-amount {
    font-family: 'Plus Jakarta Sans', 'Inter', sans-serif;
    font-size: 1.45rem;
    font-weight: 800;
    color: var(--brand-dark);
    letter-spacing: -.03em;
}

.recipes-once { font-size: .78rem; color: var(--ink-soft); font-weight: 500; }

@media (max-width: 575.98px) {
    .recipes-offer { flex-direction: column; align-items: stretch; text-align: center; }
    .recipes-offer .btn { width: 100%; }
}

/* The warning under the recipes offer, for a student who already has a kitchen
   sitting unpaid. Amber rather than grey: it is correcting an assumption that
   would otherwise cost them their listing. */
.recipes-note {
    font-size: .84rem;
    line-height: 1.5;
    padding: .6rem .8rem;
    border-left: 3px solid var(--yellow);
    border-radius: 0 var(--r-xs) var(--r-xs) 0;
    background: var(--yellow-soft);
    color: #6C4E00;
}

.recipes-note strong { color: #4A3600; }

/* The certificate offer. Deliberately not the same yellow as the recipes
   offer next to it: one of them asks for money and the other hands something
   over, and a student scanning the column should be able to tell which is
   which before reading a word. Green, and quieter. */
.cert-offer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .9rem 1rem;
    border: 1px solid rgba(15, 81, 50, .22);
    border-radius: var(--r-sm);
    background: linear-gradient(180deg, #fff, #F1F7F3);
}

.cert-what { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }

.cert-course {
    font-family: 'Plus Jakarta Sans', 'Inter', sans-serif;
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--brand-dark);
}

.cert-when { font-size: .78rem; color: var(--ink-soft); font-weight: 500; }

@media (max-width: 575.98px) {
    .cert-offer { flex-direction: column; align-items: stretch; text-align: center; }
    .cert-offer .btn { width: 100%; }
}

/* Tablets and phones on their side keep the two boxes beside each other, so
   there is no room for the full 44 - but 34px circles are still a miss
   waiting to happen on glass. 40 is what every other button here gets. */
@media (pointer: coarse) and (min-width: 576px) {
    .calc-step button { width: 40px; height: 40px; font-size: 1.1rem; }
}

/* A short window - a phone turned on its side, or a small laptop with the
   browser part open - is wider than the phone breakpoint but has no room to
   give a sticky bar a third of itself. Height decides this one, not width. */
@media (max-height: 560px) {
    .calc-bar { position: static; }
}

/* The popup's own boxes, last so they win.

   Same rule as every other box on a touch screen - 16px or Safari on iPhone
   zooms the page in on the tap and stays there. This sits at the end of the
   file rather than beside the others because the popup styles are further
   down and would otherwise be the ones that win. */
@media (pointer: coarse) {
    .dk-swal .swal2-input,
    .dk-swal .swal2-textarea {
        font-size: 16px;
    }
}
