/* ==========================================================================
   Student Sweet Spot · October 2026
   Campaign-only layer. Loads AFTER styles.css and adds nothing to the house
   sheet. Every colour here is an existing token or a value lifted straight
   off the printed Edinburgh menu (the Chocometer ramp, the copper prices).

   A campaign is a change of message, not a change of brand. The three new
   components below are:
     .manifesto   the menu's own opening question, set as type
     .chocometer  their printed intensity scale, made operable
     .picks       Dolci Bear's picks, filtered by how long you have
   ========================================================================== */

:root{
  /* the Chocometer ramp, read off pp.32-33 of the menu */
  --cm-01:#f3e8d2;
  --cm-02:#e6c795;
  --cm-03:#a86f3c;
  --cm-04:#57311e;
  --cm-05:#1d1009;
  /* prices are copper on the printed menu, not body colour */
  --copper:#b87a46;
}

/* --- shared campaign atoms ------------------------------------------------ */

.badge{
  display:inline-block;font-size:.5rem;letter-spacing:.2em;text-transform:uppercase;
  padding:.3rem .5rem;border:1px solid var(--gold);color:var(--gold);
  line-height:1;white-space:nowrap;vertical-align:middle;
}
.badge.solid{background:var(--gold);color:#3d1421;border-color:var(--gold)}
.badge.diet{border-color:rgba(94,33,48,.3);color:var(--muted);letter-spacing:.14em}
.badge.veg{border-color:#6e9a3e;color:#5c8433}
.badge-row{display:flex;flex-wrap:wrap;gap:.35rem;justify-content:center}

.price{
  font-family:'Cormorant Garamond',Georgia,serif;font-size:1.5rem;
  color:var(--copper);font-variant-numeric:tabular-nums;line-height:1;
}

/* =====================================================================
   MANIFESTO · the menu's first page, animated
   Their own words. The question is the whole campaign, so it gets the
   room a headline would get and nothing competes with it.
   ===================================================================== */

.manifesto{text-align:center;position:relative;overflow:hidden}
.manifesto .q{
  font-family:'Cormorant Garamond',Georgia,serif;font-weight:300;
  font-size:clamp(2.2rem,1rem + 5.4vw,5rem);line-height:1.04;
  color:var(--burgundy);letter-spacing:-.015em;text-wrap:balance;
}
.manifesto .q em{font-style:italic;color:var(--gold)}
/* each word rises on its own, staggered by --i from the script */
/* The word box has to clip VERTICALLY so the rise comes up out of nothing,
   but `overflow:hidden` clips horizontally too, and a Cormorant italic leans
   past its own advance width · which is why the question mark on "last?" was
   losing its right-hand side. The padding widens the clip box on both sides
   and the negative margin gives the width straight back, so the glyph is
   inside the box and the line sets exactly as it did before. */
.manifesto .w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-inline:.14em;margin-inline:-.14em;
}
.manifesto .w > span{
  display:inline-block;transform:translateY(102%);
  transition:transform .9s var(--slow);transition-delay:calc(var(--i,0) * 70ms);
}
.manifesto.in .w > span{transform:none}
.manifesto .answer{
  margin-top:clamp(1.6rem,3vw,2.4rem);
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:clamp(1.15rem,1rem + .8vw,1.6rem);color:var(--ink-soft);
}
.manifesto .turn{
  margin-top:clamp(2rem,4vw,3rem);padding-top:clamp(1.6rem,3vw,2.2rem);
  border-top:1px solid var(--line);
  display:grid;gap:1.1rem;justify-items:center;
}
.manifesto .turn p{max-width:46ch;color:var(--ink-soft)}
@media(prefers-reduced-motion:reduce){
  .manifesto .w > span{transform:none}
}

/* =====================================================================
   CHOCOMETER · the one true infographic in their menu, made operable
   Five cups, one scale, ivory to midnight. The section ground travels the
   ramp with the selection, so the page itself gets darker as the cup does.
   ===================================================================== */

.chocometer{
  --ground:var(--cm-01);
  --fg:#3b2318;
  --fg-soft:rgba(59,35,24,.72);
  --hair:rgba(59,35,24,.2);
  background:var(--ground);color:var(--fg);
  /* no transition · campaign.js interpolates these per frame and a CSS
     transition on top of that is exactly what made it feel glitchy */
  overflow:hidden;
}
.chocometer .kicker,.chocometer .label{color:var(--fg-soft)}
.chocometer .h2,.chocometer .title{color:var(--fg)}
.chocometer .h2 em{color:inherit;opacity:.72}

.cm-grid{
  display:grid;gap:clamp(2rem,5vw,4rem);align-items:center;
  grid-template-columns:1fr;
}
@media(min-width:900px){
  .cm-grid{grid-template-columns:auto minmax(0,1fr) minmax(0,.9fr)}
}

/* --- the rail --- */
/* phones: the scale lies down, bar above a row of numbers.
   900px up: it stands up, a vertical bar beside a column of names. */
.cm-rail{
  position:relative;display:flex;gap:1rem;
  flex-direction:column;align-items:stretch;
}
@media(min-width:900px){
  .cm-rail{flex-direction:row;height:340px;gap:1.2rem}
}

.cm-bar{
  position:relative;flex:0 0 auto;
  width:100%;height:10px;
  background:linear-gradient(90deg,var(--cm-01),var(--cm-02) 26%,var(--cm-03) 52%,var(--cm-04) 78%,var(--cm-05));
  box-shadow:inset 0 0 0 1px var(--hair);
}
@media(min-width:900px){
  .cm-bar{
    width:10px;height:100%;
    background:linear-gradient(180deg,var(--cm-01),var(--cm-02) 26%,var(--cm-03) 52%,var(--cm-04) 78%,var(--cm-05));
  }
}
/* the travelling marker */
.cm-dot{
  position:absolute;width:20px;height:20px;border-radius:50%;
  background:var(--ground);box-shadow:0 0 0 1.5px var(--fg);
  top:50%;left:0;transform:translate(-50%,-50%);
}
@media(min-width:900px){
  .cm-dot{left:50%;top:0}
}

.cm-ticks{
  display:flex;flex-direction:row;justify-content:space-between;
  flex:1 1 auto;gap:.3rem;min-width:0;
}
@media(min-width:900px){
  .cm-ticks{flex-direction:column;justify-content:space-between;height:100%}
}

.cm-tick{
  display:flex;align-items:center;gap:.7rem;cursor:pointer;
  background:none;border:0;padding:.35rem 0;text-align:left;
  color:var(--fg-soft);transition:color .5s var(--ease),opacity .5s;
  font-family:'Jost',sans-serif;
}
.cm-tick i{
  font-style:normal;font-family:'Cormorant Garamond',Georgia,serif;
  font-size:.86rem;letter-spacing:.1em;opacity:.7;
}
.cm-tick b{
  font-weight:400;font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;
  white-space:nowrap;
}
@media(max-width:899px){ .cm-tick b{display:none} .cm-tick{justify-content:center} }
.cm-tick:hover{color:var(--fg)}
.cm-tick[aria-selected="true"]{color:var(--fg)}
.cm-tick[aria-selected="true"] i{opacity:1}
.cm-tick[aria-selected="true"] b{letter-spacing:.24em}
.cm-tick:focus-visible{outline:2px solid currentColor;outline-offset:3px}

/* --- the cup · see THE SHEET at the foot of this file --- */
.cm-cup{position:relative;aspect-ratio:1;max-width:430px;margin-inline:auto;width:100%}

/* --- the readout --- */
.cm-read{display:grid;gap:.9rem;min-height:15rem;align-content:start}
.cm-read .n{
  font-family:'Cormorant Garamond',Georgia,serif;font-size:3.4rem;line-height:.9;
  opacity:.34;
}
.cm-read h3{
  font-family:'Cormorant Garamond',Georgia,serif;font-weight:400;
  font-size:clamp(1.6rem,1.2rem + 1.5vw,2.4rem);line-height:1.1;color:var(--fg);
}
.cm-read .tag{
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:1.15rem;color:var(--fg-soft);
}
.cm-read p{color:var(--fg-soft);font-size:.96rem;max-width:34ch}
/* NB: not .foot · that is the site footer and it would paint this burgundy */
.cm-foot{
  margin-top:.5rem;padding-top:1rem;border-top:1px solid var(--hair);
  display:flex;align-items:baseline;gap:1rem;flex-wrap:wrap;
}
.cm-read .price{color:inherit;opacity:.9}
.chocometer .badge{border-color:currentColor;color:inherit;opacity:.8}
/* the swap itself · fade the words, do not slide them */
.cm-read.swap{opacity:0;transition:opacity .28s ease}
.cm-read{opacity:1;transition:opacity .5s ease .12s}

.cm-note{
  margin-top:clamp(2rem,4vw,3rem);padding-top:1.4rem;border-top:1px solid var(--hair);
  display:flex;flex-wrap:wrap;gap:.6rem 2rem;justify-content:space-between;align-items:center;
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--fg-soft);
}

/* =====================================================================
   PICKS · Dolci Bear's, filtered by how long you actually have
   Three honest student states. The filter is the interaction; the plates
   are the house .plate component with a price and the menu's own badges.
   ===================================================================== */

.filters{
  display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;
  margin-top:clamp(1.6rem,3vw,2.4rem);
}
.filter{
  border:1px solid var(--line);background:transparent;color:var(--ink-soft);
  padding:.7rem 1.3rem;cursor:pointer;
  font-size:.64rem;letter-spacing:.2em;text-transform:uppercase;
  transition:border-color .45s var(--ease),color .45s var(--ease),background .45s var(--ease);
}
.filter:hover{border-color:var(--gold);color:var(--burgundy)}
.filter[aria-pressed="true"]{background:var(--burgundy);border-color:var(--burgundy);color:var(--linen)}
.filter:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.filter small{display:block;font-size:.58rem;letter-spacing:.1em;opacity:.62;margin-top:.25rem;text-transform:none}

.picks{margin-top:clamp(1.8rem,3.5vw,2.6rem)}
/* three per filter, so three across once there is room for them */
@media(min-width:980px){.plates.picks{grid-template-columns:repeat(3,1fr)}}
.picks .plate-art{max-width:215px}
/* captions run to one or two lines depending on the dish · give them a fixed
   bed so the three cards keep their baselines and nothing rides up into the
   illustration above it */
.picks .cap-ital{
  margin-top:1.2rem;min-height:3.1em;
  display:flex;align-items:flex-start;justify-content:center;
}
.picks .plate{cursor:default}
.picks .plate:hover{transform:translateY(-6px)}
/* leaving the filter · collapse out, then back in. No layout jump. */
.pick{transition:opacity .45s var(--ease),transform .55s var(--slow)}
.pick.out{opacity:0;transform:translateY(14px) scale(.98);pointer-events:none}
.pick[hidden]{display:none!important}
.pick-head{display:flex;align-items:baseline;justify-content:center;gap:.7rem;flex-wrap:wrap}
.pick .badge-row{margin-top:.7rem}
.pick .plate-meta{margin-top:.9rem}

/* =====================================================================
   CAPTURE · the point of the campaign
   ===================================================================== */

.capture{
  border:1px solid rgba(176,141,79,.42);background:var(--linen);
  padding:clamp(1.5rem,3.4vw,2.6rem);
}
.on-dark .capture{background:#fdfbf6;color:#4f403a}
.cap-grid{display:grid;gap:1rem}
@media(min-width:620px){.cap-grid.two{grid-template-columns:1fr 1fr}}
.capture label{
  display:block;font-size:.6rem;letter-spacing:.24em;text-transform:uppercase;
  color:#93857b;margin-bottom:.5rem;
}
.capture input,.capture select{
  width:100%;padding:.9rem 1.05rem;border:1px solid rgba(94,33,48,.18);
  background:#f6f0e5;color:#4f403a;font:inherit;font-size:.98rem;border-radius:0;
  transition:border-color .3s var(--ease);
}
.capture select{
  appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,#93857b 50%),linear-gradient(135deg,#93857b 50%,transparent 50%);
  background-position:calc(100% - 19px) 51%,calc(100% - 14px) 51%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;
  background-color:#f6f0e5;
}
.capture input:focus,.capture select:focus{outline:none;border-color:var(--gold)}
.consent{
  display:flex;gap:.8rem;align-items:flex-start;
  font-size:.82rem;line-height:1.55;color:#6d5c54;
}
.consent input{width:auto;flex:0 0 auto;margin-top:.3rem;accent-color:#5e2130}
.cap-msg{margin-top:1rem;font-size:.86rem;min-height:1.2rem}
.cap-msg.err{color:#a8412c}
.cap-msg.ok{color:#4a6b3a}
.capture .done{display:grid;gap:1rem;justify-items:start}
.capture .done .h3{color:#5e2130}

/* =====================================================================
   BEAR · the mascot line, set as a quote the way the menu sets them
   ===================================================================== */

.bear-quote{
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:clamp(1.2rem,1rem + 1.1vw,1.9rem);line-height:1.35;
  color:var(--muted);text-wrap:balance;max-width:26ch;
}
.bear-quote cite{
  display:block;margin-top:.9rem;font-style:normal;font-family:'Jost',sans-serif;
  font-size:.6rem;letter-spacing:.28em;text-transform:uppercase;color:var(--gold);
}

/* =====================================================================
   COUNTDOWN · real dates only. October is a real deadline.
   ===================================================================== */

.runs{
  display:flex;flex-wrap:wrap;gap:.8rem 2.6rem;align-items:baseline;
  margin-top:1.6rem;padding-top:1.4rem;border-top:1px solid var(--line);
}
.runs div{display:grid;gap:.3rem}
.runs dt,.runs .k{font-size:.58rem;letter-spacing:.24em;text-transform:uppercase;color:var(--muted)}
.runs .v{
  font-family:'Cormorant Garamond',Georgia,serif;font-size:1.5rem;
  color:var(--burgundy);line-height:1;font-variant-numeric:tabular-nums;
}

/* --- hero tweaks for this campaign only ----------------------------------- */
.hero-offer{
  display:inline-flex;align-items:baseline;gap:.6rem;flex-wrap:wrap;
  margin-top:1.4rem;padding:.75rem 1.2rem;
  border:1px solid rgba(210,181,133,.5);
  color:#f7efe6;font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
}
.hero-offer b{
  font-family:'Cormorant Garamond',Georgia,serif;font-weight:400;
  font-size:1.5rem;letter-spacing:0;color:var(--gold-lite);line-height:1;
}

/* --- the config flag, visible to us and nobody else ----------------------- */
.build-note{
  background:#3d1421;color:rgba(247,239,230,.8);
  font-size:.68rem;letter-spacing:.06em;line-height:1.6;
  padding:.9rem 0;
}
.build-note b{color:var(--gold-lite);font-weight:400}

@media(prefers-reduced-motion:reduce){
  .chocometer,.cm-dot,.cm-cup video,.cm-cup img,.pick{transition-duration:.01ms!important}
}

/* ==========================================================================
   THE INTERACTIVE LAYER
   Splat canvas, the melt, 3D plates, the profiler and the topping drop.
   Paired with fx.js. Everything here degrades to a still, readable page
   with motion off · none of it is load-bearing for the offer.
   ========================================================================== */

/* --- the pigment canvas ---------------------------------------------------
   Under the nav and the dock so controls stay crisp, over everything else.
   multiply, because watercolour darkens where it overlaps and screen would
   make it glow like neon, which is the wrong century for this brand. */
.fx-splat{
  position:fixed;inset:0;z-index:95;
  /* canvas is a replaced element · inset:0 alone leaves it at its intrinsic
     300x150, so the size has to be stated */
  width:100%;height:100%;
  pointer-events:none;
  /* NO mix-blend-mode, and display:none rather than opacity:0 when idle.
     A full-viewport blended layer makes the compositor re-blend the entire
     page on every scroll frame, and even a transparent one keeps a
     1440x900 layer alive that has to be re-composited. Measured, this alone
     was blowing one frame in ten while scrolling. The multiply now happens
     INSIDE the canvas via globalCompositeOperation, which is free. */
  display:none;
}
.fx-splat.live{display:block}

/* =====================================================================
   THE MELT · a chocolate pour driven by scroll position
   --p runs 0 to 1 as the block crosses the viewport.
   ===================================================================== */

.melt{
  position:relative;
  height:clamp(240px,32vw,420px);
  overflow:hidden;
  background:var(--ivory);
  isolation:isolate;
}
.melt.on-blush{background:var(--blush)}
.melt.on-egg{background:var(--egg)}

/* fx.js paints the wash · the canvas carries the whole thing */
.melt-canvas{position:absolute;inset:0;width:100%;height:100%;display:block}

.melt-in{
  position:absolute;inset:auto 0 0;z-index:3;
  text-align:center;padding:0 20px clamp(1.1rem,2.6vw,1.9rem);
  color:var(--burgundy);
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:clamp(1.05rem,.9rem + .9vw,1.55rem);
  pointer-events:none;
}

/* no motion · a short painted band rather than a dead gap */
.melt.static{height:clamp(90px,10vw,130px)}
.melt.static::after{
  content:"";position:absolute;left:0;right:0;top:0;height:54%;
  background:linear-gradient(178deg,#4a2617,#2b1410);
}

/* =====================================================================
   3D PLATES · the pointer separates the layers
   ===================================================================== */

.tilt-stage{perspective:1000px}
.tilt{
  --rx:0deg; --ry:0deg; --gx:50%; --gy:50%;
  transform-style:preserve-3d;
  /* the perspective lives on the card, not the grid · a shared vanishing
     point makes the outer cards shear away from the viewer */
  transform:perspective(1000px) rotateX(var(--rx)) rotateY(var(--ry));
  transition:transform .7s var(--slow),box-shadow .7s var(--ease);
}
.tilt.is-tilting{transition:transform .12s linear,box-shadow .4s var(--ease)}
.tilt [data-depth]{
  transition:transform .7s var(--slow);
  will-change:transform;
}
.tilt.is-tilting [data-depth]{transition:transform .12s linear}

/* the watercolour bloom that sits behind the dish and moves least */
.tilt-splat{
  position:absolute;left:50%;top:44%;width:86%;aspect-ratio:1;
  transform:translate(-50%,-50%);
  background:
    radial-gradient(ellipse 44% 38% at 32% 40%,rgba(184,122,70,.2),transparent 62%),
    radial-gradient(ellipse 38% 44% at 68% 56%,rgba(94,33,48,.16),transparent 64%),
    radial-gradient(ellipse 30% 30% at 54% 28%,rgba(176,141,79,.2),transparent 66%);
  pointer-events:none;z-index:0;
  opacity:0;transition:opacity .6s var(--ease);
}
.tilt.is-tilting .tilt-splat{opacity:1}

/* a glare that tracks the pointer across the card face */
.tilt-glare{
  position:absolute;inset:0;z-index:5;pointer-events:none;
  background:radial-gradient(38% 38% at var(--gx) var(--gy),rgba(255,248,236,.5),transparent 70%);
  opacity:0;transition:opacity .5s var(--ease);
  mix-blend-mode:soft-light;
}
.tilt.is-tilting .tilt-glare{opacity:1}
.tilt.is-tilting{box-shadow:0 34px 60px -34px rgba(61,20,33,.5)}
.picks .plate.tilt:hover{transform:rotateX(var(--rx)) rotateY(var(--ry))}
.tilt > *:not(.tilt-splat):not(.tilt-glare){position:relative;z-index:2}

/* =====================================================================
   THE FLAVOUR PROFILER
   ===================================================================== */

.pf-grid{display:grid;gap:clamp(2rem,4.5vw,3.6rem);align-items:start}
@media(min-width:900px){.pf-grid{grid-template-columns:1fr 1fr}}

.pf-controls{display:grid;gap:clamp(1.4rem,3vw,2.1rem)}
.pf-row{display:grid;gap:.7rem}
.pf-head{display:flex;justify-content:space-between;align-items:baseline;gap:1rem}
.pf-head b{
  font-weight:400;font-size:.66rem;letter-spacing:.24em;text-transform:uppercase;color:var(--burgundy);
}
.pf-head i{
  font-style:normal;font-family:'Cormorant Garamond',Georgia,serif;
  font-size:1.5rem;color:var(--gold);font-variant-numeric:tabular-nums;line-height:1;
}
.pf-head small{display:block;font-size:.72rem;letter-spacing:0;text-transform:none;color:var(--muted);margin-top:.3rem}

/* the sliders read as the Chocometer's bar, laid flat */
.pf-range{
  -webkit-appearance:none;appearance:none;
  width:100%;height:10px;border-radius:0;
  background:linear-gradient(90deg,var(--track-a,#efe6d6),var(--track-b,#5e2130));
  box-shadow:inset 0 0 0 1px var(--line);
  cursor:pointer;
}
.pf-range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:22px;height:22px;border-radius:50%;
  background:var(--linen);box-shadow:0 0 0 1.5px var(--burgundy),0 3px 8px rgba(61,20,33,.28);
  cursor:grab;
}
.pf-range::-webkit-slider-thumb:active{cursor:grabbing}
.pf-range::-moz-range-thumb{
  width:22px;height:22px;border:0;border-radius:50%;
  background:var(--linen);box-shadow:0 0 0 1.5px var(--burgundy),0 3px 8px rgba(61,20,33,.28);
  cursor:grab;
}
.pf-range:focus-visible{outline:2px solid var(--gold);outline-offset:4px}
#pf-choc{--track-a:#f3e8d2;--track-b:#1d1009}
#pf-fruit{--track-a:#fdeef0;--track-b:#a8112e}
#pf-caff{--track-a:#f4ece0;--track-b:#4a2617}

.pf-switch{
  display:flex;align-items:center;gap:.9rem;
  padding-top:1.2rem;border-top:1px solid var(--line);
}
.pf-switch input{
  appearance:none;-webkit-appearance:none;
  width:52px;height:28px;border-radius:999px;
  background:var(--line);box-shadow:inset 0 0 0 1px var(--line);
  position:relative;cursor:pointer;transition:background .4s var(--ease);flex:0 0 auto;
}
.pf-switch input::after{
  content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:var(--linen);box-shadow:0 2px 5px rgba(61,20,33,.3);
  transition:transform .4s var(--slow);
}
.pf-switch input:checked{background:var(--burgundy)}
.pf-switch input:checked::after{transform:translateX(24px)}
.pf-switch input:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.pf-switch label{font-size:.82rem;color:var(--ink-soft);cursor:pointer}
.pf-switch label b{display:block;font-weight:400;font-size:.64rem;letter-spacing:.22em;text-transform:uppercase;color:var(--burgundy)}

/* the answer */
.pf-card{
  position:relative;
  background:var(--linen);border:1px solid rgba(176,141,79,.4);
  padding:clamp(1.4rem,3vw,2.2rem);text-align:center;
  transition:opacity .24s var(--ease),transform .5s var(--slow);
}
.pf-card.swapping{opacity:0;transform:translateY(10px)}
.pf-card .label{display:block;margin-bottom:1rem}
.pf-art{
  width:100%;max-width:250px;aspect-ratio:1;margin:0 auto;
  display:grid;place-items:center;
}
.pf-art img{
  width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply;
  -webkit-mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 40%,transparent 78%);
  mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 40%,transparent 78%);
}

/* The illustration is the menu's own, lifted from the Edinburgh PDF with its
   alpha channel intact, so it needs no keying, no mask and no blend mode ·
   it is already a painting on nothing. */
.pf-art img{mix-blend-mode:normal;-webkit-mask-image:none;mask-image:none}

.pf-card h3{
  font-family:'Cormorant Garamond',Georgia,serif;font-weight:400;
  font-size:clamp(1.5rem,1.2rem + 1.2vw,2.1rem);color:var(--burgundy);
  margin-top:.6rem;line-height:1.12;
}
.pf-card .tag{
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:1.1rem;color:var(--gold);margin-top:.45rem;
}
.pf-card .note{font-size:.9rem;color:var(--ink-soft);margin-top:.9rem;max-width:40ch;margin-inline:auto}
.pf-foot{
  margin-top:1.3rem;padding-top:1.2rem;border-top:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;gap:1rem;flex-wrap:wrap;
}

/* =====================================================================
   THE TOPPING DROP
   ===================================================================== */

.drop-grid{display:grid;gap:clamp(1.8rem,4vw,3.2rem);align-items:center}
@media(min-width:880px){.drop-grid{grid-template-columns:.92fr 1.08fr}}

.drop-stage{position:relative;width:100%;max-width:540px;margin:0 auto}
.fx-static{
  padding:2rem;text-align:center;border:1px dashed var(--line);
  font-size:.9rem;color:var(--muted);
}

.toppings{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:1.6rem}
.topping{
  display:inline-flex;align-items:center;gap:.6rem;
  border:1px solid var(--line);background:transparent;color:var(--ink-soft);
  padding:.65rem 1.1rem;cursor:pointer;
  font-size:.64rem;letter-spacing:.18em;text-transform:uppercase;
  transition:border-color .4s var(--ease),color .4s var(--ease),transform .25s var(--slow);
}
.topping:hover{border-color:var(--gold);color:var(--burgundy)}
.topping:active{transform:translateY(2px) scale(.97)}
.topping:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.topping .dot{width:13px;height:13px;border-radius:50%;flex:0 0 auto;box-shadow:inset 0 -2px 3px rgba(0,0,0,.18)}
.dot-marshmallow{background:linear-gradient(140deg,#fffdf8,#e4d7c3)}
.dot-strawberry{background:radial-gradient(circle at 34% 32%,#e0566a,#8d1329)}
.dot-pearl{background:radial-gradient(circle at 34% 32%,#6b3b24,#20100b)}
.dot-hazelnut{background:radial-gradient(circle at 34% 32%,#c98f5c,#5a3618)}
.dot-pistachio{background:radial-gradient(circle at 34% 32%,#b6cf7e,#6f8a3c)}
.topping.clear{border-style:dashed;color:var(--muted)}

/* =====================================================================
   MOBILE
   ===================================================================== */
@media(max-width:640px){
  .melt{height:clamp(150px,34vw,220px)}
  .pf-card .note{font-size:.86rem}
}



/* ==========================================================================
   PAINTED LOOPS, THE CHOCOMETER STACK, FLOATING PLATES AND THE GOLDEN KEY
   ========================================================================== */

/* --- every illustration is a loop with its still as the poster ------------ */
.art-loop{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  opacity:0;transition:opacity .9s var(--ease);
  mix-blend-mode:multiply;pointer-events:none;
}
.art-loop.ready{opacity:1}
.plate-art{position:relative}
.plate-art .art-loop{
  -webkit-mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,#000 56%,transparent 94%);
  mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,#000 56%,transparent 94%);
}

/* --- the Chocometer cup · five crossfading layers ------------------------- */
.cm-cup{position:relative;aspect-ratio:1;max-width:430px;margin-inline:auto;width:100%}
.cm-layer{
  position:absolute;inset:0;
  /* opacity is set per frame from the scale position · no transition here,
     it would fight the interpolation */
  will-change:opacity;
}
.cm-layer img,.cm-layer video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  mix-blend-mode:multiply;
  -webkit-mask-image:radial-gradient(ellipse 62% 62% at 50% 50%,#000 38%,transparent 76%);
  mask-image:radial-gradient(ellipse 62% 62% at 50% 50%,#000 38%,transparent 76%);
}
.cm-layer video{opacity:0;transition:opacity .9s var(--ease)}
.cm-layer video.ready{opacity:1}
.cm-layer video.ready + *,.cm-layer video.ready ~ img{opacity:0}
/* the wash goes dark at the bottom of the scale · multiply dies there */
.chocometer[data-dark] .cm-layer img,.chocometer[data-dark] .cm-layer video{mix-blend-mode:normal}
.chocometer{transition:none}

/* --- the picks float · no card, no border, no box ------------------------- */
.pick{
  display:flex;flex-direction:column;text-align:center;
  padding:clamp(1rem,2vw,1.6rem) .6rem;
  border:0;box-shadow:none;
  /* The illustrations are watercolour on white paper, so they need multiply
     to sit on the ground. But .tilt applies a transform, which opens a new
     stacking context, and a blend only ever reaches the backdrop inside its
     own group. With no background here the image multiplies against nothing
     and its paper shows as a white rectangle · which is the box that was
     standing off the page. Painting the card the SAME colour as the section
     puts a backdrop inside the group for multiply to work against, and the
     card itself stays invisible because it matches. */
  background:transparent;
}
.pick:hover{box-shadow:none}
.pick .plate-art{
  margin:clamp(.6rem,1.6vw,1.1rem) auto 0;width:100%;max-width:230px;aspect-ratio:4/5;
  display:grid;place-items:center;
}
.pick .plate-art img{
  width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply;
  -webkit-mask-image:radial-gradient(ellipse 78% 78% at 50% 50%,#000 52%,transparent 92%);
  mask-image:radial-gradient(ellipse 78% 78% at 50% 50%,#000 52%,transparent 92%);
  transition:transform .8s var(--slow);
}
.pick .title{color:var(--burgundy)}
.pick .cap-ital{margin-top:1.1rem;min-height:3.1em;display:flex;align-items:flex-start;justify-content:center}
.pick .plate-meta{margin-top:.9rem}
/* the only thing the pointer lifts is the illustration, not a panel */
.pick .tilt-splat{opacity:0}
.pick.is-tilting .tilt-splat{opacity:.9}

.pick.is-tilting{box-shadow:none}

/* --- the profiler answer is a loop too ------------------------------------ */
.pf-art{position:relative}
.pf-art .art-loop{
  -webkit-mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 40%,transparent 78%);
  mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 40%,transparent 78%);
}

/* =====================================================================
   THE GOLDEN KEY
   ===================================================================== */

.keyband{overflow:hidden}
.key-grid{display:grid;gap:clamp(2rem,5vw,4rem);align-items:center}
@media(min-width:920px){.key-grid{grid-template-columns:1.02fr .98fr}}

.key-stage{display:grid;gap:1.3rem;justify-items:center}
.key-tables{
  display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(.7rem,1.6vw,1.1rem);
  width:100%;max-width:400px;
}
.key-table{
  position:relative;aspect-ratio:1;cursor:pointer;
  border:1px solid rgba(210,181,133,.4);background:rgba(247,239,230,.07);
  border-radius:50%;
  transition:border-color .5s var(--ease),background .5s var(--ease),transform .5s var(--slow);
  display:grid;place-items:center;
  color:var(--gold-lite);
}
.key-table:hover{border-color:rgba(210,181,133,.6);transform:translateY(-4px)}
.key-table:focus-visible{outline:2px solid var(--gold);outline-offset:4px}
.key-table:active{transform:translateY(-1px) scale(.98)}

/* the table top · a plain painted circle until you look under it */
.key-top{
  position:absolute;inset:11%;border-radius:50%;
  background:radial-gradient(circle at 38% 32%,rgba(247,239,230,.26),rgba(247,239,230,.07) 72%);
  box-shadow:inset 0 0 0 1px rgba(210,181,133,.22);
  transition:opacity .45s var(--ease),transform .55s var(--slow);
}
.key-table.open .key-top{opacity:0;transform:scale(.72) rotate(-14deg)}

.key-face{
  width:34%;display:grid;place-items:center;
  opacity:0;transform:scale(.5) rotate(-24deg);
  transition:opacity .5s var(--ease),transform .7s var(--slow);
}
.key-face svg{width:100%;height:auto;display:block}
.key-table.win .key-face{opacity:1;transform:none}
.key-table.win{
  border-color:var(--gold);
  background:radial-gradient(circle at 50% 50%,rgba(210,181,133,.3),rgba(176,141,79,.08) 70%);
  animation:keyglow 2.6s var(--ease) infinite;
}
@keyframes keyglow{
  0%,100%{box-shadow:0 0 0 0 rgba(210,181,133,.32)}
  50%{box-shadow:0 0 0 14px rgba(210,181,133,0)}
}
.key-table.miss{opacity:.34;cursor:default;border-color:rgba(247,239,230,.1)}
.key-table.miss:hover{transform:none}

.key-read{
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  font-size:clamp(1.05rem,.95rem + .6vw,1.4rem);
  color:rgba(247,239,230,.72);text-align:center;min-height:2.4em;
  transition:color .5s var(--ease);
}
.key-read.win{color:var(--gold-lite)}
.key-reset{--fg:#f7efe6;--bd:rgba(247,239,230,.34)}

@media(prefers-reduced-motion:reduce){
  .key-table.win{animation:none}
  .art-loop{display:none}
}


/* ==========================================================================
   KEYED ILLUSTRATIONS
   The paper the illustrations were painted on is cream, so multiply could
   never hide it on a tinted ground · it just turned the ground warm inside a
   rectangle. The stills are now keyed to real transparency, so they need no
   blend mode and no mask, and they sit on any ground including the near-black
   bottom of the Chocometer.

   The mp4 loops cannot carry alpha, so they keep multiply and a soft mask and
   the sections that hold them use warm grounds, where cream on cream is
   invisible.
   ========================================================================== */
.pick .plate-art img,
.plate-art picture img{
  mix-blend-mode:normal;
  -webkit-mask-image:none;mask-image:none;
}
.pick{background:transparent}

/* the loops sit under the keyed still and only ever add movement */
.plate-art .art-loop{z-index:-1;mix-blend-mode:multiply}

/* THE SHEET.
   The illustration is painted on cream paper and the cup itself is cream, so
   no luma key can separate one from the other · they are the same value. So
   the paper stops being a problem to hide and becomes the device: a torn sheet
   that fades in under the cup as the scale darkens. Multiply then works
   perfectly at every step, no mask, no keying, no artefacts, and the dark end
   reads as a painting pinned to a wall.
   --paper is set per frame by campaign.js, 0 at Ivory, 1 by Deep Roast. */
.cm-cup::before{
  content:"";position:absolute;inset:-2%;
  background:
    radial-gradient(ellipse 60% 55% at 46% 40%,rgba(255,252,246,.55),transparent 70%),
    #f2ebdf;
  opacity:var(--paper,0);
  transition:opacity .3s linear;
  /* a torn sheet, not a box · the edge has to give out gradually or it reads
     as the rectangle we spent all this effort removing */
  -webkit-mask-image:radial-gradient(ellipse 62% 60% at 50% 50%,#000 34%,rgba(0,0,0,.92) 58%,rgba(0,0,0,.45) 80%,transparent 96%);
  mask-image:radial-gradient(ellipse 62% 60% at 50% 50%,#000 34%,rgba(0,0,0,.92) 58%,rgba(0,0,0,.45) 80%,transparent 96%);
  pointer-events:none;
}
.cm-layer{position:absolute;inset:0;z-index:1;will-change:opacity}
.cm-layer img,.cm-layer video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  mix-blend-mode:multiply;
  /* feathers the painted edge into the sheet, and into the ground above it */
  -webkit-mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 52%,transparent 88%);
  mask-image:radial-gradient(ellipse 64% 64% at 50% 50%,#000 52%,transparent 88%);
}
.cm-layer video{opacity:0;transition:opacity .9s var(--ease)}
.cm-layer video.ready{opacity:1}

/* The manifesto ends on a picture of its own argument: a marshmallow being
   dropped into a glass. It plays ONCE when it comes into view rather than
   looping, because a single deliberate drop reads as a full stop and a loop
   reads as a gif. */
.drop-in{
  margin:clamp(1.6rem,3.5vw,2.6rem) auto 0;
  width:min(340px,72vw);position:relative;
  display:flex;flex-direction:column;align-items:center;
}
.drop-in picture,.drop-in img{display:block;width:100%}
.drop-in .art-loop{
  position:absolute;inset:auto 0 auto 0;top:0;height:auto;
  aspect-ratio:1;object-fit:contain;mix-blend-mode:multiply;
}
.drop-in figcaption{margin-top:.9rem;text-align:center;font-size:.98rem}

/* The house .bleed lays a flat 60% burgundy veil over its media, which was
   right for a photograph and is wrong for a painting · it dulled the whole
   watercolour to keep two lines of type legible. This swaps it for a soft
   radial scrim centred on the words, so the type still clears contrast and
   the edges of the painting stay at full strength. */
.bleed-media::after{
  background:
    radial-gradient(60% 52% at 50% 46%,rgba(40,14,23,.62),rgba(40,14,23,.34) 55%,rgba(40,14,23,.1) 80%,transparent 100%),
    linear-gradient(to bottom,rgba(40,14,23,.18),transparent 22%,transparent 78%,rgba(40,14,23,.18));
}
.bleed-in .h2{text-shadow:0 2px 26px rgba(40,14,23,.55)}

/* Two of the plate illustrations (the fondue and the frappé) come from the
   earlier low-resolution batch and carry blocky compression halos baked into
   the frame around the subject. Those are mid-tone, not paper, so the key
   cannot lift them. A soft radial mask fades the periphery out instead. It
   costs nothing on the clean, keyed ones · they are already transparent out
   there. Both come out when those two are regenerated at 1920. */
.pick .plate-art img{
  -webkit-mask-image:radial-gradient(ellipse 60% 60% at 50% 50%,#000 58%,transparent 92%);
  mask-image:radial-gradient(ellipse 60% 60% at 50% 50%,#000 58%,transparent 92%);
}

/* ==========================================================================
   THE HERO · let the painting be the shape it was painted
   --------------------------------------------------------------------------
   The house hero is min-height:100svh with object-fit:cover, which was right
   when the art was a photograph you could crop anywhere. It is wrong for a
   composition that was deliberately built 16:9 with the glass in the right
   third and the headline's space on the left: in a 1440x1150 window, cover
   scales the clip ~42% to fill the height and throws away 600px of width,
   and the house `drift` keyframe then zooms it another 13% on top. Between
   them the frame you generated never appears on screen.

   So the hero takes the CLIP's aspect ratio when there is room for it, and
   only falls back to cropping on shapes where 16:9 genuinely cannot fit.
   ========================================================================== */
.hero{
  min-height:min(100svh, max(620px, 56.25vw));
}
/* no drift · it was a second, invisible zoom on top of the first */
.hero-media img,.hero-media video{
  animation:none;
  transform:none;
  /* on tall or narrow windows there is still a crop · bias it to the right
     so the branded glass survives and the empty paper is what gets lost */
  object-position:68% 50%;
}
@media(max-width:820px){
  .hero{min-height:min(100svh, max(560px, 120vw))}
  .hero-media img,.hero-media video{object-position:74% 50%}
}


/* =====================================================================
   THE DROP · the painted version
   The canvas sim that used to live here is gone. What is left is the
   illustration and the menu's own three toppings, set as type.
   ===================================================================== */

.drop-stage{position:relative;display:flex;flex-direction:column;align-items:center}
.drop-stage picture,.drop-stage img{display:block;width:100%}
.drop-stage .art-loop{
  position:absolute;left:0;top:0;width:100%;
  aspect-ratio:1;height:auto;object-fit:contain;
  mix-blend-mode:multiply;
}
.drop-stage figcaption{
  margin-top:1rem;text-align:center;font-size:1rem;max-width:32ch;
}

.topping-list{
  margin-top:clamp(1.6rem,3vw,2.2rem);
  display:flex;flex-direction:column;width:100%;max-width:34rem;
  list-style:none;padding:0;
}
.topping-list li{
  display:grid;grid-template-columns:auto 1fr auto;align-items:baseline;gap:1rem;
  padding:1rem 0;border-top:1px solid var(--line);
}
.topping-list li:last-child{border-bottom:1px solid var(--line)}
.topping-list .dot{
  width:13px;height:13px;border-radius:50%;align-self:center;
  box-shadow:inset 0 -2px 3px rgba(0,0,0,.2);
}
.topping-list b{
  font-weight:400;font-size:.98rem;color:var(--burgundy);letter-spacing:.01em;
}
.topping-list i{
  font-family:'Cormorant Garamond',Georgia,serif;font-style:italic;
  color:var(--muted);font-size:1rem;text-align:right;
}
@media(max-width:560px){
  .topping-list li{grid-template-columns:auto 1fr;row-gap:.2rem}
  .topping-list i{grid-column:2;text-align:left}
}

/* Once a painted loop is genuinely playing, its poster still has no job left.
   Leaving it there meant two multiply-blended copies of the same subject at
   different moments in the animation, stacked · a double image that read as
   trails and leftover outlines. */
.has-loop > picture,
.has-loop > img{opacity:0;transition:opacity .5s var(--ease)}

/* === consolidation fixes · added during the pre-ship check ================
   1. The main site's styles.css defines .tag as a small uppercase chip with a
      gold border and white-space:nowrap. This page uses .tag for an italic
      serif tagline. In the standalone student deploy styles.css had no .tag
      rule at all, so the collision only appears once the two builds are
      merged. Undo the chip here, scoped to the campaign's own blocks.
   2. Below 900px .pf-grid has no column rule, so its single auto track sizes
      to the widest child and pushes the page sideways on a phone.
   ======================================================================== */
.pf-card .tag,
.cm-read .tag{
  display:block;padding:0;border:0;
  letter-spacing:normal;text-transform:none;white-space:normal;
}

@media(max-width:899px){
  .pf-grid{grid-template-columns:minmax(0,1fr)}
  .pf-grid>*{min-width:0}
}

/* 3. The merged styles.css narrows .book-grid's left column to .68fr, which
      was .86fr in the standalone student deploy. At .68fr the reminder
      headline breaks to three lines with an orphaned word and the bullets
      wrap. Restore the campaign's own proportion, scoped to this page, and
      only in the breakpoint where the rule exists. */
@media(min-width:980px){
  body[data-campaign="students"] .book-grid{grid-template-columns:.86fr 1.14fr}
}
