/* Gripswich — trial-hours announcement banner -------------------------------
   Its own self-contained component sheet, on the same reasoning as
   visitbar.css: this banner has to render identically on three shells that
   load two different stylesheets — the public site (style.css), and the staff
   console + member portal (both console.css).

   Those two sheets name the SAME palette differently: --clr-bg-dark vs --bg,
   --clr-orange vs --orange, --clr-teal-4 vs --teal-4. A rule written against
   either set resolves to nothing on the other surface, and an undefined
   custom property doesn't fall back to the browser default — it drops the
   declaration. The banner would render as a transparent, unpadded run of
   text rather than an announcement, and no test that only checks for a 200
   would catch it.

   So the component carries its own tokens, scoped to the root class, at the
   public site's values. Nothing outside .trial-banner is touched and the
   sheet is safe to drop into any shell.

   To retire the banner after the trial: delete the .trial-banner rules below,
   templates/_trial_hours_banner.html, the {% include %} in each shell, and
   trial_banner + TRIAL_KEY (gym/context_processors.py, gym/announcements.py).
   NOT the file, and not the three <link> tags — the desk's public notice and
   the member's hide button are permanent and live in here too, for the same
   cross-shell palette reason. */

.trial-banner {
  /* The public site's palette, restated locally — see the file header. */
  --tb-ground:   #030712;  /* style.css --clr-bg-dark  */
  --tb-border:   #374151;  /* style.css --clr-border   */
  --tb-ink:      #111827;  /* style.css --clr-bg       */
  --tb-orange:   #f97316;  /* style.css --clr-orange   */
  --tb-orange-4: #fb923c;  /* style.css --clr-orange-4 */
  --tb-teal-4:   #2dd4bf;  /* style.css --clr-teal-4   */
  --tb-text:     #f3f4f6;  /* style.css --clr-text     */
  --tb-muted:    #9ca3af;  /* style.css --clr-muted    */
  /* Same clamp as --gutter in both style.css and console.css, so the banner's
     side inset lines up with the content edges on every surface. */
  --tb-gutter: clamp(2rem, 8vw, 10rem);

  background: var(--tb-ground);
  border-bottom: 1px solid var(--tb-border);
}

/* Sits ABOVE the sticky header on all three shells, never inside it, so it
   scrolls away instead of permanently eating vertical space — the console
   and portal headers are already the tallest thing on a phone. */
.trial-banner__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  margin: 0 auto;
  padding: 0.65rem var(--tb-gutter);
  text-align: center;
}

.trial-banner__pill {
  flex-shrink: 0;
  background: var(--tb-orange);
  color: var(--tb-ink);   /* dark ink on orange — see .btn--orange, 6.3:1 */
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
}

.trial-banner__text { display: flex; flex-direction: column; gap: 0.15rem; }

.trial-banner__line { font-size: 0.9375rem; color: var(--tb-text); }
.trial-banner__line b { color: var(--tb-teal-4); }

.trial-banner__sub { font-size: 0.8125rem; color: var(--tb-muted); }

/* Class selector, not a bare `a`, so it beats console.css's global
   `a { color: var(--teal-4); text-decoration: none; }` on the two app shells. */
.trial-banner__cta {
  flex-shrink: 0;
  color: var(--tb-teal-4);
  font-weight: 700;
  font-size: 0.9375rem;
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
  /* A finger-sized target on a link whose own box is one line of text — 24px on
     the public shell and 18px in the portal, where console.css gives anchors a
     tighter line-height. The padding is the hit area; the equal negative margin
     hands the space straight back to the flex row, so the banner is not a pixel
     taller than it was. That matters more here than the usual min-height would:
     this bar is the first thing on every page on all three shells, it already
     wraps to ~180px on a 390px phone, and growing it is exactly what the device
     audit told us not to spend the top of a phone screen on. */
  display: inline-flex;
  align-items: center;
  padding-block: 0.8rem;
  margin-block: -0.8rem;
}
.trial-banner__cta:hover { color: var(--tb-orange-4); }

/* The desk-editable public notice (templates/_public_notice.html).
 *
 * Lives in this sheet rather than style.css because it is included by all
 * three shells and they name their palette tokens differently — the same
 * reason the trial banner is here. Self-contained: literal colours, no var().
 *
 * Amber rather than the trial banner's palette, so that on the rare page
 * carrying both, a standing announcement and a one-off gym notice are not the
 * same object twice. */
.site-notice {
  width: 100%;
  background: #7a4b00;
  color: #fff6e6;
  font-size: 0.92rem;
  line-height: 1.35;
}
.site-notice__inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.55rem 1rem;
  display: flex;
  gap: 0.65rem;
  align-items: baseline;
  flex-wrap: wrap;
}
.site-notice__pill {
  flex: none;
  background: #fff6e6;
  color: #7a4b00;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
}
.site-notice__text {
  font-weight: 600;
  /* Shares its row with the × rather than pushing it onto one of its own: on a
     phone the notice already wraps to two lines, and a third row holding
     nothing but a close button is exactly the header height a device audit
     told us not to spend. flex-basis lets it wrap under the NOTICE pill when
     it must; min-width:0 is what actually lets a long word wrap inside a flex
     item instead of forcing the row wider (see the console's flex traps). */
  flex: 1 1 10rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The same notice, inside the "Time to climb?" drawer (templates/_visit_bar.html).
 *
 * A modifier rather than a second set of rules, because the drawer's copy and
 * the bar at the top of the page are the same announcement and a reader sees
 * both on one screen — two treatments of one sentence reads as two different
 * things having happened. The bar is full-bleed chrome above the header; this
 * one sits inside a panel that already has its own gutters, so it takes a card
 * shape and drops the outer edge-to-edge ground.
 *
 * Sized down a touch from the bar's own type: in the drawer it is a note
 * ABOVE the live gauge, and the gauge's percentage is what the reader opened
 * the panel for. */
/* The automatic busy bar (templates/_busy_notice.html).
 *
 * A colour of its own, not the amber above, because the two bars say different
 * KINDS of thing and only one of them is a human speaking. Amber is reception:
 * "closed Sunday for the comp" — read it, it may change your plans. This slate
 * is the building reporting on itself: "Friday will be busy". A member who has
 * learnt that amber means someone typed something should not have that learning
 * spent on a sentence nobody wrote.
 *
 * Only the two ground colours are restated. Everything else — the inner rail,
 * the pill geometry, the text's flex behaviour, the × — is inherited from the
 * base bar, so the two stay the same object in different clothes and a fix to
 * one lands on both. */
.site-notice--busy {
  background: #1f3a52;
  color: #e3f0fa;
}
.site-notice--busy .site-notice__pill {
  background: #e3f0fa;
  color: #1f3a52;
}
/* The rule between two bookings on one bar. An element rather than a "|"
 * character in the string: a glyph would inherit the text's own wrapping and
 * can end up alone at the start of a line, and it would have to be escaped and
 * carried through the plain-text version that feeds the hide key.
 *
 * Sized in `em` so it tracks the bar's font rather than needing a second
 * breakpoint on a phone, and drawn in currentColor at low opacity so it stays
 * correct if the bar's palette is ever restated. */
.site-notice__divider {
  display: inline-block;
  width: 1px;
  height: 0.95em;
  margin: 0 0.55rem;
  background: currentColor;
  opacity: 0.45;
  /* Sits the rule on the text's optical line rather than its baseline, where a
     1px bar reads as hanging below the words either side of it. */
  vertical-align: -0.12em;
}

.site-notice--inline {
  border-radius: 10px;
  /* The panel is dark and this ground is dark amber, so the block needs an
     edge of its own or it reads as a shadow rather than a notice. */
  border: 1px solid #a9701a;
  margin-bottom: 1.25rem;
}
.site-notice--inline .site-notice__inner {
  max-width: none;
  padding: 0.6rem 0.85rem;
  /* The bar's row is baseline-aligned so the pill sits on the text's first
     line. Here the text routinely runs to two or three lines, and a pill
     baselined against a paragraph that tall drifts away from the top of it. */
  align-items: flex-start;
}
.site-notice--inline .site-notice__pill {
  /* Nudged back onto the first line's optical centre, now that the row aligns
     to the top rather than to a shared baseline. */
  margin-top: 0.1rem;
}

/* The member's × on both bars (templates/_announcement_hide.html).
 *
 * Here rather than in style.css/console.css for the same reason everything
 * else in this sheet is: it renders on the public shell and the portal, which
 * name their palette tokens differently, and an undefined custom property
 * drops the whole declaration rather than falling back. Literal colours only.
 *
 * The console links this sheet too but never renders the button — the desk
 * does not get to hide the gym's notices. */
.ann-hide {
  flex: none;
  margin: 0;
  display: flex;
  align-items: center;
}

.ann-hide__btn {
  appearance: none;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  border-radius: 6px;
  /* A 36px box on a bar that is only ~40px tall: the hit area is the button,
     not the glyph, so this is thumb-reachable without the × dictating how much
     vertical space an announcement costs on a phone. */
  min-width: 2.25rem;
  min-height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Keyboard focus has to be visible on both grounds, and they are opposites —
   currentColor picks up whichever variant below is in play. */
.ann-hide__btn:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 1px;
}

/* Dark ground. Muted at rest on purpose: the × is an escape hatch, not a
   second call to action competing with "See the hours →". */
.trial-banner .ann-hide__btn { color: var(--tb-muted); }
.trial-banner .ann-hide__btn:hover { color: var(--tb-text); }

/* Amber ground (the desk's notice). Pinned to the right edge of the centred
   1100px column, while the trial banner's sits inline after its CTA — that
   one's row is centre-justified, and an auto margin would shove the
   announcement itself off centre. */
.site-notice .ann-hide { margin-left: auto; align-self: center; }
.site-notice .ann-hide__btn { color: #f0cf9d; }
.site-notice .ann-hide__btn:hover { color: #fff6e6; }
