/* ==================================================================
   BRare standard furniture — the house kit.

   Ships on EVERY BRare site. This is the static-site build of it:
   the Astro starter carries the same rules in src/styles/furniture.css
   and mounts them through SiteChrome.astro. Here the markup is inlined
   in each page and armed by site-chrome.js.

   Do not fork it per project — restyle it by redefining the palette
   tokens below. Everything here reads Joocy Smash's own tokens from
   style.css, so the kit wears the shop's clothes: 3px ink outline,
   hard offset shadow, pill radius, Anton on the labels.

   Two rules hold the whole thing together:
     1. Everything is token-driven, so it follows the palette.
     2. Everything is inert until site-chrome.js adds `.js-chrome`, so a
        visitor without JavaScript never sees a dead control. A floating
        button that cannot be dismissed, or a progress bar frozen at
        zero, is worse than no button and no bar.
   ================================================================== */

:root {
  /* The kit needs an error colour. --red is 4.35:1 on the cream ground,
     which is under the floor; --red-dark clears it at 6.13:1. */
  --color-error: var(--red-dark);

  /* Red and green each need a second value: one that works as a fill
     under white text, one that works as text on the dark panels.
     The brand pair on its own fails 4.5:1 in one direction or the
     other, and legibility is not negotiable. */
  --green-deep: #48822F;  /* white on it = 4.66:1  — fills */
  --red-light: #F5555B;   /* on the ink panel = 5.25:1 — text */
}

/* --- Skip link ----------------------------------------------------
   First thing in the tab order, invisible until it has focus. */
.skip-link {
  position: absolute;
  left: 12px;
  top: -200px;
  z-index: 200;
  background: var(--yellow);
  color: var(--ink);
  border: 3px solid var(--ink);
  border-radius: 999px;
  box-shadow: 4px 4px 0 var(--ink);
  font-family: var(--font-display);
  padding: 12px 22px;
  text-decoration: none;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 12px; }

/* --- Scroll progress ----------------------------------------------
   Sits on top of the sticky header's own bottom rule, so it reads as
   part of the header rather than a stripe floating over the page. */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--yellow);
  z-index: 60;
  pointer-events: none;
  display: none;
}
.js-chrome .scroll-progress { display: block; }

/* --- The floating stack (back-to-top + contact) --------------------
   Bottom-right, stacked, clear of the phone safe area. Hidden until
   the page has been scrolled past the hero, and gone entirely
   without JS. */
.floaties {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 55;
  display: none;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  /* THE CONTAINER MUST NOT TAKE CLICKS. It is invisible, but its box is
     stretched to the width and height of the contact menu inside it —
     240x400px pinned to the bottom-right corner of every page. The menu
     is `visibility: hidden` so the menu itself is inert, but the
     container is not, and it swallowed every click inside that
     rectangle: the carousel's next arrow, and on a phone both hero
     buttons, the phone number and the email link.
     Pointer events are handed back to the controls individually below.
     Never put `pointer-events: auto` back on this element. */
  pointer-events: none;
}
.js-chrome .floaties { display: flex; }
.floaties > .floatie,
.floaties > .contact-menu { pointer-events: auto; }
.floaties.is-shifted { bottom: calc(112px + env(safe-area-inset-bottom, 0px)); }

.floatie {
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  border: 3px solid var(--ink);
  border-radius: 999px;
  box-shadow: 3px 3px 0 var(--ink);
  background: var(--white);
  color: var(--ink);
  cursor: pointer;
  padding: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.18s ease, visibility 0.25s,
              background-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}
.floatie.is-shown { opacity: 1; visibility: visible; transform: none; }
.floatie-contact { background: var(--red); color: var(--white); }
@media (hover: hover) {
  .floatie:hover {
    background: var(--yellow);
    color: var(--ink);
    transform: translate(-2px, -2px);
    box-shadow: 5px 5px 0 var(--ink);
  }
  .floatie-contact:hover { background: var(--yellow); color: var(--ink); }
}
.floatie:active { transform: translate(1px, 1px); box-shadow: 1px 1px 0 var(--ink); }
.floatie svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.4; }

/* The contact button opens a short list rather than dialling straight
   away — a mis-tap that rings the shop mid-service is worse than one
   more tap. */
.contact-menu {
  display: grid;
  gap: 0;
  background: var(--white);
  border: 3px solid var(--ink);
  border-radius: 18px;
  box-shadow: 4px 4px 0 var(--ink);
  overflow: hidden;
  min-width: 15rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
.contact-menu[data-open='true'] { opacity: 1; visibility: visible; transform: none; }
.contact-menu a {
  padding: 12px 16px;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--line);
}
.contact-menu a:last-child { border-bottom: 0; }
.contact-menu a span {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
@media (hover: hover) {
  .contact-menu a:hover { background: var(--yellow); }
}

/* --- Cookie notice ------------------------------------------------
   The site sets no cookies of its own and runs no analytics. The one
   third party that can is the Google map on the Find Us page, so the
   notice says that and nothing more. It is never a consent wall — if
   analytics is ever added it has to become one. */
.cookie-note {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 70;
  background: var(--bg);
  border-top: 4px solid var(--ink);
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  display: none;
}
.cookie-note[data-open='true'] { display: block; }
.cookie-note-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 28px;
}
.cookie-note p { margin: 0; max-width: 62ch; font-size: 0.92rem; color: var(--ink-soft); }
.cookie-note .btn { padding: 10px 22px; font-size: 0.9rem; }

/* --- Copy to clipboard --------------------------------------------
   The number and address stay selectable either way; this is a
   shortcut, not the only route. */
.copy-btn {
  display: none;
  margin-left: 8px;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--yellow);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 10px;
  cursor: pointer;
  vertical-align: middle;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.js-chrome .copy-btn { display: inline-block; }
@media (hover: hover) {
  .copy-btn:hover { background: var(--red); color: var(--white); }
}
.copy-btn[data-done='true'] { background: var(--green-deep); color: var(--white); }

/* --- Form states --------------------------------------------------
   Errors are spoken by the field itself, not an alert box at the top,
   so the fix is next to the problem. */
.form-field input[aria-invalid='true'],
.form-field textarea[aria-invalid='true'] {
  border-color: var(--color-error);
  background: #FFF1F1;
}
.field-error {
  display: none;
  margin: 6px 0 0;
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--color-error);
}
.field-error[data-shown='true'] { display: block; }

.form-status {
  display: none;
  margin: 0 0 18px;
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: var(--white);
  box-shadow: 4px 4px 0 var(--ink);
  padding: 14px 18px;
  font-weight: 600;
  max-width: none;
}
.form-status[data-shown='true'] { display: block; }
.form-status[data-tone='bad'] { background: #FFF1F1; border-color: var(--color-error); box-shadow: 4px 4px 0 var(--color-error); }
.form-status[data-tone='good'] { background: var(--yellow); }
.form-status h3 { margin: 0 0 4px; }
.form-status p { margin: 0; max-width: none; }

.btn[disabled], .btn[aria-disabled='true'] {
  opacity: 0.65;
  cursor: progress;
  transform: none;
  box-shadow: 2px 2px 0 var(--ink);
}

/* --- FAQ ----------------------------------------------------------
   Native <details>, so it opens without JS and prints open. */
.faq-list { max-width: 760px; }
.faq {
  border: 3px solid var(--ink);
  border-radius: 18px;
  background: var(--white);
  box-shadow: 4px 4px 0 var(--ink);
  margin-bottom: 14px;
}
.faq summary {
  cursor: pointer;
  list-style: none;
  padding: 16px 52px 16px 20px;
  position: relative;
  font-family: var(--font-display);
  font-size: 1.15rem;
  line-height: 1.2;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+';
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--red-dark);
}
.faq[open] summary::after { content: '\2212'; }
@media (hover: hover) { .faq summary:hover { color: var(--red-dark); } }
.faq > div { padding: 0 20px 18px; color: var(--ink-soft); }
.faq > div p { margin: 0; max-width: 62ch; }

/* --- Scroll-in entrances -------------------------------------------
   The hiding rule is gated on `.js-reveal`, which the inline head
   script adds ONLY when JS is running and reduced motion is not
   requested. No JS, or reduced motion, and nothing is ever hidden.
   The head script also arms a watchdog that ungates everything if the
   observer never runs — a failed reveal would otherwise leave a blank
   page, which is far worse than no animation. */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
}
.js-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s ease, transform 0.6s ease;
}

/* --- Motion --------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .floatie, .contact-menu, .copy-btn, .scroll-progress, .skip-link { transition: none; }
  .floatie:hover, .floatie:active { transform: none; }
  .js-reveal [data-reveal] { opacity: 1; transform: none; }
}

/* --- Print ---------------------------------------------------------
   Someone printing this wants the address, the hours and the menu on
   paper, in ink they paid for. The dark grounds, the chrome, the map
   and the video all come off; link targets get written out. */
@media print {
  :root {
    --bg: #fff;
    --ink: #000;
    --ink-soft: #333;
    --white: #fff;
    --line: #999;
  }
  body { background: #fff !important; color: #000 !important; font-size: 12pt; }
  header.site-header, .scroll-progress, .floaties, .cookie-note, .skip-link,
  .hero-scroll, .zigzag, .carousel-arrow, .carousel-dots, .copy-btn,
  iframe, video, form, .nav-order-btn, .hero-scroll-hint, .cheese-splat,
  .find-strip-bg, .find-strip-fade { display: none !important; }
  .dark-panel, .combo-section, .site-footer, .find-strip, .grass-fed-strip {
    background: #fff !important;
    color: #000 !important;
  }
  .dark-panel h2, .dark-panel .lede, .combo-text h3, .combo-text p,
  .site-footer, .site-footer a, .site-footer h4, .site-footer p,
  .grass-fed-strip-inner p, .find-strip-content, .find-strip-content h2,
  .find-strip-content p, .highlight-card, .highlight-card h3, .highlight-card p {
    color: #000 !important;
  }
  .highlight-card, .combo-text, .review-card, .faq, .rating-badge {
    border: 1px solid #999 !important;
    box-shadow: none !important;
    background: #fff !important;
  }
  .js-reveal [data-reveal] { opacity: 1 !important; transform: none !important; }
  .faq > div { display: block !important; }
  .faq summary::after { content: '' !important; }
  a[href^='http']::after,
  a[href^='mailto:']::after,
  a[href^='tel:']::after { content: ' (' attr(href) ')'; font-size: 0.8em; word-break: break-all; }
  img { max-width: 55% !important; page-break-inside: avoid; }
  section, .faq, .highlight-card, .review-card { page-break-inside: avoid; }
}

/* --- Screen-reader only ---------------------------------------------- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Unconfirmed facts ----------------------------------------------
   A fact the client has not supplied renders as a visible yellow mark
   rather than being quietly guessed, and is left out of the structured
   data. These are the mechanism that stops an invented trading detail
   shipping — don't tone them down, fill the value in and delete the
   mark. */
.todo {
  display: inline-block;
  background: var(--yellow);
  color: var(--ink);
  border: 2px dashed var(--ink);
  border-radius: 10px;
  padding: 6px 12px;
  font-weight: 600;
  font-size: 0.9rem;
}
