/* Hallmark · pre-emit critique: P5 H4 E5 S4 R5 V5 · genre: editorial · theme: platform demo chrome · macrostructure: Long Document · tone: quiet utility · anchor hue: antique brass · enrichment: none · contrast: pass (40–41) · nav: sticky top bar, always-visible controls · footer: N/A · slop: pass (all 58 gates; 42–45) · honest: pass (46) · chrome: pass (47) · tokens: pass (48) · responsive: pass (49) · icons: pass (30) · mobile: pass (34, 49, 50–57) */

:root {
  --demo-chrome-ink: oklch(0.95 0.012 82);
  --demo-chrome-muted: oklch(0.72 0.016 76);
  --demo-chrome-surface: oklch(0.18 0.018 66);
  --demo-chrome-surface-raised: oklch(0.235 0.022 68);
  --demo-chrome-rule: oklch(0.36 0.018 68);
  --demo-chrome-accent: oklch(0.79 0.105 82);
  --demo-chrome-stage: oklch(0.91 0.016 78);
  --demo-chrome-focus: oklch(0.87 0.13 82);
  --demo-chrome-shadow: 0 1px 2px oklch(0.16 0.014 66 / 0.14);
  --demo-chrome-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --demo-chrome-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --demo-chrome-z-sticky: 200;
  /* The bar's own rendered height (padding-block 0.75rem*2 + the 2.75rem
     device/CTA row) — used to size the Tablet/Mobile scroll area below it.
     An approximation: a notch's safe-area-inset-top can add a few px the bar
     itself absorbs, which the stage's own overflow: auto quietly covers. */
  --demo-chrome-bar-height: 4.3125rem;
}

html,
body {
  overflow-x: clip;
}

/* A slim, on-brand scrollbar for the whole preview surface — the outer page
   in Desktop mode, and the device-preview iframe's own document in
   Tablet/Mobile — instead of each browser's bulky native default. Reuses the
   chrome's own rule/muted tones, so it reads as part of this design rather
   than an unstyled system control. */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--demo-chrome-rule) transparent;
}

::-webkit-scrollbar {
  width: 0.5rem;
  height: 0.5rem;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--demo-chrome-rule);
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: 999px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--demo-chrome-muted);
  background-clip: padding-box;
}

::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

::-webkit-scrollbar-corner {
  background: transparent;
}

/* The chrome and the stage own this page's shell, so the theme's own body box
 * cannot inset it — minimalist floats its sheet on a padded desk, which would
 * otherwise push the bar down the page on that theme alone. */
body {
  margin: 0;
  padding: 0;
}

/* This chrome is injected into the theme's own document, where the only reset
 * is whatever that theme happened to declare — some scope theirs to their root
 * class, some declare none. Every platform-owned element here sizes itself. */
.demo-invitation-chrome,
.demo-invitation-chrome *,
.demo-invitation-chrome *::before,
.demo-invitation-chrome *::after,
.demo-invitation-stage,
.demo-invitation-stage__embed,
.invite-frame {
  box-sizing: border-box;
}

/* A real top navbar, not a floating overlay: sticky and in normal document
   flow, so it reserves its own space and pushes the invitation down rather
   than sitting on top of it. Identity and controls sit directly in it —
   always visible, macOS/Ubuntu-menu-bar style, no click-to-reveal step. */
.demo-invitation-chrome {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--demo-chrome-z-sticky);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  padding-inline: max(0.75rem, env(safe-area-inset-left)) max(0.75rem, env(safe-area-inset-right));
  padding-block: max(0.75rem, env(safe-area-inset-top)) 0.75rem;
  color: var(--demo-chrome-ink);
  font-family: var(--demo-chrome-font);
  font-size: 0.6875rem;
  font-style: normal;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: normal;
  word-spacing: normal;
  text-align: left;
  text-transform: none;
  background: var(--demo-chrome-surface);
  border-block-end: 1px solid var(--demo-chrome-rule);
  box-shadow: var(--demo-chrome-shadow);
}

.demo-invitation-chrome__device-input:focus-visible + .demo-invitation-chrome__device,
.demo-invitation-chrome__cta:focus-visible {
  outline: 2px solid var(--demo-chrome-focus);
  outline-offset: 3px;
}

/* Groups the device switcher and the CTA on the bar's trailing edge. Never
   shrinks — the escape hatch (the CTA) always keeps its full size; identity
   on the leading edge is what gives way first if space ever runs out. */
.demo-invitation-chrome__controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-shrink: 0;
}

.demo-invitation-chrome__identity {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}

.demo-invitation-chrome__brand,
.demo-invitation-chrome__theme {
  overflow: hidden;
  font-size: 0.6875rem;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.demo-invitation-chrome__brand {
  color: var(--demo-chrome-ink);
  font-weight: 650;
}

.demo-invitation-chrome__theme {
  color: var(--demo-chrome-muted);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
}

.demo-invitation-chrome__devices {
  display: none;
  gap: 0.5rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Icon + label already say what each button does — a real menu bar doesn't
   caption its icon groups. Kept for assistive tech, not sighted users. */
.demo-invitation-chrome__devices-legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  clip-path: inset(50%);
}

.demo-invitation-chrome__device-options {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.25rem;
}

.demo-invitation-chrome__device-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  clip-path: inset(50%);
}

.demo-invitation-chrome__device {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0.5rem;
  color: var(--demo-chrome-muted);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: 0.125rem;
  transition:
    color 180ms var(--demo-chrome-ease),
    background-color 180ms var(--demo-chrome-ease),
    border-color 180ms var(--demo-chrome-ease),
    transform 100ms var(--demo-chrome-ease);
}

.demo-invitation-chrome__device:active {
  color: var(--demo-chrome-accent);
  background: var(--demo-chrome-surface);
  transform: translateY(1px);
}

.demo-invitation-chrome__device-input:disabled + .demo-invitation-chrome__device {
  cursor: not-allowed;
  opacity: 0.55;
}

.demo-invitation-chrome__device-input:checked + .demo-invitation-chrome__device {
  color: var(--demo-chrome-accent);
  background: var(--demo-chrome-surface-raised);
  border-color: var(--demo-chrome-rule);
}

.demo-invitation-chrome__device-icon {
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  width: 0.9rem;
  height: 0.7rem;
  border: 1px solid currentColor;
  border-radius: 0.08rem;
}

.demo-invitation-chrome__device-icon::after {
  position: absolute;
  right: 0.15rem;
  bottom: -0.22rem;
  left: 0.15rem;
  height: 1px;
  content: "";
  background: currentColor;
}

.demo-invitation-chrome__device-icon--tablet {
  width: 0.68rem;
  height: 0.88rem;
}

.demo-invitation-chrome__device-icon--tablet::after {
  right: 0.12rem;
  bottom: -0.16rem;
  left: 0.12rem;
}

.demo-invitation-chrome__device-icon--mobile {
  width: 0.5rem;
  height: 0.88rem;
  border-radius: 0.1rem;
}

.demo-invitation-chrome__device-icon--mobile::after {
  right: 0.08rem;
  bottom: -0.16rem;
  left: 0.08rem;
}

.demo-invitation-chrome__cta {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  min-height: 2.75rem;
  color: var(--demo-chrome-accent);
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.1em;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.demo-invitation-chrome__cta-long,
.demo-invitation-chrome__cta-short {
  padding-bottom: 0.2rem;
  border-bottom: 1px solid color-mix(in oklab, var(--demo-chrome-accent) 55%, transparent);
  transition: border-color 180ms var(--demo-chrome-ease);
}

.demo-invitation-chrome__cta-long {
  display: none;
}

.demo-invitation-chrome__cta:active {
  color: var(--demo-chrome-ink);
  transform: translateY(1px);
}

.demo-invitation-stage {
  min-height: 100dvh;
  background: transparent;
}

/* Desktop keeps the ordinary document: the bar stays sticky, the body
   scrolls, matching how the real guest page actually behaves — nothing here
   applies to it. Tablet/Mobile trade that for an app-shell split instead:
   the body itself never scrolls, and .demo-invitation-stage below is taken
   out of flow entirely (position: fixed, offset by the bar's own height) so
   it alone owns a scrollbar — regardless of what a theme happens to place in
   body before its own .invite-frame (icon-sprite <svg data:>, etc.); a grid
   row assignment would have depended on exactly which element comes where,
   fixed positioning doesn't care. A theme's own scroll-driven JS
   (IntersectionObserver reveals, window-scroll listeners) still targets the
   real window either way — it's the device frame's own iframe document that
   scrolls, an independent browsing context with its own window, exactly like
   a real phone or tablet already is. */
body:has(#demo-device-tablet:checked),
body:has(#demo-device-mobile:checked) {
  overflow: hidden;
}

/* Scoped to pages that actually carry the chrome (desktop-mode top-level
   render). The bare `?embed=1` document this same stylesheet now also loads
   into has no .demo-invitation-chrome, so this stays inert there — .invite-frame
   behaves exactly like it does on the real guest page, with no container-type
   ancestor to trap a theme's `position: fixed` children. */
body:has(.demo-invitation-chrome) .invite-frame {
  container: invite-frame / inline-size;
  width: 100%;
  max-width: none;
}

/* Tablet/Mobile hand off to a same-origin iframe instead of boxing this
   element down: a CSS max-width squeeze leaves the real document viewport
   unchanged, so a theme's plain `@media` breakpoints (as opposed to
   `@container invite-frame` ones) never see a narrower width. The iframe's
   own nested document gets a real layout viewport equal to its rendered box
   size, so every theme's breakpoints respond correctly regardless of which
   query type it uses. It starts with no `src` — demo_invitation_chrome.js
   activates it on first selection. */
.demo-invitation-stage__embed {
  display: none;
  width: 100%;
  border: 0;
}

body:has(#demo-device-tablet:checked) .demo-invitation-stage,
body:has(#demo-device-mobile:checked) .demo-invitation-stage {
  position: fixed;
  inset-block: var(--demo-chrome-bar-height) 0;
  inset-inline: 0;
  min-height: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  padding: clamp(1rem, 3vw, 2.5rem);
  background: var(--demo-chrome-stage);
}

body:has(#demo-device-tablet:checked) .invite-frame,
body:has(#demo-device-mobile:checked) .invite-frame {
  display: none;
}

body:has(#demo-device-tablet:checked) .demo-invitation-stage__embed,
body:has(#demo-device-mobile:checked) .demo-invitation-stage__embed {
  display: block;
}

/* Sized to the device's own screen, not the invitation's content height —
   the iframe scrolls internally, the way a real phone or tablet does. */
body:has(#demo-device-tablet:checked) .demo-invitation-stage__embed {
  max-width: 48rem;
  height: min(64rem, calc(100dvh - var(--demo-chrome-bar-height) - 5rem));
}

body:has(#demo-device-mobile:checked) .demo-invitation-stage__embed {
  max-width: 24.375rem;
  height: min(52.75rem, calc(100dvh - var(--demo-chrome-bar-height) - 5rem));
}

/* The acknowledgement replaces the RSVP form inside the invitation itself, so
   it has to sit inside whatever band the theme put there. */
.demo-invitation-chrome--confirmation {
  position: relative;
  inset: auto;
  z-index: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.125rem;
  max-width: 30rem;
  margin: 1rem auto;
  padding: 2rem 1.5rem;
  color: inherit;
  text-align: center;
  background: color-mix(in oklab, currentColor 8%, transparent);
  border: 1px solid color-mix(in oklab, currentColor 28%, transparent);
  box-shadow: none;
  /* The opposite of the bar above: this one sits inside the theme's own RSVP
   * band, so it takes that theme's typography back. */
  font: inherit;
  letter-spacing: normal;
  pointer-events: auto;
}

.demo-invitation-chrome--confirmation .rsvp-confirmation__message {
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.6;
}

.demo-invitation-chrome--confirmation a {
  min-height: 2.5rem;
  padding-block: 0.75rem;
  color: inherit;
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
  border-bottom-color: color-mix(in oklab, currentColor 45%, transparent);
}

.demo-invitation-chrome--confirmation a:focus-visible {
  outline-color: currentColor;
}

@media (min-width: 40.001rem) {
  .demo-invitation-chrome__devices {
    display: grid;
  }

  .demo-invitation-chrome__cta-long {
    display: inline;
  }

  .demo-invitation-chrome__cta-short {
    display: none;
  }
}

@media (hover: hover) and (pointer: fine) {
  .demo-invitation-chrome__device:hover {
    color: var(--demo-chrome-ink);
    border-color: var(--demo-chrome-rule);
  }

  .demo-invitation-chrome__cta:hover span {
    border-bottom-color: var(--demo-chrome-accent);
  }

  .demo-invitation-chrome--confirmation a:hover {
    border-bottom-color: currentColor;
  }
}

@media (prefers-reduced-motion: reduce) {
  .demo-invitation-chrome__device,
  .demo-invitation-chrome__cta {
    transition-duration: 0.01ms;
    animation-duration: 0.01ms;
  }
}
