/*
 * widget-theme.css — hand-authored companion stylesheet for the SSR widget.
 * NOT a Tailwind build; linked only by the widget shells (never admin), and
 * scoped under #widget-root so the maket type scale never bleeds into admin
 * typography.
 *
 * Contents:
 *   1. maket fluid clamp() type scale (overrides stock Tailwind font sizes,
 *      and defines the non-stock `text-s`/`text-md` tokens the widget uses).
 *   2. body scrollbar hidden (the 6px thumb only shows on inner scroll areas;
 *      those live in _theme.html, which is theme-dependent).
 *   3. intl-tel-input phone-field styling (appended for the contact screen).
 */

/* ── 1. maket fluid type scale ──────────────────────────────────────────── */
#widget-root .text-xs   { font-size: clamp(0.78rem, -0.11vw + 0.81rem, 0.72rem); line-height: calc(clamp(0.78rem, -0.11vw + 0.81rem, 0.72rem) * 1.1); }
#widget-root .text-s    { font-size: clamp(0.83rem, 0.05vw + 0.82rem, 0.86rem);  line-height: calc(clamp(0.83rem, 0.05vw + 0.82rem, 0.86rem) * 1.1); }
#widget-root .text-base { font-size: clamp(0.89rem, 0.26vw + 0.82rem, 1.03rem);  line-height: calc(clamp(0.89rem, 0.26vw + 0.82rem, 1.03rem) * 1.1); }
#widget-root .text-md   { font-size: clamp(0.95rem, 0.53vw + 0.82rem, 1.24rem);  line-height: calc(clamp(0.95rem, 0.53vw + 0.82rem, 1.24rem) * 1.1); }
#widget-root .text-lg   { font-size: clamp(1.01rem, 0.87vw + 0.8rem, 1.49rem);   line-height: calc(clamp(1.01rem, 0.87vw + 0.8rem, 1.49rem) * 1.1); }
#widget-root .text-xl   { font-size: clamp(1.08rem, 1.29vw + 0.76rem, 1.79rem);  line-height: calc(clamp(1.08rem, 1.29vw + 0.76rem, 1.79rem) * 1.1); }
#widget-root .text-2xl  { font-size: clamp(1.15rem, 1.81vw + 0.7rem, 2.15rem);   line-height: calc(clamp(1.15rem, 1.81vw + 0.7rem, 2.15rem) * 1.1); }
#widget-root .text-3xl  { font-size: clamp(1.23rem, 2.45vw + 0.62rem, 2.58rem);  line-height: calc(clamp(1.23rem, 2.45vw + 0.62rem, 2.58rem) * 1.1); }
#widget-root .text-4xl  { font-size: clamp(1.31rem, 3.23vw + 0.5rem, 3.09rem);   line-height: calc(clamp(1.31rem, 3.23vw + 0.5rem, 3.09rem) * 1.1); }

/* ── 1b. StepBar segmented pill (static; colors come from the theme block) ── */
#widget-root .step-seg { border-radius: 0 !important; }
#widget-root .step-seg[data-first="true"] { border-start-start-radius: 9999px !important; border-end-start-radius: 9999px !important; }
#widget-root .step-seg[data-last="true"] { border-start-end-radius: 9999px !important; border-end-end-radius: 9999px !important; }
#widget-root .step-seg[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
#widget-root .step-seg:not([data-active="true"]):not([aria-disabled="true"]):hover { background-color: color-mix(in srgb, currentColor 6%, transparent); }

/* ── 2. body scrollbar hidden + full-height shell (widget shells only) ──── */
html, body { height: 100%; }
body::-webkit-scrollbar { width: 0; display: none; }
body { scrollbar-width: none; }

/* ---------------------------------------------------------------------------
   International phone input (intl-tel-input) — the legacy widget's bespoke
   two-box styling, verbatim (app.css): a separate bordered flag box + a
   separate bordered input box, plus a searchable country dropdown.
   intl-tel-input builds .iti__* nodes at runtime (and on mobile appends the
   dropdown to <body>), so the rules live here, namespaced under .widget-iti /
   #phone. The .iti--fullscreen-popup rules at the bottom are intentionally
   NOT namespaced because that popup renders outside the widget wrapper. Box
   border and radius mirror the sibling text inputs (1px #c7c7c7, --w-radius).
   --------------------------------------------------------------------------- */
.widget-iti.iti {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: 8px;
  width: 100%;
}
.widget-iti .iti__country-container {
  position: static;
  flex: 0 0 auto;
  display: flex;
  align-items: stretch;
  border: 1px solid #c7c7c7;
  border-radius: var(--w-radius);
  background: #fff;
}
.widget-iti .iti__selected-country {
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  padding: 0 14px;
  gap: 8px;
  cursor: pointer;
}
.widget-iti .iti__selected-country-primary {
  padding: 0;
}
.widget-iti .iti__arrow {
  width: 7px;
  height: 7px;
  border: 0;
  border-right: 2px solid #6b7280;
  border-bottom: 2px solid #6b7280;
  border-radius: 1px;
  transform: rotate(45deg);
  position: relative;
  top: -2px;
  margin-left: 4px;
}
.widget-iti .iti__arrow--up {
  transform: rotate(-135deg);
  top: 2px;
}
.widget-iti #phone {
  flex: 1 1 auto;
  width: 100%;
  min-height: 50px;
  padding: 0 14px !important;
  border: 1px solid #c7c7c7;
  border-radius: var(--w-radius);
  background: #fff;
  font-size: 16px;
  color: inherit;
}
.widget-iti #phone:focus {
  outline: none;
  border-color: #6b7280;
}
/* Half-width phone cell: from 960px the contact grid pairs phone with email (below that
   the cell spans both columns), so the input must be allowed to drop under its
   content-based automatic minimum — otherwise the ~71px flag box + number overflow the
   220px column. Has to live here rather than as a Tailwind `min-w-0` on the element:
   `.widget-iti #phone` is an ID selector and would win against a utility. */
@media (min-width: 960px) {
  .widget-iti #phone { min-width: 0; }
}
/* Summary rail heading (desktop): beside the form the recap card is a one-third rail, not
   a co-equal panel, so its heading steps off the fluid `.text-md` ramp above (~19.8px at
   1512px) down to a flat 14px, sitting just above the 12px row values. Scoped under
   #widget-root for the same reason as the .contact-form inputs below — the ramp is an ID
   selector, so a `md:text-sm` utility would lose to it. Gated at md: so the full-width
   mobile card keeps the ramp untouched. */
@media (min-width: 768px) {
  #widget-root .summary-title { font-size: 14px; line-height: 1.3; }
}
/* Date and pax squares carry no size rule of their own — the tile is whatever
   `grid-cols-7 gap-1` divides the wrapper into, with aspect-square making the
   height follow. On the 600px desktop card the wrapper pins at its max-w-[480px]
   and each square lands at 65px, oversized next to the desktop type scale; 450px
   brings them to 61px. Phones are untouched: the cap only binds once the panel
   exceeds 450px (~490px viewport), so below the md gate the computed width is
   identical either way. Slots share the wrapper utilities but not `.tile-grid`,
   which is why this needs its own hook rather than keying on max-w-[480px]. */
@media (min-width: 768px) {
  #widget-root .tile-grid { max-width: 450px; }
}
/* >=16px avoids iOS Safari focus-zoom on the contact fields (mirrors #phone and
   the .iti fullscreen search). Higher specificity than the `#widget-root
   .text-base` clamp so it wins for the email/name/notes/country controls. */
#widget-root .contact-form input,
#widget-root .contact-form select,
#widget-root .contact-form textarea {
  font-size: 16px;
}
/* Desktop contact-form type scale (>=768px). The recap rail runs at 14/12px, so the form
   sits one step above it instead of three — the previous desktop scale was five scattered
   sizes (28.6 / 16.5 / 16 / 14 / 12.5); this is four (20 / 16 / 13 / 12).

   INPUTS DELIBERATELY KEEP THEIR 16px from the rule above: that guards iOS Safari
   focus-zoom, which fires on iPad too, and iPads land inside this md: range. It also
   matches theFork's own contact step (13px label over a 16px input) — the typed value
   stays the largest text on the form and the labels step down around it.

   Scoped under #widget-root and placed after the 16px rule so these win over the fluid
   .text-* ramp at the top of this file (id+class+type beats id+class). Gated at md: so
   the phone layout keeps the ramp untouched. */
@media (min-width: 768px) {
  #widget-root .contact-form h2                    { font-size: 20px; line-height: 1.25; }
  #widget-root .contact-form label,
  #widget-root .contact-form legend,
  #widget-root .contact-form label span            { font-size: 13px; line-height: 1.3; }
  #widget-root .contact-form span[role='alert'],
  #widget-root .contact-form p                     { font-size: 12px; line-height: 1.3; }
  #widget-root .contact-form div[role='alert'],
  #widget-root .contact-form div[role='status']    { font-size: 13px; line-height: 1.4; }
  #widget-root .contact-form button[type='submit'] { font-size: 14px; line-height: 1.2; }
}
/* The credit-card guarantee sits inside the recap card, which is OUTSIDE
   `.contact-form` — so this rule must not be scoped to the form (the md: block
   above would then never match it either, which is fine: this is the only size
   it needs). (1,1,2) still beats the `.text-*` clamp ramp at the top of this
   file, which is why the element carries no Tailwind size utility. It runs one
   step above the card's own 14/12px scale because it is the one line announcing
   a financial commitment. */
#widget-root div[role='status'].preauth-notice {
  font-size: 15px;
  line-height: 1.45;
}
.widget-iti .iti__dropdown-content {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 6px;
  margin-left: 0;
  border: 1px solid #d1d5db;
  border-radius: var(--w-radius);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  overflow: hidden;
  background: #fff;
  z-index: 20;
}
[dir='rtl'] .widget-iti .iti__dropdown-content {
  direction: rtl;
  text-align: right;
}
[dir='rtl'] .widget-iti #phone {
  text-align: right;
}
.widget-iti.iti,
.iti--fullscreen-popup {
  --iti-flag-width: 24px;
  --iti-flag-height: 18px;
  --iti-flag-sprite-width: 5856px;
  --iti-flag-sprite-height: 18px;
  --iti-path-flags-1x: url("/static/intl-tel-input/img/flags.webp");
  --iti-path-flags-2x: url("/static/intl-tel-input/img/flags@2x.webp");
  --iti-path-globe-1x: url("/static/intl-tel-input/img/globe.webp");
  --iti-path-globe-2x: url("/static/intl-tel-input/img/globe@2x.webp");
}
.widget-iti .iti__flag,
.iti--fullscreen-popup .iti__flag {
  background-position: calc(var(--iti-flag-offset, 100px) * 1.5) 0;
  border-radius: 3px;
}
.widget-iti .iti__search-input {
  width: calc(100% - 24px);
  margin: 12px;
  padding: 10px 12px;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  font-size: 14px;
  box-sizing: border-box;
}
.widget-iti .iti__search-input:focus {
  outline: none;
  border-color: #9ca3af;
}
.widget-iti .iti__search-input + .iti__country-list {
  border-top: none;
}
.widget-iti .iti__country-list {
  max-height: 240px;
  padding-bottom: 4px;
  overflow-y: auto;
}
.widget-iti .iti__country {
  margin: 1px 8px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 15px;
}
.widget-iti .iti__country-list .iti__flag {
  margin-right: 12px;
}
[dir='rtl'] .widget-iti .iti__country-list .iti__flag {
  margin-right: 0;
  margin-left: 12px;
}
.widget-iti .iti__country-name,
.iti--fullscreen-popup .iti__country-name {
  font-weight: 600;
}
.widget-iti .iti__dial-code,
.iti--fullscreen-popup .iti__dial-code {
  color: #6b7280;
}
.widget-iti .iti__country.iti__highlight {
  background-color: #f3f4f6;
}
.iti--fullscreen-popup .iti__search-input {
  font-size: 16px; /* >=16px avoids iOS focus-zoom */
  padding: 14px 16px;
}
.iti--fullscreen-popup .iti__country {
  padding: 12px 16px;
}

/* ---------------------------------------------------------------------------
   Step-pill loading ring — the legacy StepBar <Spinner size=16 width=2>
   (gray #e5e7eb track, themed arc, 0.8s rotation), shown in the current
   segment while an htmx panel request is in flight. Visibility is driven by
   htmx's indicator lifecycle (.htmx-indicator opacity swap); the ring spins
   permanently, invisible when idle.
   --------------------------------------------------------------------------- */
.step-spinner {
  width: 16px;
  height: 16px;
  border: 2px solid #e5e7eb;
  border-bottom-color: currentColor;
  border-radius: 50%;
  box-sizing: border-box;
  animation: etw-rotation 0.8s linear infinite;
  /* Override htmx's 200ms ease-in: a 60ms hold keeps instant responses
     flicker-free, then the ring pops in fast enough to register on
     150-400ms round-trips (tunnel / mobile). */
  opacity: 0;
  transition: opacity 80ms ease-in 60ms;
}
.step-spinner.htmx-request,
.step-spinner.nav-loading {
  opacity: 1;
}
@keyframes etw-rotation {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

/* ---------------------------------------------------------------------------
   In-button loader for pages WITHOUT a step-bar (contact submit, Stripe button,
   and every standalone white page: manage / reconfirmation / review /
   leave-a-review). The VISUAL is DaisyUI's `loading loading-spinner` set on the
   same span — already in output.css (no new request; the exact spinner the
   admin panel uses), tinted by `currentColor` so it contrasts each button. This
   class carries only the REVEAL/marker role: DaisyUI's `.loading` is always
   shown, so we hide it until the control is busy — `.htmx-request` (htmx adds it
   to the requesting contact form) or `aria-busy` (widget.js sets it on native
   forms + `[data-busy]` full-nav CTAs). Top-level, not scoped under
   #widget-root, so it reaches the standalone shells too. A busy control carrying
   NO ring (icon-only nav) falls back to a dim. --------------------------------- */
.w-btn-spinner {
  display: none;
}
.htmx-request .w-btn-spinner,
[aria-busy="true"] .w-btn-spinner {
  display: inline-block;
}
[aria-busy="true"] {
  pointer-events: none;
}
[aria-busy="true"]:not(:has(.w-btn-spinner)) {
  opacity: 0.55;
}

/* ---------------------------------------------------------------------------
   Step-container auto-height transition (desktop only).
   `globalViewTransitions` (base.html htmx-config) wraps every panel/contact
   swap in document.startViewTransition(). Naming the #widget card lifts it
   into its own ::view-transition-group, so the browser animates the card box
   from its old height to its new (auto) height while the step content
   cross-fades — the "auto height" resize a plain CSS transition can't do (the
   swapped #panel / #contact-body are recreated by outerHTML, and #widget's
   height stays computed:auto). #widget is content-height only at md+ (base.html
   md:h-auto); on phones it's a fixed h-dvh card whose inner area scrolls, so the
   name — and thus the animation — is scoped to md+ and left off mobile entirely.
   #widget captured on its own also drops it from the root snapshot, so the
   unchanged backdrop produces no full-page fade.
   --------------------------------------------------------------------------- */
@media (min-width: 768px) {
  #widget-root #widget { view-transition-name: etw-widget-card; }

  /* Selection → contact is a native full-page navigation inside the iframe,
     where cross-document view transitions never run (@view-transition only
     fires for the top-level traversable). Animate the destination card on load
     instead — iframe-safe, and closer to the legacy step `slide`. Panel swaps
     keep morphing via same-document startViewTransition (globalViewTransitions),
     which is unaffected by dropping the cross-document opt-in. */
  @keyframes etw-step-enter {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  #widget-root #widget.step-enter {
    animation: etw-step-enter 260ms cubic-bezier(0.33, 1, 0.68, 1) both;
  }
}

/* Only the CONTAINER height animates. The old step is dropped and the new step
   is shown at once (no content cross-fade / dissolve), while the group box tweens
   between the two step heights — so you see just the card smoothly resize.
   easeOutCubic — matched to the Zenchef widget's morph curve (which runs 400ms);
   at 260ms it keeps that smooth, soft-landing decelerate but a touch quicker. */
::view-transition-group(etw-widget-card) {
  animation-duration: 260ms;
  animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
}
::view-transition-old(etw-widget-card) { animation: none; opacity: 0; }
::view-transition-new(etw-widget-card) { animation: none; opacity: 1; }

/* Across a full-page navigation, only the card morphs — keep the page backdrop
   from cross-fading (no full-page dissolve on hops where the card isn't shared,
   e.g. into a standalone confirmation page). */
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root) { animation: none; }

/* Phones: the swap still triggers a view transition (the trigger isn't
   viewport-aware), but nothing is named below md, so only the root group
   exists — disable it so mobile stays visually instant, exactly as today. */
@media (max-width: 767.98px) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* Respect reduced-motion on every viewport: swap instantly, no morph/fade. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
  #widget-root #widget.step-enter { animation: none; }
}

/* Cache-bust check 2026-07-20: dist hash-flip demo (#47). */
