/* ==========================================================================
   deploy-notice — the cross-surface "a deploy is about to happen / is happening / just
   finished" strip (S294, DA294.9; DEPNOTICE-EXEC-2 brief).

   Rendered by {% deploy_notice %} (apps.core.templatetags.deploy_notice) directly below
   {% env_banner %} in every in-scope shell (ops/base*.html, engine/base.html,
   shared/mobile_base.html, and public/base.html gated to the /reserve/ path only — see each
   shell's own comment). A shared partial, so (design_lint Rule 9) it may use only Tier 0
   (brand-kit.css) and its own `--deploy-notice-*` interface properties; every family maps the
   5 state colour triplets (bg/fg/accent) once, at `:root`, the same shape env-banner.css's own
   `--env-banner-*` mapping uses — atoms-desktop.css and atoms-calendar.css (Admin/Settings/
   Calendar — all three already carry literal `--warn`/`--ok`/`--danger`/`--accent` Tier-1
   tokens this maps straight from), atoms-mobile.css (BM/Staff/Guest/Vendor) and
   public-atoms.css (the Reserve flow only). Dark mode follows because each family's own dark
   block redefines the tokens those mappings read.

   NOT position:sticky, deliberately (DEPNOTICE-EXEC-2 judgement call, recorded in that report's
   decision ledger): every family's topbar is already `position:sticky; top:0` ahead of this
   element in the DOM (same as `.env-banner` above it), so this strip sits in normal document
   flow directly below the env banner and scrolls away with the page rather than fight the
   topbar for the top:0 slot — the one change that is guaranteed, by construction, to never
   overlap a sticky header or drawer without touching any other file's z-index or sticky
   offset (the "non-blocking... must not overlap" requirement the brief itself leads with,
   weighed above its own literal word "sticky").

   MARKUP (NOTICEUI-1, S308): .deploy-notice[data-dn-state] > p.deploy-notice__sr (visually hidden
   polite live region, text changes only on a state change) + .deploy-notice__row[aria-hidden]
   (.deploy-notice__signal dot|spinner + p.deploy-notice__text, never wraps as a row so the dot
   is never alone on a line) + .deploy-notice__actions (button.deploy-notice__reload, and for
   Failed a.deploy-notice__link tel:). States: announced (dot), deploying + unreachable (spinner,
   same Updating style), done (Reload), failed (Reload + Call us). Colours stay on the family's
   own tokens (ink text on the soft tint, >= 4.5:1 in every family, light and dark; measured in
   docs/reports/devtools/NOTICEUI-1_Seq54_*.md), the buttons are solid pills with white text.
   ========================================================================== */

/* Standard Alpine idiom (x-cloak has no effect without this rule). Desktop and Calendar already
   carry this globally; Mobile and Public did not load Alpine before this component, so it is
   repeated here, self-contained, rather than widening 4 more files for one global rule no var()
   call needs (no Rule 9 conflict: this references no custom property at all). */
[x-cloak] { display: none !important; }

.deploy-notice {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--deploy-notice-gap, 0.5rem);
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: var(--deploy-notice-pad-y, 0.625rem) var(--deploy-notice-pad-x, 1rem);
  border-bottom: var(--deploy-notice-border-width, 0.125rem) solid var(--deploy-notice-accent);
  background: var(--deploy-notice-bg);
  color: var(--deploy-notice-fg);
  font-family: var(--deploy-notice-font-family, inherit);
  font-size: var(--deploy-notice-font-size, 0.875rem);
  font-weight: 500;
  line-height: var(--deploy-notice-line-height, 1.4);
  text-align: center;
}

/* One state is shown at a time (the Alpine component toggles [data-dn-state]); the colour
   triplet comes from the family's own mapping of these 5 semantic slots. */
.deploy-notice[data-dn-state="announced"] { --deploy-notice-bg: var(--deploy-notice-warn-bg); --deploy-notice-fg: var(--deploy-notice-warn-fg); --deploy-notice-accent: var(--deploy-notice-warn-accent); }
.deploy-notice[data-dn-state="deploying"] { --deploy-notice-bg: var(--deploy-notice-info-bg); --deploy-notice-fg: var(--deploy-notice-info-fg); --deploy-notice-accent: var(--deploy-notice-info-accent); }
.deploy-notice[data-dn-state="unreachable"] { --deploy-notice-bg: var(--deploy-notice-info-bg); --deploy-notice-fg: var(--deploy-notice-info-fg); --deploy-notice-accent: var(--deploy-notice-info-accent); }
.deploy-notice[data-dn-state="done"] { --deploy-notice-bg: var(--deploy-notice-ok-bg); --deploy-notice-fg: var(--deploy-notice-ok-fg); --deploy-notice-accent: var(--deploy-notice-ok-accent); }
.deploy-notice[data-dn-state="failed"] { --deploy-notice-bg: var(--deploy-notice-danger-bg); --deploy-notice-fg: var(--deploy-notice-danger-fg); --deploy-notice-accent: var(--deploy-notice-danger-accent); }

/* Visually hidden, still read: the one live region. Self-contained (no family's .sr-only is assumed). */
.deploy-notice__sr {
  position: absolute;
  width: 0.0625rem;
  height: 0.0625rem;
  margin: -0.0625rem;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The message row never wraps as a row: the signal stays inline with the text, and the text wraps
   inside itself (min-width:0), so a long sentence at 360px can never leave the dot alone. */
.deploy-notice__row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: var(--deploy-notice-row-gap, 0.5rem);
  max-width: 100%;
}
.deploy-notice__signal { display: inline-flex; flex: none; align-items: center; }
.deploy-notice__text {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.deploy-notice__dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
}
.deploy-notice__spinner {
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
  box-sizing: border-box;
  border-radius: 50%;
  border: 0.125rem solid currentColor;
  border-top-color: transparent;
}
/* Motion only when the viewer has not asked for reduced motion; both signals still show, static. */
@media (prefers-reduced-motion: no-preference) {
  .deploy-notice__dot { animation: deploy-notice-pulse 1.4s ease-in-out infinite; }
  .deploy-notice__spinner { animation: deploy-notice-spin 0.8s linear infinite; }
}
@keyframes deploy-notice-spin { to { transform: rotate(360deg); } }
@keyframes deploy-notice-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.4; transform: scale(1.3); } }

.deploy-notice__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--deploy-notice-actions-gap, 1rem);
}

/* Reload: a real <button> (it reloads this page, it does not navigate). Solid pill, white text; Done
   uses the family's success button tokens, Failed its danger ones. */
.deploy-notice__reload {
  flex: none;
  border: none;
  border-radius: var(--deploy-notice-btn-radius, 999px);
  padding: 0.375rem 1rem;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  cursor: pointer;
  background: var(--deploy-notice-btn-bg);
  color: var(--deploy-notice-btn-fg);
}
.deploy-notice__reload:hover { background: var(--deploy-notice-btn-hover-bg); }
.deploy-notice[data-dn-state="failed"] .deploy-notice__reload {
  background: var(--deploy-notice-danger-btn-bg);
  color: var(--deploy-notice-danger-btn-fg);
}
.deploy-notice[data-dn-state="failed"] .deploy-notice__reload:hover { background: var(--deploy-notice-danger-btn-hover-bg); }
.deploy-notice__reload:focus-visible,
.deploy-notice__link:focus-visible {
  outline: 0.125rem solid var(--deploy-notice-fg);
  outline-offset: 0.125rem;
}
.deploy-notice__link {
  color: var(--deploy-notice-fg);
  font-weight: 600;
  text-decoration: underline;
}

@media (prefers-reduced-motion: no-preference) {
  .deploy-notice[data-dn-state] { transition: background-color 0.2s ease, color 0.2s ease; }
}

/* Compact on mobile -- tighter padding and gaps; the text wraps rather than truncate, so the countdown
   is never cut off. */
@media (max-width: 480px) {
  .deploy-notice { padding: var(--deploy-notice-pad-y-mobile, 0.5rem) var(--deploy-notice-pad-x-mobile, 0.875rem); font-size: var(--deploy-notice-font-size-mobile, 0.8125rem); gap: 0.375rem; }
  .deploy-notice__row { gap: 0.375rem; }
  .deploy-notice__actions { gap: 0.875rem; }
  .deploy-notice__reload { padding: 0.3125rem 0.875rem; font-size: 0.75rem; }
}
