/* @generated by appgen: this file is rewritten on every build.
   Hand edits belong in custom.css, which is loaded after it. */

:root {
    --paper: #f7f5f0;
    --panel: #efebe3;
    --rule: #dfd9cf;
    --ink: #1d1b18;
    --bark: #1d1b18;
    --muted: #7a736b;
    --accent: #2f6b8f;
    --soil: #1d1b18;
    --leaf: #2f6b8f;
    --serif: "Instrument Serif", Georgia, "Times New Roman", serif;
    --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --wrap: 64rem;

    /* The older names, kept so both spellings resolve. */
    --cream: var(--paper);
    --sand: var(--panel);
    --edge: var(--rule);
    --moss: var(--accent);
    --walnut: var(--accent);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font: 17px/1.65 var(--sans);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
    font-family: var(--serif);
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--bark);
    margin: 0 0 0.5em;
}

h1 { font-size: clamp(2.2rem, 6vw, 3.6rem); }
h2 { font-size: clamp(1.6rem, 3.5vw, 2.3rem); }
/* A heroless page's first heading is its h1, dressed as the h2 it replaces. */
.band h1 { font-size: clamp(1.6rem, 3.5vw, 2.3rem); }
h3 { font-size: 1.15rem; }
p { margin: 0 0 1em; }
a { color: var(--moss); }

.wrap {
    max-width: var(--wrap);
    margin: 0 auto;
    padding-inline: 20px;
}

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

.site-head {
    position: sticky;
    top: 0;
    z-index: 10;
    background: rgba(251, 248, 242, 0.92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--edge);
}

.site-head .wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
    align-items: center;
    justify-content: space-between;
    padding-block: 14px;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: Georgia, serif;
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--bark);
    text-decoration: none;
}

.mark {
    width: 22px;
    height: 22px;
    border-radius: 50% 50% 50% 6px;
    background: linear-gradient(150deg, var(--leaf), var(--moss));
    flex: none;
}

.site-head nav {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 22px;
}

.site-head nav a {
    color: var(--muted);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.95rem;
    padding-block: 4px;
    border-bottom: 2px solid transparent;
}

.site-head nav a:hover { color: var(--bark); }
.site-head nav a.here { color: var(--bark); border-bottom-color: var(--leaf); }

/* And room, so the copy clears the ridgeline rather than relying on the scrim. */
.hero.has-backdrop { padding-bottom: clamp(120px, 19vw, 250px); }

.hero .wrap { position: relative; }
.hero h1 { color: #fff; max-width: 16ch; }

.hero .lede {
    font-size: clamp(1.05rem, 2.2vw, 1.3rem);
    max-width: 46ch;
    color: #e2dac9;
    margin-bottom: 1.6em;
}

.hero .note { color: #b6ac97; font-size: 0.9rem; margin-top: 1.4em; }

.actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.btn {
    display: inline-block;
    padding: 13px 26px;
    border-radius: 999px;
    font-weight: 700;
    text-decoration: none;
    border: 2px solid transparent;
}

.btn-primary { background: var(--leaf); color: #16220d; }
.btn-primary:hover { background: #7fb054; }
.btn-ghost { border-color: rgba(255, 255, 255, 0.45); color: #f6f1e6; }
.btn-ghost:hover { border-color: #fff; }

.band-cta .btn-ghost { border-color: var(--soil); color: var(--soil); }
.band-cta .btn-ghost:hover { background: var(--sand); }

/* ------------------------------------------------------------------- bands */

.band { padding-block: clamp(48px, 8vw, 88px); }
.band + .band { border-top: 1px solid var(--edge); }
.band-services, .band-quotes { background: var(--sand); border-top: none; }
.band .intro { max-width: 60ch; color: var(--muted); font-size: 1.05rem; margin-bottom: 2em; }
.band .note { color: var(--muted); font-size: 0.9rem; margin-top: 2em; }

.prose { max-width: 62ch; }

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

.site-foot {
    background: var(--bark);
    color: #c8bfae;
    padding-block: 44px;
    font-size: 0.93rem;
}

.site-foot p { margin: 0 0 6px; }
.site-foot strong { color: #f6f1e6; }
.site-foot a { color: #a8cc82; }
.site-foot .fine { margin-top: 14px; color: #8b8171; font-size: 0.85rem; }

/* A link in the fine print reads as fine print, not as a link in a body of
   text: nothing styled it, so it fell through to the palette's link colour and
   turned up green under a grey footer. */
.site-foot .fine a { color: inherit; text-decoration: none; border-bottom: 1px solid currentColor; }
.site-foot .fine a:hover { color: var(--bark); }

@media (max-width: 34rem) {
    .btn { flex: 1 1 auto; text-align: center; }
}

/* ------------------------------------------------------------- compare */

/* The ranking as a table. Lifted from the sites that had written it by
   hand. It scrolls sideways rather than wrapping: a squeezed row is
   unreadable. */

.compare-wrap { overflow-x: auto; margin-top: 8px; -webkit-overflow-scrolling: touch; }

.compare { width: 100%; border-collapse: collapse; font-size: 0.92rem; min-width: 36rem; }

.compare th, .compare td { text-align: left; padding: 14px 18px 14px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }

.compare thead th { font: 500 0.7rem/1.6 var(--sans); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); border-bottom-color: var(--ink); }

.compare tbody th { font: 400 0.95rem/1.6 var(--sans); color: var(--muted); width: 2.5rem; }

.compare td:first-of-type { font-weight: 500; }

.compare a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--rule); }

.compare a:hover { color: var(--accent); border-color: currentColor; }

/* --------------------------------------------------------------------- faq */

.faq { max-width: 62ch; }

.faq details {
    border-bottom: 1px solid var(--edge);
    padding: 16px 0;
}

.faq summary {
    cursor: pointer;
    font-weight: 700;
    color: var(--bark);
}

.faq details[open] summary { margin-bottom: 10px; }
.faq p { margin: 0; color: var(--muted); }

/* The date line under a hero. */
.updated { font-size: 0.85rem; opacity: 0.75; margin: 0 0 1.4em; }

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

.hero {
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(120% 90% at 80% 0%, rgba(109, 158, 69, 0.28), transparent 60%),
        linear-gradient(170deg, var(--soil), var(--bark));
    color: #f6f1e6;
    padding-block: clamp(64px, 12vw, 128px);
}

/* The ridgeline sits at the foot of the hero and fades up into the gradient,
   so the text above it never has to fight it for contrast. */
.backdrop {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 58%;
    background-position: bottom center;
    background-size: cover;
    background-repeat: no-repeat;
    pointer-events: none;
}

/* The scrim. Without it the far ridges sit directly behind the buttons and the
   note under them, and a pale ridge behind pale text is unreadable. */
.backdrop::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to bottom,
        var(--bark) 0%,
        rgba(36, 29, 22, 0.72) 26%,
        rgba(36, 29, 22, 0.12) 62%,
        transparent 100%
    );
}

/* An entry's own page. Not gated on menus: a ranking has entry pages
   whether or not it tracks anybody's menu. */
.entry-hero h1 { max-width: 16ch; }
.entry-hero .actions { gap: 28px; }


/* Under the site header, which is sticky too. */
    top: 58px;
    z-index: 1;
    margin: 0 0 14px;
    padding: 10px 0 8px;
    background: linear-gradient(var(--paper) 78%, transparent);
    font-family: var(--sans);
    font-size: 0.74rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
}

.menu-note { color: var(--muted); font-size: 0.9rem; margin: 0 0 10px; max-width: 56ch; }

.menu-items {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
    gap: 20px 48px;
    align-items: start;
}

.menu-entry.is-wide { grid-column: 1 / -1; }

.menu-item {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px 14px;
    align-items: baseline;
    margin: 0;
}

.menu-name {
    font-size: 0.95rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    line-height: 1.35;
}

.menu-cost {
    color: var(--muted);
    font-size: 0.88rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.menu-cost-own {
    margin: 3px 0 0;
    white-space: normal;
    color: #8c8477;
}

.menu-desc {
    grid-column: 1 / -1;
    color: #5f594f;
    font-size: 0.89rem;
    line-height: 1.5;
    margin: 3px 0 0;
    max-width: 46ch;
}

.menu-flags {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 5px 0 0;
    padding: 0;
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #a49b8e;
}

@media (max-width: 560px) {
    .menu-items { gap: 16px; }
    .menu-part-head { top: 52px; }
}

.menu-hero { padding-block: clamp(56px, 9vw, 96px) clamp(20px, 3vw, 32px); }

.menu-hero h1 { font-size: clamp(2.4rem, 6vw, 4.2rem); }

.band-menu .menu-index + .menu { margin-top: 30px; }

.menu-index {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 26px 0 0;
}

.menu-link {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    padding: 7px 15px;
    border: 1px solid var(--rule);
    border-radius: 999px;
    font-size: 0.86rem;
    font-weight: 500;
    color: var(--muted);
    text-decoration: none;
    transition: border-color 0.2s ease, color 0.2s ease;
}

.menu-link:hover { color: var(--ink); border-color: #c9c1b4; }

.menu-link .menu-count { font-size: 0.76rem; color: #a49b8e; font-variant-numeric: tabular-nums; }

.band-menu .menu-name-head { padding-top: 8px; }

.menu-name-head + .menu-note { margin-bottom: 14px; }

.band-menu-preview .menu-part:first-of-type { margin-top: 18px; }

.menu-more { margin: 30px 0 0; }


/* The link to an entry's own menu page. */
.rank-menu { font-weight: 500; }

/* rank-body is the second grid column of .rank and carries no rules of
   its own; it groups the text away from the number. */
/* ------------------------------------------------------- ranked entries */

.rank-links { font-size: 0.9rem; margin: 0.6em 0 0; }
.crumbs { font-size: 0.85rem; margin: 0 0 1em; }
.band-entry .contact { margin-top: 32px; }
.band-entry .rank-tags { list-style: none; padding: 0; margin: 24px 0 0; }
.entry-steps {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 16px;
    margin-top: 40px;
}
.entry-steps a span { display: block; font-size: 0.8rem; opacity: 0.7; }
.entry-next { margin-left: auto; text-align: right; }

/* ------------------------------------------------------------- ranking */

/* The ranked list. Lifted out of the three sites that had each written it by hand. */

.ranking {
    list-style: none;
    margin: 0;
    padding: 0;
    border-bottom: 1px solid var(--rule);
}

.rank {
    display: grid;
    grid-template-columns: 5rem 1fr;
    gap: 0 24px;
    padding: 30px 0;
    border-top: 1px solid var(--rule);
}

.rank-no {
    font: 400 2.6rem/1 var(--serif);
    color: #b3aba0;
    font-variant-numeric: tabular-nums;
}

.rank-no::before { content: "No."; font-size: 0.4em; margin-right: 3px; vertical-align: 0.9em; }

.rank h3 {
    font-size: clamp(1.6rem, 3vw, 2rem);
    line-height: 1.1;
    margin: 0 0 0.2em;
}

.rank h3 a { text-decoration: none; background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat; transition: background-size 0.35s ease, color 0.2s; }

.rank h3 a:hover { color: var(--accent); background-size: 100% 1px; }

.rank-place { color: var(--muted); font-size: 0.85rem; margin-bottom: 0.9em; }

.rank .blurb { max-width: 60ch; color: #3d3934; margin-bottom: 0.8em; }

.rank-tags {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.8rem;
    color: var(--muted);
}

.rank-tags li { display: inline; }

.rank-tags li + li::before { content: "  b7 "; white-space: pre; }

.rank-1 {
    background: var(--panel);
    border-top: 0;
    padding: clamp(32px, 5vw, 52px) clamp(20px, 4vw, 44px);
    margin-bottom: 18px;
    grid-template-columns: 7rem 1fr;
}

.rank-1 + .rank { border-top: 0; }

.rank-1 .rank-no { font-size: 5rem; color: var(--accent); }

/* The ask, in the list. No numeral column to fill, so the body takes the whole
   width; a panel behind it so it reads as an aside rather than as an entry
   somebody forgot to number. */
/* .rank.rank-ask, not .rank-ask: a site's own stylesheet loads after this one
   and sets .rank's columns, which at equal specificity wins. The ask has no
   numeral, so losing here put its whole body in the 5rem number column and set
   the copy one word per line. The body is pinned across every column too, so it
   cannot happen again if the grid changes. */
.rank.rank-ask { grid-template-columns: 1fr; background: var(--panel); padding: 30px; }
.rank.rank-ask .rank-body { grid-column: 1 / -1; }
.rank-ask .blurb { max-width: 52ch; }
.rank-ask .signup { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; max-width: 32rem; }
.rank-ask .signup label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
}
.rank-ask .signup input[type="email"] {
    flex: 1 1 15rem;
    font: 400 1rem/1.5 var(--sans);
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 12px 14px;
}
.rank-ask .signup input[type="email"]:focus { outline: none; border-color: var(--accent); }
.rank-ask .signup button {
    font: 500 0.95rem/1 var(--sans);
    color: var(--paper);
    background: var(--ink);
    border: 1px solid var(--ink);
    border-radius: 2px;
    padding: 12px 20px;
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease;
}
.rank-ask .signup button:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); }
.rank-ask .signup button:disabled { opacity: 0.55; cursor: default; }
.rank-ask .signup-said { flex: 1 0 100%; margin: 2px 0 0; font-size: 0.88rem; color: var(--muted); }

/* Not a number, so it does not pretend to be one: the word, set small and
   quiet, in the space the numeral would have taken. */
.rank-no.rank-wild {
    font: 500 0.62rem/1.4 var(--sans);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px solid currentColor;
    border-radius: 999px;
    padding: 3px 8px;
    white-space: nowrap;
    justify-self: start;
    /* The number column is 5rem and this is a word, so it is allowed to be
       narrower than the column and to sit at the top of it like a numeral. */
    align-self: start;
}

/* "No. Wildcard" is not a thing. The prefix belongs to numerals only. */
.rank-no.rank-wild::before { content: none; }

.rank-1 h3 { font-size: clamp(2.3rem, 5.5vw, 3.6rem); }

.rank-1 .blurb { font-size: 1.08rem; }

.rank-1::before {
    content: "Top pick";
    grid-column: 2;
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 10px;
}

.rank-1 .rank-no { grid-row: 1 / span 2; }

@media (max-width: 560px) {
    .rank, .rank-1 { grid-template-columns: 1fr; }
    .rank-no { font-size: 1.6rem; margin-bottom: 6px; }
    .rank-1 .rank-no { font-size: 3rem; grid-row: auto; }
    .rank-1::before { grid-column: 1; }
}

/* ------------------------------------------------------------ the opening */

/* The calling card, added by motion.js and removed when it has played, so none
   of this affects a page without JavaScript, and a reader who has asked for
   less motion never sees it at all. */

.cr-intro {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    place-items: center;
    overflow: hidden;
    cursor: pointer;
}

.cr-stage {
    position: relative;
    width: min(62vw, 360px, 38vh);
    perspective: 900px;
    will-change: transform;
}
.cr-zoom .cr-stage {
    transform: translateY(var(--dy)) scale(var(--zoom));
    transition: transform 1.35s cubic-bezier(0.7, 0, 0.25, 1);
}

/* The hole, and the whole trick: an empty element whose enormous spread shadow
   is the paper around it, so the live page shows through here and nowhere
   else. Scaling the stage until this covers the screen is what takes the
   reader through the opening and into the site. */
.cr-hole {
    position: absolute;
    box-shadow: 0 0 0 300vmax var(--paper), inset 0 10px 24px -8px rgba(29, 27, 24, 0.35);
    transition: box-shadow 0.6s ease;
}
.cr-zoom .cr-hole { box-shadow: 0 0 0 300vmax var(--paper), inset 0 0 0 0 transparent; }

.cr-stage > svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/* A panel: a door, a bush. Each is its own element so it can move on its own,
   and carries its own drawing at its own scale. */
.cr-panel {
    position: absolute;
    transition: transform 1.2s cubic-bezier(0.55, 0, 0.2, 1), box-shadow 1.2s ease;
    transform-style: preserve-3d;
}
.cr-panel svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

.cr-intro svg * {
    fill: none;
    stroke: var(--ink);
    stroke-width: 0.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A lobe of a bush: filled with paper so it occludes, stroked like everything
   else, and drawn in its turn. The core is the fill laid over their inner
   halves afterwards - it has no stroke, and is never seen on paper. */
.cr-intro .cr-lobe { fill: var(--paper); }
.cr-intro .cr-core { fill: var(--paper); stroke: none; }

/* Every line draws itself, from its own length, in its own time. */
.cr-intro .cr-draw {
    stroke-dasharray: var(--len);
    stroke-dashoffset: var(--len);
    animation: cr-draw 0.9s cubic-bezier(0.6, 0, 0.3, 1) forwards;
    animation-delay: var(--delay);
}

/* The handle, and the holds: small, and the only things in the accent colour. */
.cr-intro .cr-pull {
    stroke: var(--accent);
    stroke-width: 1.5;
    opacity: 0;
    animation: cr-fade 0.4s ease forwards;
    animation-delay: var(--delay);
}
.cr-intro .cr-mark {
    stroke: var(--accent);
    stroke-width: 1.5;
    opacity: 0;
    transform-origin: center;
    transform-box: fill-box;
    animation: cr-pop 0.34s cubic-bezier(0.2, 1.5, 0.4, 1) forwards;
    animation-delay: var(--delay);
}

.cr-intro text {
    fill: var(--ink);
    stroke: none;
    font: 400 22px var(--serif);
    opacity: 0;
    animation: cr-fade 0.6s ease forwards;
    animation-delay: var(--delay);
}
.cr-intro text.cr-small { font: 500 6.5px var(--sans); letter-spacing: 2.4px; fill: var(--muted); }
.cr-intro .cr-label { transition: opacity 0.4s ease; }
.cr-open .cr-label { opacity: 0; }

@keyframes cr-draw { to { stroke-dashoffset: 0; } }
@keyframes cr-fade { to { opacity: 1; } }
@keyframes cr-pop {
    from { opacity: 0; transform: scale(0.4); }
    to { opacity: 1; transform: scale(1); }
}

/* What is through the opening is drawn at the drawing's scale, so once the
   view starts moving in it would be magnified into smears across the page.
   It has said what it had to say by then; it leaves first. */
.cr-zoom .cr-inside { opacity: 0; transition: opacity 0.45s ease; }

/* Gone: fade whatever is left once the page fills the screen. */
.cr-done { opacity: 0; transition: opacity 0.35s ease; pointer-events: none; }

.cr-skip {
    position: absolute;
    right: 20px;
    bottom: 16px;
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
    transition: opacity 0.3s ease;
}
.cr-open .cr-skip { opacity: 0; }

/* ------------------------------------------------------------- the page */

/* Entries rise as you reach them, one after another rather than all at once,
   so a short list reads as a list rather than a jolt. */
.cr-motion .rank { opacity: 0; transform: translateY(16px); }
.cr-motion .rank.cr-in {
    opacity: 1;
    transform: none;
    transition: opacity 0.7s ease, transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* The hero settles: heading, then line, then buttons. */
.cr-motion .hero h1,
.cr-motion .hero .lede,
.cr-motion .hero .actions { opacity: 0; transform: translateY(12px); }
.cr-ready .hero h1,
.cr-ready .hero .lede,
.cr-ready .hero .actions {
    opacity: 1;
    transform: none;
    transition: opacity 0.8s ease, transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.cr-ready .hero .lede { transition-delay: 0.1s; }
.cr-ready .hero .actions { transition-delay: 0.2s; }

/* Two leaves filling the doorway, hinged on their outer edges, the way the
   cabinet's doors are. */
.cr-door {
    top: 24%;
    width: 35%;
    height: 54.667%;
    background: var(--paper);
}
.cr-door-l { left: 15%; transform-origin: 0 50%; }
.cr-door-r { left: 50%; transform-origin: 100% 50%; }
.cr-open .cr-door-l { transform: rotateY(-112deg); box-shadow: -6px 0 18px rgba(29, 27, 24, 0.12); }
.cr-open .cr-door-r { transform: rotateY(112deg); box-shadow: 6px 0 18px rgba(29, 27, 24, 0.12); }
