/* =============================================================
   Chef Avo — the "tell me what to eat" drawer.

   Deliberately the same object as the School Meals order panel: a
   right-side <dialog> on the same slide, radius and backdrop, so the
   site has one drawer that does several jobs rather than two panels
   that look like they came from different products. What differs is
   only what a chef should differ by — a warmer ground, and the mascot
   at the top instead of a stepper.
   ============================================================= */

.cav{
  position:fixed; top:0; bottom:0; right:0; left:auto; margin:0;
  height:auto; max-height:100dvh; width:clamp(400px,46vw,720px);
  /* Overrides the UA <dialog> max-width:calc(100% - 38px), which otherwise
     leaves a sliver of backdrop down the panel's left edge. */
  max-width:100vw;
  border:none; padding:0; overflow:hidden;
  color:var(--ink); font-family:var(--font-b);
  /* White. It was a green wash, then a cream one, and a tinted ground is the
     one thing a chat window never has: the colour has to come from what is
     said on it, not from behind it. Everything the panel needs to say — whose
     line is whose, which answer is picked — is now said in the foreground. */
  background:#FFFFFF;
  border-radius:28px 0 0 28px;
  box-shadow:-34px 0 90px -30px rgba(40,55,35,.5);
  transform:translateX(100%);
  transition:transform .36s cubic-bezier(.22,.61,.36,1),
             overlay .36s allow-discrete, display .36s allow-discrete;
}
.cav[open]{ transform:translateX(0); }
@starting-style{ .cav[open]{ transform:translateX(100%); } }

.cav::backdrop{
  background:rgba(44,58,46,.45); backdrop-filter:blur(3px);
  opacity:0;
  transition:opacity .36s ease, overlay .36s allow-discrete, display .36s allow-discrete;
}
.cav[open]::backdrop{ opacity:1; }
@starting-style{ .cav[open]::backdrop{ opacity:0; } }

/* Fixed frame: header and footer hold still, only the stage scrolls. A panel
   whose progress bar scrolls away stops telling you how far along you are. */
.cav-in{
  position:relative; display:flex; flex-direction:column;
  height:100%; max-height:100dvh; overflow:hidden;
}
/* One bloom, and only at the very foot of the panel, where the thread runs out
   and there is nothing left to look at. Anything stronger than this is a tint,
   which is what the white is here to be rid of. */
.cav-in::before{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:radial-gradient(62% 30% at 50% 104%, rgba(233,167,116,.16) 0%, transparent 72%);
}
/* Above the blooms. The close button is left out: it is already positioned
   with a z-index of its own, and re-declaring position here would drop it out
   of its corner. */
.cav-head, .cav-thread{ position:relative; z-index:1; }

.cav-close{
  position:absolute; top:16px; right:16px; z-index:5;
  width:38px; height:38px; border-radius:50%; cursor:pointer; line-height:1;
  background:#fff; border:1px solid rgba(110,145,82,.22); color:var(--ink2); font-size:15px;
  box-shadow:0 6px 16px -8px rgba(63,82,54,.4);
  transition:background .15s ease, color .15s ease, transform .2s ease;
}
.cav-close:hover{ background:var(--ink); color:#fff; transform:rotate(90deg); }

/* ---- the chef himself ---------------------------------------- */

.cav-head{
  display:flex; align-items:center; gap:14px;
  padding:22px 68px 16px 26px; flex:none;
  /* A hairline under the header, so the thread scrolls *beneath* something
     instead of the first bubble floating in an open wash of colour. */
  border-bottom:1px solid rgba(90,84,64,.12);
}
.cav-avi{
  position:relative; flex:none;
  width:62px; height:62px; border-radius:50%;
  background:radial-gradient(circle at 50% 40%,#FCFEF9 0%,#EDF6E1 60%,#DDEBCC 100%);
  box-shadow:0 10px 24px -14px rgba(92,74,44,.35);
  display:flex; align-items:flex-end; justify-content:center;
}
/* Slightly oversized and clipped by the disc, so he sits IN the circle rather
   than floating inside it with a ring of empty space. */
.cav-avi-img{
  width:52px; height:auto; display:block; margin-bottom:-2px;
  /* He breathes. A drawn character that holds perfectly still for the whole
     conversation reads as a sticker of a chef rather than one at the pass. */
  animation:cavBob 3.6s ease-in-out infinite;
}
@keyframes cavBob{
  0%,100%{ transform:translateY(0) rotate(0); }
  50%    { transform:translateY(-3px) rotate(-1.5deg); }
}
.cav-hat{
  position:absolute; top:-13px; left:50%; transform:translateX(-46%) rotate(-8deg);
  width:34px; height:auto; filter:drop-shadow(0 3px 5px rgba(44,58,46,.25));
}
.cav-head-t{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.cav-head-t b{ font:700 17px/1 var(--font-b); color:var(--ink); letter-spacing:-.01em; }
/* The same live dot the site's eyebrows wear. It says the kitchen is open and
   somebody is at the pass — a static line of grey text says nothing. */
.cav-live{ display:inline-flex; align-items:center; gap:8px; min-width:0; }
.cav-live i{ font:400 13.5px/1.4 var(--font-b); font-style:normal; color:var(--ink3); }
.cav-dot{
  position:relative; flex:none; width:7px; height:7px;
  border-radius:50%; background:var(--sage2);
}
.cav-dot::after{
  content:""; position:absolute; inset:-4px; border-radius:50%;
  border:1.5px solid var(--sage2); animation:ping 2.2s ease-out infinite;
}

/* ---- the thread ------------------------------------------------
   The whole UI. A chat rather than a wizard, so what has already been said
   stays on screen: every answer the customer gave is still a live control,
   which is what makes "I picked the wrong one" a single tap from anywhere
   rather than a walk backwards through screens. */

/* Block flow, not flex.
   A flex column of flex rows was the obvious build and it fought back: the
   message boxes stopped growing to fit their own option chips and printed on
   top of one another. Ordinary block flow cannot do that — a block is as tall
   as what is inside it, always — and a chat thread is a stack of blocks, which
   is what block layout is for. The avatar is taken out of flow and the bubble
   is indented past it, so nothing has to negotiate a height. */
.cav-thread{
  flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  scroll-behavior:smooth;
  /* The gutter is held open whether or not there is anything to scroll, so the
     thread does not jump sideways the moment Avo's second line makes it
     overflow. 12 of padding plus the 10 of gutter is the 22 down the left. */
  scrollbar-gutter:stable;
  padding:12px 12px 22px 22px;
  /* The first few pixels dissolve instead of being sliced off by the header's
     hairline, so a bubble scrolls *under* the header rather than through it. */
  mask-image:linear-gradient(to bottom, transparent 0, #000 15px);
}

/* The browser's own bar is a grey slab, and on a white panel with rounded
   bubbles that slab was the loudest edge in the drawer. This one is a hairline
   that darkens under the pointer and takes no room of its own. */
.cav-thread{ scrollbar-width:thin; scrollbar-color:rgba(60,92,44,.22) transparent; }
.cav-thread::-webkit-scrollbar{ width:10px; }
.cav-thread::-webkit-scrollbar-track{ background:transparent; }
.cav-thread::-webkit-scrollbar-thumb{
  /* A transparent border with the paint clipped to the content box is how a
     10px-wide bar draws a 4px-wide thumb with air on both sides. */
  background:rgba(60,92,44,.2); background-clip:content-box;
  border:3px solid transparent; border-radius:999px;
}
.cav-thread:hover::-webkit-scrollbar-thumb{ background:rgba(60,92,44,.36); background-clip:content-box; }

.cav-msg{
  position:relative; margin-bottom:12px;
  /* A little overshoot on arrival. A straight fade is how a page loads; a
     bubble that lands with some weight is how a message arrives. */
  opacity:0; transform:translateY(10px) scale(.965);
  transition:opacity .28s ease, transform .42s cubic-bezier(.18,1.35,.4,1);
}
.cav-msg.is-in{ opacity:1; transform:none; }
.cav-msg:last-child{ margin-bottom:0; }

/* Avo speaks left with his face beside him; the customer answers right — the
   arrangement everyone already knows, so nobody has to be told which is which.
   `cav-from`, not `cav-avi`: the header mascot owns that one and sizes itself
   to a 62px disc, which silently sized every message to 62px too. */
.cav-from{ padding-left:39px; }
.cav-you{ display:flex; justify-content:flex-end; }

.cav-face{
  position:absolute; left:0; bottom:0;
  width:30px; height:30px; border-radius:50%; overflow:hidden;
  background:radial-gradient(circle at 50% 38%,#FCFEF9 0%,#EDF6E1 62%,#DCEAC9 100%);
  box-shadow:0 0 0 2px rgba(255,255,255,.9), 0 4px 10px -6px rgba(44,58,46,.5);
  display:flex; align-items:flex-end; justify-content:center;
  font-size:16px; line-height:1;
}
.cav-face img{
  width:26px; height:auto; display:block; margin-bottom:-1px;
  animation:cavBob 4.2s ease-in-out infinite;
}
/* Holds the indent for a control that is Avo's but is not him speaking, and
   for every message after the first in a run — a face on each of four bubbles
   in a row is noise, and every chat app people already use hides it. */
.cav-face-gap{ display:none; }

.cav-stack{ max-width:460px; }
.cav-verdict-msg .cav-stack{ max-width:520px; }

/* inline-block so a bubble hugs its own sentence instead of ruling a line.
   Avo's side is tinted, ringed and lit; the customer's is the dark chip below.
   Two speakers that differ only by which corner is square read as one voice —
   the tint is what makes his lines the thing you look at. */
.cav-b{
  position:relative; overflow:hidden;
  display:inline-block; max-width:100%;
  background:#F4F4F0;
  border:1px solid rgba(90,84,64,.10);
  border-radius:18px 18px 18px 5px; padding:13px 17px;
  font-size:14.5px; line-height:1.55; color:var(--ink);
  /* No shadow and no halo. On white, a soft grey fill is the whole separation
     — a bubble that also floats reads as a card, and the thread becomes a
     stack of cards rather than a conversation. */
  box-shadow:none;
}
.cav-b .cav-note{
  display:block; margin-top:5px; font-size:12.5px; line-height:1.45; color:var(--ink3);
}

/* One sheen across the bubble as it lands, and only then: `is-fresh` is put on
   by script and never printed into the markup, so a repaint of the thread does
   not set forty bubbles shining at once. It is the arrival that is worth
   marking — that is the moment the customer is being answered. */
.cav-b::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(102deg,
    transparent 34%, rgba(255,255,255,.9) 50%, transparent 66%);
  transform:translateX(-130%);
}
.cav-msg.is-fresh .cav-b::after{ animation:cavSheen .85s cubic-bezier(.3,.7,.4,1) .06s 1; }
@keyframes cavSheen{ to{ transform:translateX(130%); } }

/* The cursor at the end of a line still being said. It is the reason the
   typing reads as someone answering rather than the page loading slowly. */
.cav-caret{
  display:inline-block; width:2px; height:1.05em; margin-left:3px;
  vertical-align:-3px; border-radius:1px; background:var(--sage);
  animation:cavCaret .9s steps(1) infinite;
}
@keyframes cavCaret{ 0%,50%{ opacity:1; } 51%,100%{ opacity:0; } }
/* An empty bubble is 2px of caret wide; hold the line's height while it fills
   so the first word does not make the whole thread jump. */
.cav-b.is-streaming{ min-height:calc(1.55em + 26px); }

/* The question's own eyebrow. It comes from the question data, which has
   carried a kicker since the wizard days and printed it nowhere — a line of
   context above "Who am I cooking for?" is what stops a question bubble
   reading like a form label. */
.cav-kicker{
  display:block; margin-bottom:6px;
  font:800 10px/1 var(--font-b); letter-spacing:.15em; text-transform:uppercase;
  color:var(--sage);
}
.cav-q-t{ display:block; font:600 15.5px/1.4 var(--font-b); color:var(--ink); }

/* Typing dots. The pause they fill is deliberate — a verdict that lands the
   instant you tap reads as a lookup table, not as someone thinking. */
.cav-typing{ display:inline-flex; gap:4px; align-items:center; padding:15px 16px; }
.cav-typing i{
  width:6px; height:6px; border-radius:50%; background:var(--sage-c2);
  animation:cavType 1.15s ease-in-out infinite;
}
.cav-typing i:nth-child(2){ animation-delay:.16s; }
.cav-typing i:nth-child(3){ animation-delay:.32s; }
@keyframes cavType{
  0%,60%,100%{ transform:translateY(0); opacity:.45; }
  30%        { transform:translateY(-4px); opacity:1; }
}

/* The customer's own words, and still a button: this is the only way back to an
   earlier answer, so it has to look pressable long after it was pressed. */
.cav-said{
  display:inline-flex; align-items:center; gap:8px; cursor:pointer; text-align:left;
  background:var(--ink); color:#FCF8F1; border:1.5px solid var(--ink);
  border-radius:18px 18px 5px 18px; padding:11px 15px; max-width:85%;
  font:600 14px/1.4 var(--font-b);
  transition:background .18s ease, transform .18s ease;
}
.cav-said:hover{ background:#16210F; transform:translateY(-1px); }
.cav-said:hover .cav-change{ opacity:1; }
.cav-change{
  flex:none;
  font:700 10px/1 var(--font-b); letter-spacing:.1em; text-transform:uppercase;
  opacity:.55; border-bottom:1px solid rgba(252,248,241,.5); padding-bottom:2px;
  transition:opacity .18s ease;
}
/* For screen readers only — "change" alone does not say what it changes. */
.cav-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ---- the answers on offer ---- */

/* A cloud of chips, each as wide as its own words.
   Rows were tried and they were worse: five identical full-width bars for five
   two-word answers is mostly empty box, and a stack of equal rectangles is a
   form however it is styled. Answers of different lengths looking different
   lengths is also the truth — "Rajma & beans" is not the same size of thought
   as "Lunch at the gate by school time", and the long ones take their own line
   without being told to. */
.cav-opts{ display:flex; flex-wrap:wrap; gap:9px; margin-top:10px; }
/* --oc is the answer's own colour, set inline by script from the route that
   answer leads to: butter for the school gate, lilac for a desk. It is the
   site's existing code — the same two colours the Home route diagram uses —
   so the first question is colour, not another column of pale green. Answers
   that lead nowhere new keep the house sage. */
.cav-opt{
  --oc:var(--sage);
  position:relative; display:inline-flex; align-items:center;
  gap:10px; cursor:pointer; text-align:left; max-width:100%;
  padding:8px 15px 8px 8px; border-radius:999px;
  /* The one thing on this panel that is meant to be pressed, so on a white
     ground it keeps the border and the lift that say so. */
  background:#fff; border:1.5px solid rgba(60,92,44,.22); color:var(--ink);
  box-shadow:0 4px 14px -8px rgba(44,58,46,.22);
  transition:border-color .18s ease, background .18s ease,
             transform .18s ease, box-shadow .18s ease;
}
/* Each chip lands just after the one before it, left to right, so the set
   arrives as a handful of answers rather than a block appearing. --i is the
   chip's place in the row, set inline by script.
   Hung off `is-fresh`, which script adds only to a message that has just
   arrived: the thread is rebuilt from scratch on every tap, so an animation on
   the chip itself would replay the whole stagger each time a box was ticked.
   And `backwards`, not `both` — a filled-forwards transform outranks the
   declarations under it, which would have left the chips unable to lift on
   hover for the rest of the conversation. */
.cav-msg.is-fresh .cav-opt{
  animation:cavChip .34s cubic-bezier(.2,1.3,.4,1) backwards;
  animation-delay:calc(var(--i,0) * 45ms);
}
@keyframes cavChip{
  from{ opacity:0; transform:translateY(6px) scale(.94); }
  to  { opacity:1; transform:none; }
}
/* A chip carrying a second line cannot be a pill without looking like a
   swollen one, so it squares off a little and lets its text breathe. */
.cav-opt:has(.cav-opt-txt i){ border-radius:20px; padding:9px 17px 9px 9px; }
.cav-opt:has(.cav-opt-txt i) .cav-opt-ic{ width:38px; height:38px; font-size:19px; }
.cav-opt:hover{
  transform:translateY(-2px) scale(1.012);
  border-color:color-mix(in srgb, var(--oc) 48%, transparent);
  background:color-mix(in srgb, var(--oc) 5%, #fff);
  box-shadow:0 14px 24px -16px color-mix(in srgb, var(--oc) 55%, transparent);
}
.cav-opt.is-on{
  border-color:var(--oc);
  background:color-mix(in srgb, var(--oc) 9%, #fff);
}

/* The emoji in a disc with a ring — the same icon language as the route stops
   on Home. A bare glyph beside text is the default nobody chose; the disc is
   what makes it look drawn for this. */
.cav-opt-ic{
  flex:none; display:grid; place-items:center;
  width:32px; height:32px; border-radius:50%;
  font-size:17px; line-height:1;
  background:radial-gradient(circle at 50% 32%,
    #FFFFFF 0%,
    color-mix(in srgb, var(--oc) 9%, #fff) 62%,
    color-mix(in srgb, var(--oc) 20%, #fff) 100%);
  box-shadow:inset 0 0 0 1.5px color-mix(in srgb, var(--oc) 32%, transparent),
             0 4px 9px -7px rgba(44,58,46,.7);
  transition:box-shadow .18s ease, transform .3s cubic-bezier(.2,1.5,.4,1);
}
/* A small tilt-and-grow on hover. The disc is the only thing in the row that
   can move without shifting the words, and a menu whose pictures react is the
   difference between a list and something worth tapping. */
.cav-opt:hover .cav-opt-ic{ transform:scale(1.12) rotate(-6deg); }
.cav-opt.is-on .cav-opt-ic{
  box-shadow:inset 0 0 0 2px var(--oc), 0 4px 9px -7px rgba(44,58,46,.7);
}

.cav-opt-txt{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.cav-opt-txt b{ font:600 14.5px/1.3 var(--font-b); }
.cav-opt-txt i{ font:400 12.2px/1.35 var(--font-b); font-style:normal; color:var(--ink3); }

/* A tick on the picked ones, and only where one can survive being tapped: a
   single-choice answer turns into the customer's own bubble in the same beat,
   so its tick would appear and be gone in one frame. Hidden rather than not
   printed, so both lists have the same row and line up the same way. */
.cav-opts:not(.is-multi) .cav-opt-tick{ display:none; }
.cav-opt-tick{
  flex:none; width:21px; height:21px; border-radius:50%;
  display:grid; place-items:center;
  background:var(--oc); color:#fff; font-size:11px; line-height:1;
  opacity:0; transform:scale(.5);
  transition:opacity .16s ease, transform .26s cubic-bezier(.2,1.6,.4,1);
}
.cav-opt.is-on .cav-opt-tick{ opacity:1; transform:none; }

/* No arrow on the single-choice rows. One was added and it put the wizard
   straight back: an arrow on the right of a row is a Next button, and a Next
   button is the thing this drawer stopped being. Tapping an answer is a reply,
   not a step forward. */

.cav-next{
  margin-top:8px; padding:11px 20px; border-radius:999px; cursor:pointer;
  background:var(--ink); color:var(--cream); border:none;
  font:700 13.5px/1 var(--font-b);
  transition:transform .18s ease, opacity .18s ease;
}
.cav-next:hover:not(:disabled){ transform:translateY(-2px); }
.cav-next:disabled{ opacity:.35; cursor:not-allowed; }

/* A pill rather than an underlined word: it sits between two of Avo's bubbles,
   where an underline reads as a link inside what he just said. */
.cav-againbtn{
  margin:2px 0 4px; display:inline-flex; align-items:center; gap:8px; cursor:pointer;
  background:#fff; border:1.5px solid var(--sage-c1); padding:9px 16px 9px 10px;
  border-radius:999px; font:600 13.5px/1 var(--font-b); color:var(--sage-d);
  box-shadow:0 6px 16px -14px rgba(44,58,46,.6);
  transition:border-color .18s ease, transform .18s ease;
}
.cav-againbtn:hover{ border-color:var(--sage); transform:translateY(-2px); }
.cav-againbtn span{
  display:grid; place-items:center; flex:none;
  width:24px; height:24px; border-radius:50%;
  background:var(--band); color:var(--sage); font-size:13px; line-height:1;
}

/* ---- the verdict ------------------------------------------------ */

.cav-verdict-msg{ max-width:100%; }
/* The payoff of the whole conversation, so it is framed rather than being one
   more white box: a band of the dish's own accent across the top, the colour
   it already wears on the Bowls page. */
/* The one thing in the thread that is not a line of talk, so it is the one
   thing that is a card: white against his grey bubbles, with an edge and a
   lift the talk does not get. */
.cav-card{
  padding:20px 18px 18px; border-radius:18px 18px 18px 5px;
  background:#fff; border:1px solid rgba(60,92,44,.16);
  box-shadow:0 18px 34px -26px rgba(44,58,46,.75);
}
.cav-card::before{
  content:""; position:absolute; top:0; left:0; right:0; height:4px;
  background:linear-gradient(90deg,
    var(--acc) 0%, color-mix(in srgb, var(--acc) 45%, #fff) 100%);
}
.cav-lead{
  display:block; margin-bottom:12px;
  font:800 10.5px/1 var(--font-b); letter-spacing:.14em; text-transform:uppercase;
  color:var(--peach-d);
}
.cav-dish-name{
  display:block; font:600 22px/1.15 var(--font-d);
  color:var(--ink); letter-spacing:-.01em; margin-bottom:6px;
}
/* The way back out of a suggestion you do not want. Says what to do rather
   than leaving the customer to discover that their answers are tappable. */
.cav-tweak{
  margin:16px 0 0; padding-top:13px; border-top:1px solid rgba(60,92,44,.14);
  font-size:12.5px; line-height:1.5; color:var(--ink3);
}
.cav-warn{
  font-size:13.5px; line-height:1.5; color:var(--peach-d);
  background:#FCEFE5; border-radius:12px; padding:11px 14px; margin:8px 0 16px;
}

.cav-dish{
  display:flex; align-items:center; gap:14px; margin:0 0 14px;
  padding:0;
}
/* --acc is the dish's own accent, set inline from its CPT meta, so the ring
   round its picture matches the colour it wears on the Bowls page. */
.cav-dish-pic{
  flex:none; width:86px; height:86px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; overflow:hidden;
  background:radial-gradient(circle at 50% 42%,#FCFEF9 0%,#F1F8E8 60%,#E4EFD6 100%);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 26%, transparent);
}
.cav-dish-pic img{ width:100%; height:100%; object-fit:contain; display:block; }
.cav-dish-b{ min-width:0; }
.cav-dish-tag{
  display:inline-block; margin-bottom:7px;
  font:700 10.5px/1 var(--font-b); letter-spacing:.12em; text-transform:uppercase;
  color:var(--acc); background:color-mix(in srgb, var(--acc) 13%, #fff);
  padding:6px 10px; border-radius:999px;
}
.cav-dish-b p{ margin:0; font-size:14.5px; line-height:1.55; color:var(--ink2); }

.cav-why{
  border-left:3px solid var(--sage-c1); padding:2px 0 2px 15px; margin:0 0 16px;
}
.cav-why-h{
  display:block; font:800 11px/1 var(--font-b);
  letter-spacing:.14em; text-transform:uppercase; color:var(--sage); margin-bottom:8px;
}
.cav-why ul{ margin:0; padding:0; list-style:none; display:flex; flex-wrap:wrap; gap:7px; }
.cav-why li{
  font:600 13px/1 var(--font-b); color:var(--ink2);
  background:var(--band); padding:8px 12px; border-radius:999px;
}

.cav-perks{ margin:0 0 18px; padding:0; list-style:none; display:grid; gap:8px; }
.cav-perks li{
  display:flex; gap:9px; align-items:flex-start;
  font-size:13.5px; line-height:1.5; color:var(--ink3);
}
.cav-perks li b{ color:var(--ink2); font-weight:600; }
.cav-perks li > span:last-child{ min-width:0; }
/* The same disc as the option rows, half the size. A row of bare emoji down
   the left of the card was the one place the verdict still looked typed out
   rather than laid out. */
.cav-perks .cav-perk-ic{
  flex:none; display:grid; place-items:center; margin-top:-2px;
  width:26px; height:26px; border-radius:50%;
  font-size:13px; line-height:1;
  background:radial-gradient(circle at 50% 34%,#FFFFFF 0%,#F5FAEC 66%,#E9F3D9 100%);
  box-shadow:inset 0 0 0 1.2px rgba(96,140,66,.2);
}
/* Nudged down to sit on the text's midline rather than its cap height. */
.cav-perk-dot{
  flex:none; width:6px; height:6px; margin-top:7px; border-radius:50%;
  background:var(--sage-c2);
}

/* The ask he could not meet. Quieter than the reasons above it — it is an
   admission, not a selling point — but it has to be legible enough to read
   before the button underneath is pressed. */
.cav-miss{
  display:flex; gap:9px; align-items:flex-start; margin:0 0 16px;
  font-size:13px; line-height:1.5; color:var(--ink3);
  background:#FAF7F0; border-radius:12px; padding:11px 14px;
}

.cav-carry{
  display:flex; gap:8px; align-items:flex-start; margin:0 0 18px;
  font-size:13px; line-height:1.5; color:var(--sage-d);
  background:#F1F7E6; border-radius:12px; padding:11px 14px;
}

/* What else can go in. Deliberately quieter than the Add button below it and
   louder than the pass line under that: it is an offer, not the point of the
   card, and it has to be readable before the price on the button changes. */
.cav-offer{ margin:0 0 16px; }
.cav-offer-h{
  display:block; margin-bottom:8px;
  font:800 10.5px/1 var(--font-b); letter-spacing:.13em; text-transform:uppercase;
  color:var(--ink3);
}
.cav-offer-row{ display:flex; flex-wrap:wrap; gap:7px; }
.cav-xtra{
  display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  padding:7px 12px 7px 8px; border-radius:999px;
  background:#fff; border:1.5px solid rgba(60,92,44,.2); color:var(--ink);
  font:600 13px/1 var(--font-b);
  transition:border-color .18s ease, background .18s ease, transform .18s ease;
}
.cav-xtra:hover{ transform:translateY(-1px); border-color:var(--sage-c2); }
.cav-xtra.is-on{ border-color:var(--sage); background:#F4F9EC; }
.cav-xtra-ic{
  display:grid; place-items:center; flex:none;
  width:24px; height:24px; border-radius:50%; font-size:14px; line-height:1;
  background:radial-gradient(circle at 50% 34%,#FFFFFF 0%,#F5FAEC 66%,#E9F3D9 100%);
  box-shadow:inset 0 0 0 1.2px rgba(96,140,66,.2);
}
/* The price stays visible in both states: the chip is not redrawn when it is
   ticked, so its face has to read true either way. */
.cav-xtra-p{ color:var(--ink3); font-weight:600; }
.cav-xtra.is-on .cav-xtra-p{ color:var(--sage-d); }
/* "Goes well with" — the same chip minus the icon: a pairing is another dish,
   not a spoonful of something. Some are links (a dish that has to be asked
   something on its own page first), so the underline comes off. */
.cav-pair{ padding-left:12px; text-decoration:none; }
.cav-pair.is-on{ cursor:default; }
.cav-pair.is-on > span:first-child{ color:var(--sage-d); font-weight:800; }

.cav-actions{ display:flex; flex-wrap:wrap; gap:11px; align-items:center; }
.cav-add{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  padding:16px 30px; border-radius:999px; cursor:pointer; border:none;
  background:var(--ink); color:var(--cream); font:700 15.5px/1 var(--font-b);
  transition:background .18s ease, transform .18s ease;
}
.cav-add:hover{ background:#16210F; transform:translateY(-2px); }
.cav-add.is-added{ background:var(--sage2); }
.cav-add:disabled{ cursor:default; transform:none; }
.cav-swap{
  background:none; border:none; cursor:pointer; padding:8px 2px;
  font:600 13.5px/1 var(--font-b); color:var(--ink3);
  border-bottom:1.5px solid rgba(60,92,44,.25);
}
.cav-swap:hover{ color:var(--ink); border-bottom-color:var(--ink); }

.cav-pass{
  margin:18px 0 0;
  font-size:13px; line-height:1.55; color:var(--ink3);
}
.cav-pass > span:first-child{ margin-right:5px; }
.cav-pass a{ color:var(--sage); border-bottom:1.5px solid var(--sage-c1); }

.cav-restart{
  display:block; margin:22px auto 4px; background:none; border:none; cursor:pointer;
  font:600 13px/1 var(--font-b); color:var(--ink3); padding:8px;
}
.cav-restart:hover{ color:var(--ink); }

.cav-sorry{ padding-top:20px; }

/* ---- phones ------------------------------------------------------ */

@media (max-width:760px){
  .cav{ width:100vw; border-radius:22px 0 0 0; }
  .cav-head{ padding:18px 62px 12px 18px; }
  /* Phone scrollbars overlay the content and take no gutter, so the padding
     goes back to even. */
  .cav-thread{ padding:10px 16px calc(18px + env(safe-area-inset-bottom)); }
  /* A phone needs the width more than the inset. */
  .cav-from{ padding-left:0; }
  .cav-face{ display:none; }
  .cav-stack{ max-width:100%; }
  .cav-actions{ flex-direction:column; align-items:stretch; }
  .cav-add{ width:100%; }
}

/* Motion is decoration here; the panel works identically without it. */
@media (prefers-reduced-motion:reduce){
  .cav, .cav::backdrop, .cav-msg, .cav-opt, .cav-opt-ic, .cav-add, .cav-next, .cav-said{ transition:none; }
  .cav-typing i, .cav-dot::after, .cav-avi-img, .cav-face img, .cav-caret,
  .cav-msg.is-fresh .cav-opt{ animation:none; }
  .cav-typing i{ opacity:.6; }
  .cav-msg.is-fresh .cav-b::after{ animation:none; }
  .cav-msg{ opacity:1; transform:none; }
  .cav-thread{ scroll-behavior:auto; }
}

/* The choice Avo made on the customer's behalf. Given its own line rather than
   folded into the reason chips: "with paneer, not egg" is a fact about what
   arrives, not a reason it was picked. */
.cav-chose{
  display:flex; gap:9px; align-items:baseline; margin:0 0 16px;
  font-size:13.5px; line-height:1.5; color:var(--sage-d);
  background:#F1F7E6; border-radius:12px; padding:11px 14px;
}
.cav-chose b{ font-weight:700; color:var(--ink); }
