/* gigi flowers — storefront.
 *
 * This stylesheet is the demo's, lifted verbatim from demo/index.html: that
 * page is what the client saw and approved, so the safest way to look exactly
 * like it is to be it. demo/ stays read-only (rule 1 in CLAUDE.md) — this is a
 * copy, and it is the file to edit from now on.
 *
 * Three additions live at the bottom, marked as such: the pieces the demo
 * faked with JavaScript and we render on the server instead (product pages,
 * the cart page, the language switch).
 */

/* `hidden` must actually hide. The browser's own `[hidden] {display:none}` is
   in the user-agent stylesheet, and any author rule setting `display` beats it
   — the cascade orders by origin before specificity. This bit three times
   here already (the three `[hidden]` patches below are the scars) and once in
   the admin panel, where it left an unclosable overlay on the login screen.
   One rule instead of a fourth patch. */
[hidden]{display:none !important}

/* ---------- Tokens ---------- */
:root{
  --ink:#131313;
  --bg:#ffffff;
  --line:#e5e5e5;
  --muted:#767676;
  /* The one colour the shop uses to say no: a refused code, a basket under
     the minimum, an error the server sent back. It was referenced before it
     was ever declared, so every var(--sale) resolved to nothing — see
     docs/notes.md, 2026-08-30. */
  --sale:#b3261e;
  --pad: clamp(20px, 4vw, 64px);
  --sec: clamp(76px, 11vw, 176px);
  --label: 11px;
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth; scrollbar-gutter:stable}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font-family:"Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  font-weight:400; font-size:15px; line-height:1.6;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
body.is-locked{overflow:hidden}
img{display:block; max-width:100%; height:auto}
h1,h2,h3,h4,p,figure,ul,ol{margin:0}
ul{list-style:none; padding:0}
a{color:inherit; text-decoration:none}
button{font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer}
:focus{outline:none}
:focus-visible{outline:1px solid var(--ink); outline-offset:3px}
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- Primitives ---------- */
.wrap{max-width:1600px; margin:0 auto; padding-left:var(--pad); padding-right:var(--pad)}
.label{
  font-size:var(--label); line-height:1.2; text-transform:uppercase; letter-spacing:.08em;
  font-weight:400;
}
.label--muted{color:var(--muted)}
.display{
  font-weight:300; letter-spacing:-.02em; line-height:1.06;
  font-size:clamp(34px, 5.4vw, 72px);
}
.h2{
  font-weight:300; letter-spacing:-.015em; line-height:1.1;
  font-size:clamp(28px, 3.6vw, 48px);
}
.lede{font-size:clamp(15px,1.25vw,18px); line-height:1.7; color:var(--ink); max-width:62ch}
.small{font-size:13px; line-height:1.65; color:var(--muted)}
.rule{border:0; border-top:1px solid var(--line); margin:0}
.section{padding-top:var(--sec); padding-bottom:var(--sec)}
.section--tight{padding-top:clamp(56px,7vw,112px); padding-bottom:clamp(56px,7vw,112px)}
/* A product page opens with the product itself, not with a title block, so the
   section rhythm that separates one band of the home page from the next is
   just a hole under the header. A quarter of --sec: enough to clear the
   header, not enough to have to scroll to the thing being sold. */
.section--top-tight{padding-top:clamp(19px,2.75vw,44px)}

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.6em;
  background:var(--ink); color:#fff; border:1px solid var(--ink);
  padding:15px 30px; min-height:48px;
  font-size:var(--label); text-transform:uppercase; letter-spacing:.08em;
  transition:background .25s ease, color .25s ease;
}
.btn:hover{background:#fff; color:var(--ink)}
.btn--ghost{background:transparent; color:var(--ink)}
.btn--ghost:hover{background:var(--ink); color:#fff}
.btn--block{width:100%}
.link-u{
  border-bottom:1px solid var(--ink); padding-bottom:2px;
  transition:opacity .25s ease;
}
.link-u:hover{opacity:.55}

/* ---------- Announcement ---------- */
.announce{
  background:var(--ink); color:#fff; text-align:center;
  padding:11px var(--pad);
}
.announce p{font-size:var(--label); text-transform:uppercase; letter-spacing:.08em; line-height:1.4}

/* ---------- Header ---------- */
.header{
  position:sticky; top:0; z-index:60;
  background:var(--bg); border-bottom:1px solid var(--line);
}
.header__inner{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  gap:16px; height:64px;
  /* The mark is centred on the bar, not on its column, so it is taken out of
     the grid and positioned against this. */
  position:relative;
}
.wordmark{
  font-size:clamp(17px,1.6vw,21px); font-weight:400; letter-spacing:-.01em; line-height:1;
  text-transform:lowercase; justify-self:start;
}
/* The header's mark is the logo she drew, in the middle of the bar. Centring
   it inside its grid column would leave it left of centre — the menu on one
   side is narrower than the languages and the cart on the other — so it is
   taken out of the flow and centred on the bar itself. It keeps the empty
   `1fr` column, which is what stops the two sides from meeting behind it.

   Sized by height, from the bar's own height: the file is 1200x248, so a
   height of 56px draws it 271px wide, and it shrinks with the viewport rather
   than growing into the links beside it. */
.wordmark--mark{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  display:block; line-height:0;
}
.wordmark--mark img{display:block; width:auto; height:clamp(26px, 5vw, 56px)}
/* Beside the three lines: the same small-caps label as the cart on the other
   side, so the two ends of the bar are set alike. */
.shop-btn{
  font-size:var(--label); text-transform:uppercase; letter-spacing:.08em;
  white-space:nowrap; padding:6px 0; margin-left:14px;
  border-bottom:1px solid transparent; transition:border-color .25s ease;
}
.shop-btn:hover{border-bottom-color:var(--ink)}
.header__end{display:flex; align-items:center; gap:18px; justify-self:end}
.cart-btn{font-size:var(--label); text-transform:uppercase; letter-spacing:.08em; white-space:nowrap; padding:6px 0; border-bottom:1px solid transparent; transition:border-color .25s ease}
.cart-btn:hover{border-bottom-color:var(--ink)}

/* ---------- Hero ---------- */
.hero{position:relative; min-height:clamp(560px, 100svh, 1100px); display:flex; align-items:flex-end; overflow:hidden}
.hero__img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover}
.hero::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(to bottom, rgba(0,0,0,.26) 0%, rgba(0,0,0,.06) 42%, rgba(0,0,0,.42) 100%);
}
.hero__inner{position:relative; z-index:2; width:100%; color:#fff; padding-bottom:clamp(48px,7vw,104px); padding-top:clamp(80px,14vw,160px)}
/* The mark, and nothing else on the picture (specs/0019). Lowercase and
   light, the way it is set everywhere else in the shop, only large. */
.hero__mark{
  color:#fff; font-size:clamp(44px,9vw,132px); font-weight:300;
  letter-spacing:-.03em; line-height:1; text-transform:lowercase;
  /* The photograph is hers to change and most of hers are pale, so the mark
     carries its own shadow rather than trusting the gradient over the
     picture. */
  text-shadow:0 2px 40px rgba(0,0,0,.45);
}
.hero :focus-visible{outline-color:#fff}

/* ---------- Manifesto ---------- */
.manifesto{max-width:62ch; margin:0 auto; text-align:center}
.manifesto__q{
  font-size:clamp(30px,4.6vw,62px); font-weight:300; letter-spacing:-.02em;
  line-height:1.12; text-transform:lowercase;
}
.manifesto__text{margin-top:clamp(20px,2.6vw,34px)}
.manifesto__more{margin-top:clamp(22px,2.6vw,34px)}

/* ---------- Section head ---------- */
.sec-head{display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between; gap:20px 32px; margin-bottom:clamp(30px,4vw,64px)}
.sec-head__title{max-width:min(760px,64ch); flex:1 1 420px}
.sec-head__title .h2{max-width:20ch}
.sec-head__meta{display:flex; flex-direction:column; gap:8px; text-align:right; align-items:flex-end}
.sec-head p.lede{margin-top:16px}
.eyebrow{display:flex; align-items:center; gap:10px; margin-bottom:18px; white-space:nowrap}
.eyebrow::before{content:""; width:24px; height:1px; background:var(--ink); flex:none}

/* filters */
.filters{display:flex; flex-wrap:wrap; gap:8px}
.chip{
  font-size:var(--label); text-transform:uppercase; letter-spacing:.08em;
  border:1px solid var(--line); padding:10px 16px; min-height:38px;
  display:inline-flex; align-items:center;
  transition:border-color .2s ease, background .2s ease, color .2s ease;
}
.chip:hover{border-color:var(--ink)}
.chip[aria-pressed="true"], .chip.is-on{background:var(--ink); border-color:var(--ink); color:#fff}

/* ---------- Product grid ---------- */
.grid{display:grid; gap:clamp(30px,3vw,56px) clamp(14px,2vw,36px)}
.grid--3{grid-template-columns:repeat(3,1fr)}
.grid--4{grid-template-columns:repeat(4,1fr)}
.card{display:flex; flex-direction:column}
.card[hidden]{display:none}
.card__media{
  display:block; width:100%; position:relative; background:#f6f6f4;
  aspect-ratio:1/1; overflow:hidden;
}
.card--tall .card__media{aspect-ratio:4/5}
.card__media img{width:100%; height:100%; object-fit:cover; transition:transform .7s cubic-bezier(.2,.6,.2,1), opacity .4s ease}
.card:hover .card__media img{transform:scale(1.028)}
.card__fresh{
  position:absolute; left:0; bottom:0; background:#fff; color:var(--ink);
  padding:7px 11px; font-size:10px; text-transform:uppercase; letter-spacing:.08em;
}
.card__body{padding-top:16px; display:flex; flex-direction:column; flex:1}
.card__title{font-size:15px; font-weight:400; line-height:1.35}
.card__desc{
  margin-top:6px; color:var(--muted); font-size:13px; line-height:1.5;
  display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.card__foot{margin-top:12px; display:flex; align-items:baseline; justify-content:space-between; gap:12px; padding-top:12px; border-top:1px solid var(--line)}
.card__price{font-size:14px; white-space:nowrap}
.card__add{
  font-size:var(--label); text-transform:uppercase; letter-spacing:.08em;
  border-bottom:1px solid var(--ink); padding-bottom:2px;
  opacity:0; transform:translateY(2px);
  transition:opacity .25s ease, transform .25s ease;
}
/* The action is a button when it adds and a link when it leads to a choice
   (specs/0020); the form around the button must not become a box of its own. */
.card__buy{display:contents}
button.card__add{background:none; border:0; border-bottom:1px solid var(--ink); cursor:pointer; font-family:inherit; color:inherit}
.card:hover .card__add, .card:focus-within .card__add{opacity:1; transform:none}
.card__add.is-done{opacity:1; transform:none; border-bottom-color:var(--line); color:var(--muted)}
@media (hover:none){ .card__add{opacity:1; transform:none} }

.more-row{margin-top:clamp(34px,4vw,64px); display:flex; justify-content:center}

/* ---------- Bon ---------- */
.bon{display:grid; grid-template-columns:1fr 1fr; gap:clamp(28px,5vw,88px); align-items:center}
.bon__media{aspect-ratio:4/5; background:#f6f6f4; overflow:hidden}
.bon__media img{width:100%; height:100%; object-fit:cover}
.bon__amounts{display:flex; flex-wrap:wrap; gap:8px; margin:26px 0}

/* ---------- Photo request ---------- */
.ask{display:grid; grid-template-columns:1fr 1fr; gap:clamp(28px,5vw,88px); align-items:center}
.ask__drop{
  border:1px dashed var(--line); padding:clamp(28px,4vw,56px); text-align:center;
  display:flex; flex-direction:column; align-items:center; gap:16px;
  transition:border-color .25s ease;
}
.ask__drop:hover{border-color:var(--ink)}
.ask__file{font-size:13px; color:var(--muted); min-height:20px}

/* ---------- Dostawa ---------- */
.cols3{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(24px,3vw,56px)}
.col h3{font-size:clamp(19px,1.7vw,24px); font-weight:400; letter-spacing:-.01em; margin-top:14px}
.col p{margin-top:10px; color:var(--muted); font-size:14px}
.formats{display:grid; grid-template-columns:repeat(2,1fr); gap:clamp(20px,3vw,56px)}
.format{border-top:1px solid var(--line); padding-top:18px}
.format h4{font-size:17px; font-weight:400; margin-bottom:6px}
.slots{display:flex; flex-wrap:wrap; gap:8px; margin-top:16px}
.policy{max-width:70ch}

/* ---------- O nas ---------- */
.about{display:grid; grid-template-columns:.9fr 1.1fr; gap:clamp(28px,5vw,88px); align-items:start}
.about__media{aspect-ratio:1/1; background:#f6f6f4; overflow:hidden}
.about__media img{width:100%;height:100%;object-fit:cover}
.about p + p{margin-top:18px}

/* ---------- Footer ---------- */
.footer{border-top:1px solid var(--line); padding-top:clamp(48px,6vw,96px); padding-bottom:40px}
.footer__grid{display:grid; grid-template-columns:1.4fr 1fr 1fr 1fr; gap:clamp(24px,3vw,56px)}
.footer h4{margin-bottom:16px}
.footer li + li{margin-top:9px}
.footer a{font-size:14px}
.footer a:hover{opacity:.55}
.footer__bottom{margin-top:clamp(40px,5vw,80px); padding-top:22px; border-top:1px solid var(--line); display:flex; flex-wrap:wrap; gap:12px 32px; justify-content:space-between}

/* ---------- Overlays ---------- */
.backdrop{
  position:fixed; inset:0; z-index:80; background:rgba(19,19,19,.32);
  opacity:0; visibility:hidden; transition:opacity .35s ease, visibility .35s;
}
.backdrop.is-open{opacity:1; visibility:visible}

.drawer{
  position:fixed; top:0; right:0; bottom:0; z-index:90; width:min(420px,100%);
  background:#fff; display:flex; flex-direction:column;
  transform:translateX(100%); transition:transform .4s cubic-bezier(.3,.7,.2,1);
  visibility:hidden;
}
.drawer.is-open{transform:none; visibility:visible}
.drawer__head{display:flex; align-items:center; justify-content:space-between; padding:20px var(--pad); border-bottom:1px solid var(--line); flex:none}
.drawer__body{flex:1; overflow-y:auto; padding:0 var(--pad)}
.drawer__foot{flex:none; border-top:1px solid var(--line); padding:20px var(--pad) 28px}
.drawer--menu{left:0; right:auto; width:min(360px,100%); transform:translateX(-100%)}
.drawer--menu.is-open{transform:none}
.menu-nav{padding:14px 0}
.menu-nav a{display:block; padding:14px 0; font-size:22px; font-weight:300; letter-spacing:-.01em; border-bottom:1px solid var(--line)}
.close-x{font-size:var(--label); text-transform:uppercase; letter-spacing:.08em; border-bottom:1px solid var(--ink); padding-bottom:2px}

.cart-empty{padding:40px 0; color:var(--muted); font-size:14px}
.line{display:grid; grid-template-columns:76px 1fr; gap:16px; padding:22px 0; border-bottom:1px solid var(--line)}
.line__media{aspect-ratio:1/1; background:#f6f6f4; overflow:hidden}
.line__media img{width:100%;height:100%;object-fit:cover}
.line__title{font-size:14px; line-height:1.35}
.line__fmt{margin-top:4px; color:var(--muted)}
.line__row{margin-top:12px; display:flex; align-items:center; justify-content:space-between; gap:12px}
.stepper{display:inline-flex; align-items:center; border:1px solid var(--line)}
.stepper button{width:32px; height:32px; display:grid; place-items:center; font-size:15px; line-height:1}
.stepper button:hover{background:#f6f6f4}
.stepper span{min-width:30px; text-align:center; font-size:13px}
.line__price{font-size:14px; white-space:nowrap}
.line__rm{margin-top:10px; font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); border-bottom:1px solid var(--line); padding-bottom:2px}
.line__rm:hover{color:var(--ink); border-bottom-color:var(--ink)}
.total{display:flex; justify-content:space-between; align-items:baseline; margin-bottom:8px}
.total strong{font-weight:400; font-size:17px}
.checkout-note{margin-top:14px; font-size:13px; line-height:1.6; color:var(--muted)}
.checkout-note[hidden]{display:none}

/* Modal */
.modal{
  position:fixed; inset:0; z-index:95; display:grid; place-items:center; padding:clamp(0px,3vw,40px);
  opacity:0; visibility:hidden; transition:opacity .3s ease, visibility .3s;
}
.modal.is-open{opacity:1; visibility:visible}
.modal__panel{
  background:#fff; width:min(1120px,100%); max-height:100%; overflow-y:auto;
  display:grid; grid-template-columns:1fr 1fr;
  transform:translateY(10px); transition:transform .35s cubic-bezier(.3,.7,.2,1);
}
.modal.is-open .modal__panel{transform:none}
.modal__media{background:#f6f6f4; aspect-ratio:1/1}
.modal__media img{width:100%; height:100%; object-fit:cover}
.modal__body{padding:clamp(24px,3vw,52px); display:flex; flex-direction:column}
.modal__close{position:absolute; top:0; right:0; padding:18px 20px; z-index:2; background:#fff}
.modal__panel{position:relative}
.modal__title{font-size:clamp(22px,2.4vw,34px); font-weight:300; letter-spacing:-.015em; line-height:1.15; margin-top:14px; padding-right:40px}
.modal__price{margin-top:16px; font-size:18px}
.modal__desc{margin-top:22px; padding-top:22px; border-top:1px solid var(--line); font-size:14px; line-height:1.7}
.modal__care{margin-top:16px; font-size:14px; line-height:1.7}
.modal__care .label{display:block; margin-bottom:4px; color:var(--muted)}
.field{margin-top:24px}
.field > .label{display:block; margin-bottom:10px; color:var(--muted)}
.modal__actions{margin-top:28px; display:flex; flex-wrap:wrap; gap:12px; align-items:center}
.modal__actions .stepper{height:48px}
.modal__actions .stepper button{width:44px; height:46px}
.modal__actions .btn{flex:1; min-width:200px}
.modal__note{margin-top:22px; padding-top:18px; border-top:1px solid var(--line)}

/* ---------- Reveal ---------- */
.js .reveal{opacity:0; transform:translateY(14px)}
.js .reveal.is-in{opacity:1; transform:none; transition:opacity .5s ease, transform .5s ease}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .reveal{opacity:1; transform:none}
  *,*::before,*::after{transition-duration:.01ms !important; animation-duration:.01ms !important}
}

/* ---------- Responsive ---------- */
@media (max-width:1180px){
  .grid--4{grid-template-columns:repeat(3,1fr)}
}
@media (max-width:900px){
  .bon, .ask, .about{grid-template-columns:1fr}
  .cols3{grid-template-columns:1fr; gap:32px}
  .footer__grid{grid-template-columns:1fr 1fr}
  .modal__panel{grid-template-columns:1fr}
  .modal__media{aspect-ratio:4/3}
  .sec-head__meta{text-align:left; align-items:flex-start}
}
@media (max-width:760px){
  .grid--3{grid-template-columns:repeat(2,1fr)}
  .grid--4{grid-template-columns:repeat(2,1fr)}
  .formats{grid-template-columns:1fr; gap:26px}
}
@media (max-width:480px){
  :root{--pad:20px}
  .grid{gap:26px 12px}
  .announce p{font-size:10px; letter-spacing:.06em}
  .footer__grid{grid-template-columns:1fr; gap:34px}
}

/* ==========================================================================
   Added for the real shop — everything above is the approved demo.
   The demo was one page with a quick-view modal and a JavaScript cart; the
   shop has real product pages, a real cart page and three languages. These
   rules dress those in the same design.
   ========================================================================== */

/* The card links to a product page instead of opening a modal. */
.card__media--link { display: block; }
.card__link { display: block; color: inherit; }
.card__link:hover .card__title { border-bottom-color: var(--ink); }
.card__title { display: inline; border-bottom: 1px solid transparent; transition: border-color .25s ease; }

/* Language switch, in the header on desktop and in the menu drawer on mobile. */
.langs { display: flex; gap: 10px; }
.langs a {
  font-size: var(--label); text-transform: uppercase; letter-spacing: .08em;
  padding: 6px 0; border-bottom: 1px solid transparent; transition: border-color .25s ease;
}
.langs a:hover { border-bottom-color: var(--ink); }
.langs a.is-on { border-bottom-color: var(--ink); }
.drawer .langs { padding: 18px 0 0; }

/* Product page: gallery left, details right, same measures as the modal. */
.product { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 88px); align-items: start; }
.product__media { background: #f6f6f4; aspect-ratio: 1/1; overflow: hidden; }
.product__media img { width: 100%; height: 100%; object-fit: cover; }
.product__title { margin-top: 14px; }
.product__price { margin-top: 16px; font-size: 18px; }
.product__desc { margin-top: 22px; padding-top: 22px; border-top: 1px solid var(--line); font-size: 14px; line-height: 1.7; }
.product__note { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); }
.product__form { margin-top: 24px; }
.product__actions { margin-top: 28px; display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.product__actions .btn { flex: 1; min-width: 200px; }
.qty { width: 88px; height: 48px; border: 1px solid var(--line); text-align: center; font: inherit; }
.fmt { display: flex; flex-wrap: wrap; gap: 8px; }
.fmt label { position: relative; }
.fmt input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.fmt input:checked + span { background: var(--ink); border-color: var(--ink); color: #fff; }
.fmt input:focus-visible + span { outline: 1px solid var(--ink); outline-offset: 3px; }

/* Cart page: the drawer's line design, laid out on a page. */
.cart-page { max-width: 760px; }
.cart-page .line { grid-template-columns: 96px 1fr; }
.cart-page .total { margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--line); }
.cart-form { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* In the basket the sheet takes the whole line and the quantity and the button
   sit under it: a flex row cannot hold a card, a number and a button at the
   width of a phone. Shorter here - the words are already written by this
   point, and the basket is a list, not a desk. */
.cart-form .card-note { flex: 1 0 100%; height: 80px; }
.cart-form input { width: 64px; height: 38px; border: 1px solid var(--line); text-align: center; font: inherit; }

/* Prose for the legal and information pages. */
.prose { max-width: 70ch; }
.prose h2 { font-size: clamp(22px, 2.4vw, 30px); font-weight: 300; letter-spacing: -.015em; margin-top: 40px; }
.prose h3 { font-size: 18px; font-weight: 400; margin-top: 28px; }
.prose p, .prose li { font-size: 15px; line-height: 1.7; }
.prose p + p, .prose ul, .prose ol { margin-top: 14px; }
.prose ul, .prose ol { list-style: revert; padding-left: 1.2em; }
.prose li + li { margin-top: 6px; }
.prose table { width: 100%; border-collapse: collapse; margin-top: 18px; font-size: 14px; }
.prose th, .prose td { text-align: left; padding: 10px; border-bottom: 1px solid var(--line); }
.prose blockquote { margin-top: 18px; padding-left: 16px; border-left: 1px solid var(--line); color: var(--muted); }

@media (max-width: 900px) {
  .product { grid-template-columns: 1fr; }
  .header .langs { display: none; }
}

/* --- The side tab: the shop's one navigation (specs/0019) ------------------
 * The header used to carry a row of seven links on wide screens and a burger
 * on narrow ones — two menus saying the same thing, and the burger, being a
 * fourth child of a three-column grid, shifted the whole header one column
 * until it was taken out of the flow. Both are gone. What is left is a tab
 * pinned to the left edge of the window on every page and every width, which
 * is what the client liked on her reference and what a shop with more than two
 * categories needs.
 *
 * A <details> element: it opens and closes with no JavaScript. The summary is
 * fixed rather than absolute so it keeps its place while the page scrolls, and
 * it slides across by the panel's width when the panel is open — otherwise the
 * panel would cover the one control that closes it.
 */
.shoptab { position: static; justify-self: start; }
.shoptab > summary { list-style: none; cursor: pointer; }
.shoptab > summary::-webkit-details-marker { display: none; }

/* Three lines, drawn rather than fetched: the middle one is the element and
   the other two are its pseudo-elements. No icon font, no SVG sprite — a font
   that fails to load must not take the only way into the shop with it. */
.shoptab__tab {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; margin-left: -8px;
}
.shoptab__lines, .shoptab__lines::before, .shoptab__lines::after {
  content: ""; display: block;
  width: 20px; height: 1.5px; background: var(--ink);
  transition: transform .25s ease, opacity .25s ease;
}
.shoptab__lines { position: relative; }
.shoptab__lines::before { position: absolute; top: -6px; }
.shoptab__lines::after { position: absolute; top: 6px; }
/* Open, it becomes the cross that closes it — the same control, so there is
   never a second one to hunt for. */
.shoptab[open] .shoptab__lines { background: transparent; }
.shoptab[open] .shoptab__lines::before { transform: translateY(6px) rotate(45deg); }
.shoptab[open] .shoptab__lines::after { transform: translateY(-6px) rotate(-45deg); }
@media (prefers-reduced-motion: reduce) {
  .shoptab__lines, .shoptab__lines::before, .shoptab__lines::after { transition: none; }
}

/* The panel hangs under the header rather than off the side of the window: the
   control that opens it is in the header now, and a panel that starts anywhere
   else reads as belonging to something else. */
.shoptab__panel {
  position: fixed; left: 0; top: 0; z-index: 94;
  width: min(340px, 88vw); height: 100dvh;
  /* Clear of the control that opened it. The panel starts at the top of the
     window, so without this the first category sits under the three lines —
     which is where the × that closes it now is. */
  padding-top: 76px;
  border-right: 1px solid var(--line);
  overflow-y: auto;
}
.shoptab__panel .menu-nav--small { padding-top: 0; }
.shoptab__panel .menu-nav--small a { font-size: 15px; }
.shoptab__panel .langs { padding: 22px var(--pad) 28px; }
.shoptab__panel .menu-nav { padding-left: var(--pad); padding-right: var(--pad); }
.shoptab[open] .shoptab__tab { position: relative; z-index: 96; }

/* A little larger than the 11px label, and vertically centred in a slightly
   taller bar: these are the only things in the header you actually click. */
.header__inner { height: clamp(72px, 8vw, 92px); }
  .shoptab__panel { padding-top: 84px; }
.cart-btn, .shop-btn, .langs a {
  font-size: 13px;
  letter-spacing: .06em;
  padding: 10px 0;
  display: inline-flex;
  align-items: center;
  min-height: 40px;
}
.header__end { gap: 22px; }
.langs { gap: 14px; }

@media (max-width: 480px) {
  /* On a phone the tab sits lower than the middle: the thumb reaches the
     bottom third of the screen, not its centre. */

}

/* --- Bouquet builder -------------------------------------------------------
 * The size is a set of chips; the drawing is an SVG of one circle per flower,
 * outlined while empty and filled with the flower's colour once chosen. There
 * are usually no photographs of single stems, so the colour stands in —
 * `flowers.colour_hex`, edited in the admin.
 *
 * The palette on the left is the part a customer reads most, so it is built
 * for reading: the photograph is twice the size it was, the name and the price
 * are set at body size rather than in fine print, and the padding around them
 * is tighter so the extra size costs no extra scrolling.
 */

.builder { display: grid; grid-template-columns: 400px 1fr; gap: clamp(24px, 4vw, 64px); align-items: start; }
.builder .field + .field { margin-top: 24px; }

.palette {
  display: grid;
  gap: 0;
  max-height: 560px;
  overflow-y: auto;
  margin-top: 10px;
}
.swatch {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 7px 8px;
  border: 1px solid transparent;
  /* Rows sit directly against each other; the line is the separation, which
     reads as a list rather than as a stack of loose boxes. */
  border-bottom-color: var(--line);
  text-align: left;
  font-size: 16px;
  line-height: 1.25;
}
.swatch:hover { background: #faf9f7; }
.swatch.is-on { border-color: var(--ink); background: #f6f6f4; }
/* The dot in the running total stays small: it is a marker in a line of text,
   not a card in the palette. */
.swatch__dot { width: 14px; height: 14px; border-radius: 50%; display: inline-block; border: 1px solid rgba(0, 0, 0, .12); flex: none; }
.swatch__name { overflow: hidden; text-overflow: ellipsis; }
.swatch__price { font-size: 16px; white-space: nowrap; }

.builder__stage { display: grid; gap: clamp(20px, 3vw, 40px); grid-template-columns: 1fr 300px; align-items: start; }
#builder-svg { width: 100%; aspect-ratio: 1; background: #f6f6f4; }

.cell {
  fill: #fff;
  stroke: var(--line);
  stroke-width: .6;
  cursor: pointer;
  transition: stroke .15s ease, opacity .15s ease;
}
.cell:hover { stroke: var(--ink); }
.cell.is-selected { stroke: var(--ink); stroke-width: 1.4; }
.cell.is-filled { stroke: rgba(0, 0, 0, .18); }

.builder__lines { list-style: none; padding: 0; margin: 16px 0; font-size: 13px; }
.builder__lines li { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.builder__actions { display: flex; gap: 8px; margin: 18px 0; }
.builder__actions .btn { flex: 1; padding: 13px 18px; }
.builder__summary .total { border-top: 1px solid var(--ink); padding-top: 14px; }

@media (max-width: 1100px) {
  .builder { grid-template-columns: 1fr; }
  .builder__stage { grid-template-columns: 1fr; }
  /* Two columns on a phone, and taller: the cards are bigger now, so a short
     scrolling box would show three of them. */
  .palette { grid-template-columns: repeat(2, 1fr); max-height: 340px; }
  .swatch { font-size: 15px; }
}

/* A palette entry shows the photograph of the stem where there is one, and the
   flat colour where there is not.
 *
 * On hover — and on keyboard focus, and while the flower is the one being
 * painted with — the photograph fades out and the colour underneath shows
 * through. That colour is what the circle in the bouquet will actually be, so
 * pointing at a flower answers "what will this look like in the drawing?"
 * before clicking anything. CSS only: no script, and it works for a finger
 * (:active) and a keyboard (:focus-visible) as well as a mouse. */
.swatch__mark {
  position: relative;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  /* The colour from the database, handed over as a custom property. */
  background: var(--flower);
  border: 1px solid rgba(0, 0, 0, .12);
  flex: none;
}
.swatch__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  transition: opacity .18s ease;
}
.swatch:hover .swatch__photo,
.swatch:focus-visible .swatch__photo,
.swatch:active .swatch__photo,
.swatch.is-on .swatch__photo { opacity: 0; }

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

.swatch__price s { color: var(--muted); margin-right: 4px; }

/* A bouquet in the cart is its own drawing rather than a photograph. */
.line__bouquet svg { width: 100%; height: auto; background: #f6f6f4; }

/* The pack size sits under the flower's name: the price beside it is for that
   many stems, not for one. */
.swatch__pack { display: block; color: var(--muted); font-size: 13px; margin-top: 1px; }
.builder__packs {
  background: #f6f6f4;
  padding: 12px 14px;
  margin-top: 12px;
  line-height: 1.55;
}
#builder-spare { color: var(--muted); }

/* The palette card holds two actions: the button that picks the flower covers
   the whole card and lies underneath, and the name is a link on top of it. A
   link inside a button would be invalid markup and would swallow the click. */
.swatch { position: relative; }
.swatch__pick {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.swatch__pick:focus-visible { outline: 1px solid var(--ink); outline-offset: -2px; }
.swatch__mark, .swatch__price { position: relative; pointer-events: none; }
.swatch__name { position: relative; }
.swatch__name a { text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--line); }
.swatch__name a:hover { text-decoration-color: var(--ink); }
.swatch__pack { pointer-events: none; }

/* --- Checkout ---------------------------------------------------------------
 * Form on the left, what is being bought on the right. Only the address and
 * the delivery day are collected here; the card is entered on Stripe's page,
 * which is why there is no payment section on this form at all.
 */

.checkout { display: grid; grid-template-columns: 1.25fr .75fr; gap: clamp(24px, 4vw, 64px); align-items: start; }
.checkout fieldset { border: 0; border-top: 1px solid var(--line); margin: 0 0 28px; padding: 22px 0 0; }
.checkout legend { padding: 0; }
.checkout .formats { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-top: 14px; }
.checkout label { display: block; }
.checkout label .label { display: block; margin-bottom: 6px; }
.checkout input,
.checkout select {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line);
  background: #fff;
  font: inherit;
}
.checkout input:focus-visible,
.checkout select:focus-visible { outline: 1px solid var(--ink); outline-offset: -2px; }

/* ---------- The words on the card (specs/0012) ----------
 * A sheet of a fixed size rather than a form field. Fixed on purpose - a drag
 * handle in the corner invites resizing a thing that has a real size, and a
 * box that grows under the pointer moves the button below it. What limits the
 * writing is `maxlength`, which the server enforces again; the height only
 * says how much of it is on screen, so a longer message scrolls inside.
 */
.card-note {
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: 136px;
  resize: none;
  margin: 0;
  padding: 12px 16px;
  border: 1px solid var(--line);
  background: #fff;
  font: inherit;
  font-size: 15px;
  line-height: 1.8;
  color: var(--ink);
  transition: border-color .25s ease;
}
.card-note::placeholder { color: var(--muted); }
.card-note:hover { border-color: var(--muted); }
.card-note:focus-visible { outline: 1px solid var(--ink); outline-offset: -2px; }
@media (max-width: 640px) { .card-note { height: 108px; } }

.checkout__stripe { color: var(--muted); margin-top: 14px; }
.checkout__summary { background: #f6f6f4; padding: clamp(18px, 3vw, 28px); }
.checkout__summary .line { grid-template-columns: 64px 1fr auto; padding: 14px 0; }
.checkout__summary .line__media img,
.checkout__summary .line__bouquet svg { width: 64px; }
.checkout-error {
  border-left: 2px solid var(--sale);
  background: #fdf3f1;
  padding: 14px 16px;
  margin-bottom: 24px;
}

/* The two rules that can close the way to the checkout: an address outside
   Poznan, and a basket under her minimum. Same treatment as an error the
   server sent back, because it is the same news. */
.checkout-blocked {
  border-left: 2px solid var(--sale);
  background: #fdf3f1;
  padding: 14px 16px;
  margin-top: 18px;
}

/* A button that is not a button. The blocked state renders a <span>, so
   there is nothing to click and nothing to middle-click into a new tab; this
   only has to make that visible. */
.btn--off,
.btn--off:hover {
  background: #e9e9e6;
  color: var(--muted);
  border-color: #e9e9e6;
  cursor: not-allowed;
}

/* The postal-code question, asked in the cart. */
.postal { margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--line); }
.postal__row { display: flex; gap: 10px; margin-top: 8px; }
.postal__row input {
  flex: 1 1 auto; min-width: 0;
  padding: 13px 14px; border: 1px solid var(--line); background: #fff;
  font: inherit; color: var(--ink);
}
.btn--small { padding: 12px 22px; min-height: 0; }
.postal__msg { margin-top: 10px; font-size: 13px; line-height: 1.6; color: var(--muted); }
.postal__msg--bad { color: var(--sale); }

@media (max-width: 900px) {
  .checkout { grid-template-columns: 1fr; }
  /* The summary comes first on a phone: it is what the visitor is deciding
     about, and the form is long. */
  .checkout__summary { order: -1; }
}

/* --- Cookie consent ---------------------------------------------------------
 * A bar across the bottom, not a modal: it must not cover the product the
 * visitor came for, and it must never be the thing that has to be dismissed
 * before the shop can be read. There is no close button — an ignored banner
 * is not consent, so it simply stays until one of the two buttons is pressed.
 *
 * Rendered in the page by the server, so it is styled here rather than being
 * drawn by a script.
 */

.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  background: #fff;
  border-top: 1px solid var(--line);
  box-shadow: 0 -8px 32px rgba(0, 0, 0, .06);
}
.consent[hidden] { display: none; }
.consent__inner {
  max-width: 1600px;
  margin: 0 auto;
  padding: 20px var(--pad);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: clamp(16px, 3vw, 48px);
  align-items: center;
}
.consent__text { max-width: 78ch; }
.consent__text .label { margin-bottom: 6px; }
.consent__text p + p { margin-top: 6px; }
.consent__actions { display: flex; gap: 12px; flex-wrap: wrap; }
.consent__actions .btn { white-space: nowrap; }

@media (max-width: 760px) {
  .consent__inner { grid-template-columns: 1fr; }
  /* Both buttons share the row on a phone, so neither reads as the default. */
  .consent__actions .btn { flex: 1 1 0; padding-left: 14px; padding-right: 14px; }
}

/* Gift cards applied to an order. Several are allowed, so they are a list
   rather than a field. */
.bon {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.bon__code { font-variant-numeric: tabular-nums; }
.bon__total { margin-top: 14px; font-size: 13px; color: var(--ink); }

/* ---------- Season (specs/0014) ----------
   A drop, at the top of the home page and on a page of its own. Deliberately
   the collection's own measures — a visitor arriving from her Instagram bio
   expects a picture, a name and a grid, not a layout they have to learn. */
.season-strip{padding-top:clamp(28px,4vw,56px)}
.season__media{display:block; aspect-ratio:16/9; background:#f6f6f4; overflow:hidden; margin-bottom:clamp(20px,3vw,36px)}
.season__media img{width:100%; height:100%; object-fit:cover}

/* ---------- Working with her (specs/0015) ---------- */
.enquiry__what{display:grid; grid-template-columns:1fr 1fr; gap:clamp(20px,3vw,44px); margin:clamp(24px,4vw,44px) 0}
.enquiry{display:flex; flex-direction:column; gap:18px; margin-top:clamp(20px,3vw,36px)}
.enquiry__sent{border-left:2px solid var(--ink); padding:12px 0 12px 16px; margin:24px 0}
/* The same treatment the checkout's fields have had since it was built, which
   this form never got: without it the label sits *beside* its box instead of
   above it, and every input is whatever width the browser felt like. Noticed
   on 2026-09-07 while adding the creators' form beneath it — both forms had it
   and both are fixed by these four rules. */
.enquiry label{display:block}
.enquiry label .label{display:block; margin-bottom:6px}
.enquiry input,
.enquiry textarea{
  width:100%; padding:12px 14px; border:1px solid var(--line);
  background:#fff; font:inherit;
}
.enquiry textarea{resize:vertical}
.enquiry input:focus-visible,
.enquiry textarea:focus-visible{outline:1px solid var(--ink); outline-offset:-2px}
/* The radio chips keep their own inline layout. */
.enquiry .fmt label{display:inline-block}
.enquiry .fmt input{width:auto}
@media (max-width:720px){.enquiry__what{grid-template-columns:1fr}}

/* ---------- Tiles (specs/0023) ----------
   Photographs that are also the navigation: she makes them in the admin, one
   picture and one word each. Built in the shop's own language — Work Sans in
   the small caps label, the hairline, the near-black — rather than lifted from
   the reference, which is a different shop with a different type.

   The grid is four columns on a wide screen and two on a phone; a large tile
   takes two of them. `aspect-ratio` rather than a fixed height, so a portrait
   catalogue frame and a landscape one crop the same way instead of one of them
   letterboxing.

   The pill lifts on hover and on keyboard focus, and does nothing at all under
   `prefers-reduced-motion`. It is never the only thing that says where a tile
   leads: the caption is present and legible before any interaction, because a
   label that appears on hover does not exist on a phone. */
.tiles{
  display:grid; gap:clamp(8px,1.2vw,18px);
  grid-template-columns:repeat(2,1fr);
}
@media (min-width:900px){ .tiles{grid-template-columns:repeat(4,1fr)} }
.tile{
  position:relative; display:block; overflow:hidden;
  background:var(--line);
}
.tile--large{grid-column:span 2}
.tile img{
  width:100%; height:100%; object-fit:cover; aspect-ratio:3/4;
  transition:transform .6s ease;
}
.tile--large img{aspect-ratio:3/2}
.tile__pill{
  position:absolute; left:12px; bottom:12px;
  padding:8px 14px; border-radius:999px;
  background:var(--bg); color:var(--ink);
  transition:transform .3s ease;
}
.tile:hover img, .tile:focus-visible img{transform:scale(1.03)}
.tile:hover .tile__pill, .tile:focus-visible .tile__pill{transform:translateY(-3px)}
@media (prefers-reduced-motion:reduce){
  .tile img, .tile__pill{transition:none}
  .tile:hover img, .tile:focus-visible img{transform:none}
  .tile:hover .tile__pill, .tile:focus-visible .tile__pill{transform:none}
}

/* ---------- The cover, the root page (specs/0023) ----------
   josephatelier.de's front rebuilt from its proportions, not from its code:
   two equal columns above 990px, the right one sticky and full height, the
   left one a square card, a 2×2 grid, a text block and the gift card. Below
   990px it unwraps into one column and the order changes — first card, then
   the standing column, then the grid — which is what the reference does.

   Type and colour stay gigi's: near-black on white, Work Sans, the hairline.
   The reference's pills are already white with a thin dark border, so the one
   thing that would have clashed — its pink CTA — is a white pill here too. */
.cover{display:flex; flex-direction:column}
.cover__left{display:contents}
.cover__left > *{order:4}
.cover__right{order:2}
.cover-card--large{order:1}
.cover-grid{order:3}

.cover__sticky{position:relative; width:100%; height:100vh; height:100dvh; overflow:hidden}
.cover-slides{position:absolute; inset:0; z-index:0}

/* The rotation: exactly the reference's, which is a cross-fade and not a slide
   — read out of its own stylesheet (`opacity`, `.45s ease`) and its own script
   (one second a photograph on the desktop, two on a phone; the slideshow does
   not run at all under `prefers-reduced-motion`, and hovering the column
   pauses it). All four of those are reproduced here.

   **The difference is that ours needs no script.** The reference toggles an
   `is-active` class on a timer; a script that fails there leaves half the page
   blank. The keyframes that drive this are written into the page by the
   template, because their percentages depend on how many photographs she has
   and CSS cannot compute a keyframe offset — so the timing is exact for any
   count rather than right for five and wrong for six.

   What is left here is only what does not depend on the count: the resting
   state, which is the first photograph and nothing else, so a browser that
   runs no animations shows a photograph rather than a hole. */
.cover-slide{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0;
}
.cover-slide:first-child{opacity:1}
@media (prefers-reduced-motion:reduce){
  .cover-slide{animation:none !important; opacity:0}
  .cover-slide:first-child{opacity:1}
}
/* Hovering the column stops it, as on the reference: a photograph somebody is
   looking at should not be taken away mid-look. */
@media (hover:hover){
  .cover__sticky:hover .cover-slide{animation-play-state:paused}
}

.cover-overlay{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(180deg,rgba(19,19,19,.20),rgba(19,19,19,.35));
}
/* Above every photograph, always. The rotation used to lift the slide whose
   turn it was above this, which covered the button and made it unclickable —
   the one control on the page, hidden by the decoration behind it. */
.cover-lead{
  position:relative; z-index:2; min-height:100%;
  display:flex; flex-direction:column; justify-content:flex-end; align-items:center;
  gap:20px; text-align:center; color:#fff; padding:52px 20px 22px;
}
.cover-lead__title{
  margin:0; max-width:346px; font-size:18px; font-weight:400; line-height:1.15;
}
.cover-lead__text{margin:0; max-width:24rem; font-size:15px; line-height:1.25}

/* The cards. `aspect-ratio` rather than a height, so a square catalogue frame
   and a portrait one crop the same way instead of one of them letterboxing. */
.cover-card{position:relative; display:block; width:100%; overflow:hidden; background:var(--line)}
.cover-card img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover}
.cover-card--large{aspect-ratio:374/528}
.cover-grid{display:grid; grid-template-columns:repeat(2,minmax(0,1fr))}
.cover-card--small{aspect-ratio:195/250}

.cover-pill{
  position:absolute; left:50%; bottom:56px; transform:translateX(-50%);
  display:inline-flex; align-items:center; justify-content:center;
  height:44px; padding:0 28px; border-radius:999px;
  background:var(--bg); color:var(--ink); border:.5px solid var(--ink);
  font-size:13px; line-height:1.2; white-space:nowrap;
  transition:background-color .25s ease, color .25s ease;
}
.cover-card:hover .cover-pill, .cover-card:focus-visible .cover-pill,
.cover-gift:hover .cover-pill, .cover-gift:focus-visible .cover-pill,
.cover-lead__button:hover, .cover-lead__button:focus-visible{
  background:var(--ink); color:var(--bg);
}
/* On a phone the small pills are simply there. The hover reveal below is for
   pointer devices only — a label that appears on hover does not exist on a
   touchscreen, and the card's own name is what a screen reader reads either
   way, since the whole card is the link. */
.cover-pill--reveal{bottom:16px; height:auto; padding:8px 16px; font-size:12px}
/* The one pill that is not laid on a photograph: it sits in the flow of the
   standing column's text. Declared after `.cover-pill` on purpose — it was
   before it at first, lost the cascade on equal specificity, and the button
   went and stood at the bottom of the viewport behind the cookie banner. */
.cover-lead__button{
  position:static; transform:none; left:auto; bottom:auto;
  width:100%; max-width:342px; height:52px;
}

.cover-text{display:flex; justify-content:center; width:100%; padding:100px 32px; margin-top:50px}
.cover-text__inner{width:100%; max-width:482px}
.cover-text__heading{margin:0 0 22px; font-size:20px; line-height:1.2; font-weight:600}
.cover-text__body{margin:0; font-size:14px; line-height:1.35}

.cover-gift{position:relative; display:block; width:100%; overflow:hidden; background:var(--line); aspect-ratio:390/422}
.cover-gift img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover}
.cover-gift::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(180deg,rgba(19,19,19,.05) 24%,rgba(19,19,19,.35));
}
.cover-gift__price{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); z-index:2;
  color:#fff; font-size:20px; font-weight:700; line-height:1; white-space:nowrap;
}
.cover-gift__button{bottom:56px; z-index:3; min-width:104px; padding:0 20px}

@media (min-width:990px){
  .cover{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:0}
  .cover__left{display:block; order:1; grid-column:1}
  .cover__right{order:2; grid-column:2}
  .cover__sticky{position:sticky; top:0; height:100vh}
  .cover-lead{justify-content:center; gap:40px; padding:38px}
  .cover-lead__title{font-size:24px}
  .cover-lead__text{font-size:16px}
  .cover-lead__button{width:auto; min-width:224px; height:44px}
  .cover-card--large{aspect-ratio:1/1}
  .cover-card--small{aspect-ratio:378/488}
  .cover-text{padding:132px 20px; margin-top:0; margin-bottom:50px}
  .cover-gift{aspect-ratio:756/491}
  /* Hidden until the card is hovered or something inside it is focused —
     `focus-within` is what keeps it reachable from a keyboard. */
  .cover-pill--reveal{opacity:0; transform:translate(-50%,16px); transition:opacity .28s ease, transform .28s ease}
  .cover-card--small:hover .cover-pill--reveal,
  .cover-card--small:focus-within .cover-pill--reveal{opacity:1; transform:translateX(-50%)}
}
@media (prefers-reduced-motion:reduce){
  .cover-pill--reveal{opacity:1 !important; transform:translateX(-50%) !important; transition:none}
}

/* The way in: the wordmark on white, then gone.

   **Its resting state is invisible.** The animation is what makes it appear at
   all, and the same animation takes it away again — so a browser that runs no
   animations, a stylesheet that half-loaded, a crawler, or anything else that
   goes wrong shows no overlay rather than a white sheet nailed over the shop
   for ever. Written the other way round first, and a headless screenshot
   caught it covering the whole page: exactly the failure the reference's own
   preloader has, arrived at from the opposite direction. */
.cover-intro{
  position:fixed; inset:0; z-index:60; display:grid; place-items:center;
  background:var(--bg); pointer-events:none;
  opacity:0; visibility:hidden;
}
.cover-intro span{font-size:clamp(28px,7vw,64px); letter-spacing:-.02em}
@media (prefers-reduced-motion:no-preference){
  .cover-intro{animation:cover-intro-out 1.1s ease forwards}
  .cover-intro span{animation:cover-intro-mark 1.1s ease forwards}
}
@keyframes cover-intro-out{
  0%{opacity:1; visibility:visible}
  55%{opacity:1; visibility:visible}
  100%{opacity:0; visibility:hidden}
}
@keyframes cover-intro-mark{
  0%{opacity:0; transform:translateY(6px)}
  35%{opacity:1; transform:none}
  100%{opacity:0}
}

/* ---------- The cover, in edit mode (specs/0023) ----------
   The panel's screen for the front page is the front page itself, inside an
   iframe, with a pencil in the top-right of every card. Rebuilding this layout
   a second time in the admin would leave two things to keep in step, and the
   one that is not the shop would be the one she is looking at.

   These rules only ever apply under `.cover--edit`, so nothing here can reach
   the page a customer sees. */
.cover-slot{position:relative}
.cover-edit{
  position:absolute; top:10px; right:10px; z-index:5;
  width:34px; height:34px; border-radius:999px;
  display:none; align-items:center; justify-content:center;
  background:var(--bg); color:var(--ink); border:.5px solid var(--ink);
  font-size:15px; line-height:1; cursor:pointer;
}
.cover-move{position:absolute; top:10px; right:52px; z-index:5; display:none; gap:4px}
.cover-move button{
  width:34px; height:34px; border-radius:999px;
  background:var(--bg); color:var(--ink); border:.5px solid var(--ink);
  font-size:14px; line-height:1; cursor:pointer;
}
.cover--edit .cover-edit{display:inline-flex}
.cover--edit .cover-move{display:inline-flex}
.cover-edit:hover, .cover-move button:hover{background:var(--ink); color:var(--bg)}
/* The standing column's pencil sits above its gradient and its text. */
.cover--edit .cover__sticky > .cover-edit{top:14px; right:14px; z-index:6}
/* The menu and its pencil are one cell of the header's grid, always — the
   wrapper is rendered whether or not the pencil is, so the public page and the
   editor lay the header out identically. Adding a fourth column only in edit
   mode moved the cart button on every page that is not the editor. */
.header__menu{display:flex; align-items:center; gap:2px; justify-self:start}
.cover-edit--menu{position:static; display:inline-flex}
/* Each entry inside the open menu, in the editor: the link keeps its own row
   and the pencil sits at the end of it. */
.menu-row{display:flex; align-items:center; gap:10px}
.menu-row > a{flex:1}
.cover-edit--row{position:static; display:inline-flex; width:30px; height:30px; font-size:13px}
/* The button's own pencil rides beside it rather than in a corner: it edits
   the words and the destination, not a picture. */
.cover--edit .cover-lead .cover-edit{position:static; margin-top:12px; display:inline-flex}
/* In the editor the small pills are always legible: she is arranging them, and
   a label that only appears on hover cannot be arranged. */
.cover--edit .cover-pill--reveal{opacity:1; transform:translateX(-50%)}

/* ---------- Her own logo (2026-09-08) ----------
   `web/static/logo.png` — the wordmark she drew, trimmed of its transparent
   margin and sized once at 1200px, which is retina for every place it is
   drawn. It ships with the code rather than living in `media/`: it is part of
   the design, not something she uploads and changes, and `media/` is not in
   the repository, so a logo there would be missing on a fresh deploy. */
.cover-lead__logo{
  width:min(78%, 340px); height:auto; margin-bottom:4px;
  /* Dark green on a darkened photograph does not read. `brightness(0)` makes
     every opaque pixel black and `invert(1)` makes it white, which keeps the
     shape and the transparency exactly and needs no second file.

     The shadow is what lets her put *any* photograph behind it: the gradient
     over the column is light (20% to 35%, the reference's own numbers), so a
     bright frame — white hydrangeas, a pale wall — would otherwise leave a
     white wordmark on white. */
  filter:brightness(0) invert(1) drop-shadow(0 1px 14px rgba(0,0,0,.5));
}
@media (min-width:990px){ .cover-lead__logo{width:min(70%, 420px)} }

.footer__logo{width:min(60%, 260px); height:auto}
.footer__bottom{display:flex; justify-content:center}
