/* Find A Minyan
   Mobile first throughout. The site is used by people standing in a strange town with a phone in
   one hand, so the narrow layout is the design and the wide one is the variation. */

/* Palette and type
   Bootstrap 5.3 is themed through custom properties rather than recompiled from Sass, so the site's
   colours are set here and everything built on Bootstrap picks them up. Taken from the approved
   design (docs/design/Design.zip): a teal brand colour, a gold accent for the site's own calls to
   action, and a warmer coral for the member's own actions (adding a trip). */
:root,
[data-bs-theme="light"] {
  --fam-blue: #005c62;
  --fam-blue-dark: #004247;
  --fam-blue-light: #d2eef0;
  --fam-gold: #e29e47;
  --fam-gold-ink: #004247;
  --fam-coral: #e96e50;
  /* The same coral, dark enough to carry white text (P11.08). #e96e50 with #fff on it is 3.1:1, well
     short of WCAG 1.4.3's 4.5:1 — and the coral CTA is the button the site most wants pressed, so it
     could not be the one nobody can read. The lighter coral above is still the brand accent and is used
     for every border, outline and edge; only a filled surface with text on it uses this. */
  --fam-coral-deep: #c9491f;
  --fam-coral-deep-hover: #ac3d19;
  --fam-green-tint: #ccf4d3;
  --fam-green-ink: #005a1c;
  --fam-purple-tint: #ece2ff;
  --fam-purple-ink: #6f4fa1;
  --fam-amber-tint: #fee3c5;
  /* Was #a16100, which is 4.0:1 on --fam-amber-tint. This is 4.9:1 (P11.08). */
  --fam-amber-ink: #8f5600;
  --fam-ink: #1e2735;
  --fam-muted: #626975;
  /* Text on a --fam-line chip. --fam-muted is only 4.2:1 against that tint; this is 5.6:1, and still
     reads as the quiet, done-with state a declined RSVP or a cancelled proposal wants (P11.08). */
  --fam-chip-ink: #4f545c;
  --fam-line: #e4ddd3;
  --fam-page: #fdf7f0;

  --bs-primary: var(--fam-blue);
  --bs-primary-rgb: 0, 92, 98;
  --bs-body-color: var(--fam-ink);
  --bs-body-color-rgb: 30, 39, 53;
  --bs-body-bg: #ffffff;
  --bs-secondary-color: var(--fam-muted);
  /* Two variables, not one, and they are not interchangeable: .form-text and .text-body-secondary read
     --bs-secondary-color, while the .text-secondary utility reads --bs-secondary-rgb. Setting only the
     first left every .text-secondary on Bootstrap's own grey, which is 4.48:1 against the site's
     off-white page — a rounding error short of WCAG 1.4.3's 4.5:1 (P11.08). */
  --bs-secondary-color-rgb: 98, 105, 117;
  --bs-secondary-rgb: 98, 105, 117;
  --bs-border-color: var(--fam-line);
  --bs-link-color: var(--fam-blue);
  --bs-link-color-rgb: 0, 92, 98;
  --bs-link-hover-color: var(--fam-blue-dark);
  --bs-link-hover-color-rgb: 0, 66, 71;

  /* Hebrew appears throughout, so the stack has to reach a Hebrew face before it gives up */
  --bs-body-font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans Hebrew", "Segoe UI Historic", "Arial Hebrew", "Times New Roman", sans-serif;
  --fam-heading-font: "Plus Jakarta Sans", var(--bs-body-font-family);
  --bs-body-font-size: 1rem;
  --bs-body-line-height: 1.55;

  /* How far the fixed bar along the bottom reaches, including the phone's home indicator */
  --fam-bottom-nav: calc(3.75rem + env(safe-area-inset-bottom, 0px));
}

.btn-primary {
  --bs-btn-bg: var(--fam-blue);
  --bs-btn-border-color: var(--fam-blue);
  --bs-btn-hover-bg: var(--fam-blue-dark);
  --bs-btn-hover-border-color: var(--fam-blue-dark);
  --bs-btn-active-bg: var(--fam-blue-dark);
  --bs-btn-active-border-color: var(--fam-blue-dark);
  --bs-btn-disabled-bg: var(--fam-blue);
  --bs-btn-disabled-border-color: var(--fam-blue);
}

.btn-outline-primary {
  --bs-btn-color: var(--fam-blue);
  --bs-btn-border-color: var(--fam-blue);
  --bs-btn-hover-bg: var(--fam-blue);
  --bs-btn-hover-border-color: var(--fam-blue);
  --bs-btn-active-bg: var(--fam-blue);
  --bs-btn-active-border-color: var(--fam-blue);
}

/* Links keep Bootstrap's underline (P11.08, WCAG 1.4.1). There used to be a blanket
   "a { text-decoration: none }" here, and it was the site's single biggest accessibility failure: the
   brand teal against the body ink is only 2:1, so with the underline gone a link inside a paragraph was
   distinguished from the sentence around it by colour alone — invisible to anyone who cannot tell the
   two apart, on every content page at once.

   Nothing needs adding to keep the navigation and the button-shaped links clean: .btn and .nav-link
   clear their own underline in Bootstrap, and every one of the site's own control-shaped link classes
   (.site-brand, .site-header-link, .site-bottom-link, .site-drawer-link, .site-skip-link,
   .my-trips-btn, .messages-row) already sets text-decoration: none for itself. */

/* The account management tabs (ManageNavMenu). Bootstrap's nav-pills active background is a
   hardcoded blue in the vendor CSS rather than a variable tied to --bs-primary, so left alone it
   clashes with the site's teal. The inactive tab also needs a border of its own — without one it
   is just text next to the coloured active pill, not obviously a second, clickable tab. */
.nav-pills .nav-link {
  border: 1px solid var(--fam-line);
  color: var(--fam-blue);
}

.nav-pills .nav-link:hover {
  background-color: var(--fam-blue-light);
}

.nav-pills {
  --bs-nav-pills-link-active-bg: var(--fam-blue);
}

.nav-pills .nav-link.active {
  border-color: var(--fam-blue);
}

/* A row of tabs reads as one toolbar rather than a scattering of separate pills: the segments meet,
   share a single line between them, and only the two outer corners are rounded. Every such row on the
   site carries .site-tab-bar — the admin tabs and the account tabs — so they cannot drift apart.
   CLAUDE.md records this as a convention: any row of buttons added or changed later keeps it.

   Which corners are the outer ones depends on which way the row is running: top and bottom while it
   is stacked on a phone (flex-column), left and right once it lays out as a row (flex-lg-row). Every
   rule below sets the whole border-radius shorthand rather than the individual corners, so each one
   clears what the previous set — a longhand here would lose to the more specific :first-child rule
   above it and leave a stray rounded corner mid-row. */
.site-tab-bar {
  gap: 0;
}

.site-tab-bar .nav-link {
  border-radius: 0;
}

.site-tab-bar .nav-item:first-child .nav-link {
  border-radius: var(--bs-nav-pills-border-radius) var(--bs-nav-pills-border-radius) 0 0;
}

.site-tab-bar .nav-item:last-child .nav-link {
  border-radius: 0 0 var(--bs-nav-pills-border-radius) var(--bs-nav-pills-border-radius);
}

/* Each tab carries its own 1px border (see .nav-pills .nav-link above), so abutting two of them
   would draw a 2px line between the pair. Pulling each one back over its neighbour leaves the single
   line a toolbar should have. */
.site-tab-bar .nav-item + .nav-item .nav-link {
  margin-top: -1px;
}

@media (min-width: 992px) {
  .site-tab-bar .nav-item:first-child .nav-link {
    border-radius: var(--bs-nav-pills-border-radius) 0 0 var(--bs-nav-pills-border-radius);
  }

  .site-tab-bar .nav-item:last-child .nav-link {
    border-radius: 0 var(--bs-nav-pills-border-radius) var(--bs-nav-pills-border-radius) 0;
  }

  .site-tab-bar .nav-item + .nav-item .nav-link {
    margin-top: 0;
    margin-inline-start: -1px;
  }
}

/* A row of one is all outer corners. Last, and more specific than either rule above, so it wins in
   both directions. */
.site-tab-bar .nav-item:first-child:last-child .nav-link {
  border-radius: var(--bs-nav-pills-border-radius);
}

/* An active tab's border is the brand teal, which has to sit over its neighbours' grey rather than
   under it — without this the negative margin above hides one side of it. */
.site-tab-bar .nav-link.active {
  position: relative;
  z-index: 1;
}

/* The one warm colour on the site, reserved for the member's own "add a trip" — everything else
   the site itself asks for stays in the brand teal or the gold accent. */
.btn-coral {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--fam-coral-deep);
  --bs-btn-border-color: var(--fam-coral-deep);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--fam-coral-deep-hover);
  --bs-btn-hover-border-color: var(--fam-coral-deep-hover);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--fam-coral-deep-hover);
  --bs-btn-active-border-color: var(--fam-coral-deep-hover);
  /* The glow stays the lighter brand coral — it is a shadow, not something anybody reads */
  box-shadow: 0 8px 20px -8px rgba(233, 110, 80, .6);
}

/* Bootstrap's own secondary grey is 4.48:1 against the site's off-white page — a rounding error short
   of 4.5:1, and the Reset, Cancel and "Back to messages" buttons are all built on it (P11.08). */
.btn-outline-secondary {
  --bs-btn-color: var(--fam-muted);
  --bs-btn-border-color: var(--fam-muted);
  --bs-btn-hover-bg: var(--fam-muted);
  --bs-btn-hover-border-color: var(--fam-muted);
  --bs-btn-active-bg: var(--fam-muted);
  --bs-btn-active-border-color: var(--fam-muted);
}

body {
  background-color: var(--fam-page);
  font-family: var(--bs-body-font-family);
}

/* A visible focus ring everywhere, because a fair number of members navigate by keyboard */
:focus-visible {
  outline: 3px solid var(--fam-blue);
  outline-offset: 2px;
}

h1,
h2,
h3 {
  font-family: var(--fam-heading-font);
}

h1 {
  font-size: 1.6rem;
  font-weight: 800;
}

  /* FocusOnNavigate moves focus to the heading after every navigation so a screen reader announces
     the new page. That is for announcing, not for showing, so it is not ringed. */
  h1:focus,
  h1:focus-visible {
    outline: none;
  }

h2 {
  font-size: 1.25rem;
  font-weight: 700;
}

h3 {
  font-size: 1.1rem;
  font-weight: 700;
}

@media (min-width: 992px) {
  h1 {
    font-size: 2rem;
  }

  h2 {
    font-size: 1.5rem;
  }
}

/* Hebrew content
   User-entered text can be in either direction, and a paragraph mixing the two has to be laid out
   by what it actually says rather than by what the page assumes. */
[dir="auto"],
.text-auto {
  unicode-bidi: plaintext;
}

.hebrew {
  direction: rtl;
  text-align: start;
  unicode-bidi: isolate;
}

/* Shell */

/* Skip to content (WCAG 2.4.1, P11.08). Off screen until it is focused, which is the first tab stop
   on every page — see Shell.razor for why it is rendered even where the navigation is not. It has to
   clear the drawer (1045) as well as the header (1020), since the drawer can be open when a page is
   tabbed into. */
.site-skip-link {
  position: fixed;
  inset-inline-start: .5rem;
  top: -4rem;
  z-index: 1100;
  padding: .6rem 1rem;
  border-radius: 0 0 .6rem .6rem;
  background: var(--fam-gold);
  color: var(--fam-gold-ink);
  font-weight: 700;
  text-decoration: none;
  transition: top .15s ease-in-out;
}

  .site-skip-link:focus,
  .site-skip-link:focus-visible {
    top: 0;
    color: var(--fam-gold-ink);
  }

@media (prefers-reduced-motion: reduce) {
  .site-skip-link {
    transition: none;
  }
}

.site {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  /* Nothing on the site scrolls the page sideways. Anything too wide — the timeline, a table —
     scrolls inside its own container instead. */
  overflow-x: clip;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 1020;
  background: linear-gradient(120deg, var(--fam-blue), var(--fam-blue-dark));
  color: #fff;
}

.site-header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 3.25rem;
  padding-block: .65rem;
  padding-inline: 1rem;
  margin-inline: auto;
  width: 100%;
  max-width: 75rem;
}

.site-brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: #fff;
  font-family: var(--fam-heading-font);
  font-weight: 800;
  font-size: 1.05rem;
  text-decoration: none;
  margin-inline-end: auto;
}

  .site-brand:hover {
    color: #fff;
  }

.site-brand-badge {
  display: grid;
  place-content: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: .7rem;
  background: var(--fam-gold);
  color: var(--fam-gold-ink);
}

.site-header-nav {
  gap: .25rem;
}

.site-header-link {
  color: rgba(255, 255, 255, .85);
  text-decoration: none;
  padding: .5rem .9rem;
  border-radius: .6rem;
  font-size: .9rem;
  white-space: nowrap;
}

  .site-header-link:hover {
    color: #fff;
    background: rgba(255, 255, 255, .12);
  }

  .site-header-link.active {
    color: #fff;
    background: rgba(255, 255, 255, .22);
    font-weight: 600;
  }

  /* "Log in" reads as the site's own call to action, not just another link */
  .site-header-link.site-header-link-cta,
  .site-header-link.site-header-link-cta.active {
    color: var(--fam-gold-ink);
    background: var(--fam-gold);
    font-weight: 700;
  }

    .site-header-link.site-header-link-cta:hover {
      color: var(--fam-gold-ink);
      background: #d78f31;
    }

/* Unread conversations (P8.01) — a small count next to the "Messages" link wherever it appears
   (header, drawer, bottom bar). .site-nav-badge-icon repositions it to float over the icon instead,
   for the bottom bar's icon-over-label layout. */
.site-nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 .3rem;
  margin-inline-start: .35rem;
  border-radius: 1rem;
  background: var(--fam-coral);
  color: #fff;
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
}

.site-bottom-icon-wrapper {
  position: relative;
  display: inline-flex;
}

.site-nav-badge-icon {
  position: absolute;
  top: -.35rem;
  inset-inline-end: -.6rem;
  margin-inline-start: 0;
}

.site-header-more {
  display: grid;
  place-content: center;
  flex: none;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: .6rem;
  background: rgba(255, 255, 255, .18);
  color: #fff;
  font-size: 1.2rem;
}

  .site-header-more:hover {
    background: rgba(255, 255, 255, .3);
  }

.site-main {
  flex: 1 1 auto;
  width: 100%;
  max-width: 75rem;
  margin-inline: auto;
  padding: 1.25rem 1rem 1.5rem;
}

  /* The skip link moves focus here, which needs tabindex="-1" to be possible at all. That is for
     moving focus, not for showing it — the same reasoning as h1 above — so the region itself is not
     ringed; whatever is tabbed to next is. */
  .site-main:focus,
  .site-main:focus-visible {
    outline: none;
  }

/* Room for the fixed bar, so the last thing on a page is never trapped underneath it */
@media (max-width: 991.98px) {
  .site-main {
    padding-bottom: calc(var(--fam-bottom-nav) + 1rem);
  }

  /* ...except where there is no fixed bar. The returning-member page (P11.03) hides the navigation,
     and the room it would have needed would just be a gap above the footer. */
  .site-no-nav .site-main {
    padding-bottom: 1.5rem;
  }
}

.site-footer {
  border-top: 1px solid var(--fam-line);
  background: #fff;
  padding: 1.25rem 1rem;
}

@media (max-width: 991.98px) {
  .site-footer {
    padding-bottom: calc(var(--fam-bottom-nav) + 1rem);
  }
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.25rem;
  max-width: 75rem;
  margin-inline: auto;
}

.site-footer-note {
  max-width: 75rem;
  margin-inline: auto;
  margin-top: .75rem;
  color: var(--fam-muted);
  font-size: .875rem;
}

/* The bar along the bottom of a phone */
.site-bottom-nav {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 1030;
  display: flex;
  background: #fff;
  border-top: 1px solid var(--fam-line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.site-bottom-link {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1rem;
  min-height: 3.75rem;
  padding: .35rem .25rem;
  border: 0;
  background: transparent;
  color: var(--fam-muted);
  font-size: .7rem;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
}

  .site-bottom-link i {
    font-size: 1.25rem;
  }

  .site-bottom-link.active {
    color: var(--fam-blue);
    font-weight: 600;
  }

  .site-bottom-link span {
    /* Four labels across a 375px screen, so a long one shortens rather than wrapping the bar */
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

/* The drawer */
.site-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1040;
  background: rgba(0, 0, 0, .4);
}

.site-drawer {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  z-index: 1045;
  width: min(20rem, 85vw);
  background: #fff;
  border-inline-start: 1px solid var(--fam-line);
  transform: translateX(100%);
  transition: transform .2s ease-in-out;
  visibility: hidden;
  overflow-y: auto;
}

[dir="rtl"] .site-drawer {
  transform: translateX(-100%);
}

.site-drawer.open {
  transform: none;
  visibility: visible;
}

@media (prefers-reduced-motion: reduce) {
  .site-drawer {
    transition: none;
  }
}

.site-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem;
  border-bottom: 1px solid var(--fam-line);
}

.site-drawer-links {
  display: flex;
  flex-direction: column;
  padding: .5rem 0;
}

.site-drawer-link {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 44px;
  padding: .6rem 1rem;
  color: var(--fam-ink);
  text-decoration: none;
}

  .site-drawer-link:hover {
    background: var(--fam-blue-light);
  }

  .site-drawer-link.active {
    color: var(--fam-blue);
    font-weight: 600;
    background: var(--fam-blue-light);
  }

  .site-drawer-link i {
    font-size: 1.1rem;
    color: var(--fam-muted);
    width: 1.25rem;
    text-align: center;
  }

  /* "Log in" reads as the site's own call to action here too */
  .site-drawer-link.site-drawer-link-cta {
    margin-top: .35rem;
    color: var(--fam-gold-ink);
    font-weight: 700;
    background: var(--fam-amber-tint);
  }

    .site-drawer-link.site-drawer-link-cta i {
      color: var(--fam-gold-ink);
    }

/* Page heading */
.page-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: 1.25rem;
}

.page-heading h1 {
  margin-bottom: .25rem;
}

.page-heading-lead {
  margin-bottom: 0;
  color: var(--fam-muted);
}

.page-heading-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

/* Anything that cannot be made narrow — a timeline, a wide table — scrolls inside itself */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* The framework's unhandled-error bar. Blazor reveals it by setting display:block inline, so it
   cannot be laid out as a flex row — the dismiss is positioned instead. */
#blazor-error-ui {
  display: none;
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 1050;
  padding-block: .8rem;
  /* Room for the dismiss, which is positioned into the end of the bar rather than laid out */
  padding-inline: 1rem 2.5rem;
  background: #fff3cd;
  border-top: 1px solid #ffe69c;
  color: var(--fam-ink);
  box-shadow: 0 -4px 12px rgba(0, 0, 0, .1);
}

  #blazor-error-ui .reload {
    margin-inline-start: .5rem;
  }

  #blazor-error-ui .dismiss {
    position: absolute;
    inset-inline-end: 1rem;
    top: .7rem;
    cursor: pointer;
    font-size: 1.35rem;
    line-height: 1;
  }

/* Notifications
   NotificationArea comes from Pixata.Blazor and brings its own scoped styles, but it expects the
   site to supply .round-it, which is the rounding the rest of the site uses. */
.round-it {
  border-radius: .5rem;
}

/* Confirm dialogs
   Pixata.Blazor's Confirm component toggles #confirmOverlay between display:none and display:block
   itself, but supplies no backdrop or card chrome beyond a plain white box, so the two below are
   the site's own.

   Positioning is the component's, not ours, and only works because every <Confirm> on the site
   passes PopUpDisplayOption="PopUpDisplayOptions.Window". That is what makes it write
   position: fixed inline on the overlay. The default, Container, writes position: absolute
   instead, which anchors the dialog to the zero-height wrapper the component renders at whatever
   point in the page the <Confirm> tag happens to sit — so the dialog lands at the foot of the
   document rather than in the viewport. On a short page that is close enough to the middle of the
   screen to pass; on a long one it is off-screen entirely, and the button that opened it looks
   dead (#104, deleting a previous trip on My trips).

   The [id] on each selector is load-bearing, not decoration. The component's own scoped rules are
   #confirmOverlay[b-…] and #confirmOverlay #confirmOverlayContent[b-…]; the extra attribute
   selector matches the specificity those scope attributes add, and without it none of this
   applies at all. */
#confirmOverlay[id] {
  inset: 0;
  background: rgba(30, 39, 53, .55);
}

#confirmOverlay[id] #confirmOverlayContent[id] {
  width: min(26rem, calc(100vw - 2rem));
  background: #fff;
  border-radius: 1rem;
  padding: 1.5rem;
  box-shadow: 0 20px 45px -15px rgba(30, 39, 53, .35);
}

/* Forms
   The site's own Bootstrap 5 control set. Everything here is either about a phone in one hand or
   about the page working the same way in Hebrew, so nothing is positioned left or right. */

/* 44px is the smallest target most people can hit reliably with a thumb */
.form-field .form-control,
.form-field .form-select,
.form-submit .btn {
  min-height: 44px;
}

.form-field.form-check {
  min-height: 44px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  padding-block: .25rem;
}

  .form-field.form-check .form-check-input {
    width: 1.35rem;
    height: 1.35rem;
    margin-top: 0;
  }

  .form-field.form-check .form-check-label {
    padding-inline-start: .5rem;
    /* Extends the tap target to the full row rather than just the box */
    padding-block: .6rem;
  }

  .form-field.form-check .form-text,
  .form-field.form-check .form-field-errors {
    flex-basis: 100%;
  }

/* The picker brings its own width, which is fine on a desktop and too wide on a phone */
.form-field .form-date,
.form-field .form-date .hebrew-date-picker {
  width: 100%;
}

.form-field .form-date.is-invalid .form-control {
  border-color: var(--bs-form-invalid-border-color);
}

.form-field-errors .invalid-feedback {
  /* Bootstrap only reveals these next to an .is-invalid sibling; the messages are rendered in
     their own block so they can be announced, so they are shown explicitly */
  margin-top: .25rem;
}

/* Right to left
   The site's own chrome is English and stays left to right (P11.08). Hebrew arrives inside it — in
   dates, in the dedication, and in whatever a member typed — so what matters is that each Hebrew run
   is isolated and laid out by what it says, not that the page is mirrored. Loading bootstrap.rtl.css
   would mirror the whole shell, which is a different site, so it is deliberately not loaded.

   What that leaves is a rule the site can hold to instead: nothing in the site's own stylesheets uses
   a physical left/right property, so a Hebrew run can never strand the box around it. The logical
   pair is always available — margin-inline-start, inset-inline-end, text-align: start — and
   BootstrapVersionTests.NoStylesheetUsesAPhysicalDirectionalProperty keeps it true.

   The reboot clears a definition list's indent with margin-left, so the browser's own
   margin-inline-start survives and pushes every dd out of the page once a dl is put in a Hebrew
   block. */
dl.row > dd {
  margin-inline-start: 0;
}

/* Shared with the deferred map popup (map.css) — this class name is also built into the popup HTML
   MapPopupHtmlBuilder generates, which runs before map.css is guaranteed to have loaded, so it lives
   in the stylesheet that is always loaded rather than the one map-interop.js injects on demand. */
.fam-marker-popup-arranged {
  background: var(--fam-green-tint);
  color: var(--fam-green-ink);
}

.fam-marker-popup-rov {
  background: var(--fam-amber-tint);
  color: var(--fam-amber-ink);
}

/* A cancelled minyan proposal (P9.01) — used on both the proposal page and the "my minyonim" list,
   so it lives here rather than in either page's own scoped CSS. */
.fam-badge-cancelled {
  background: var(--fam-line);
  color: var(--fam-chip-ink);
}

/* MapLoadingPlaceholder — stands in for the map before Leaflet has ever run, so map.css (loaded on
   demand alongside Leaflet itself) is not guaranteed to be there yet either. */
.fam-map-placeholder {
  width: 100%;
  border-radius: .75rem;
  color: var(--fam-muted);
  background: linear-gradient(90deg, var(--fam-line) 25%, #fff 50%, var(--fam-line) 75%);
  background-size: 200% 100%;
  animation: fam-map-placeholder-shimmer 1.4s ease-in-out infinite;
}

@keyframes fam-map-placeholder-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .fam-map-placeholder {
    animation: none;
    background: var(--fam-line);
  }
}

/* Browse's own .browse-map-wrapper (Browse.razor.css) turns this from a block placeholder into an
   overlay covering MapView exactly, while a search is in flight — plain CSS rather than ::deep,
   since Browse.razor.css is scoped to Browse's own markup and the placeholder is a separate
   component's.

   z-index has to clear Leaflet's own panes and controls, not just sit "above" MapView's outer div —
   Leaflet's tile/marker/popup panes run 200-700 and its zoom control sits at 1000 (see leaflet.css),
   all painted *inside* that div once Leaflet has initialised, so anything lower was invisible behind
   a live map even though it was genuinely there in the DOM. */
.browse-map-wrapper .fam-map-placeholder {
  position: absolute;
  inset: 0;
  height: auto !important;
  z-index: 1200;
}

/* The two controls in browse's "search near a place" group are the last thing inside it, so
   FormField's own bottom margin lands on top of the fieldset's padding and shows as a band of nothing
   under their hints — which also pushed the map itself far enough down the page to matter. Here
   rather than in Browse.razor.css because .form-field is FormField's markup, not Browse's, the same
   reason as the rules above and below. */
.browse-near .form-field {
  margin-bottom: 0;
}

/* Since #112 that same map sits inside .browse-map-panel, with the "Jump to" toolbar on its top edge
   and the panel doing the rounding and the clipping for the pair. MapView's own .fam-map radius would
   otherwise show as a pale notch in each of the panel's bottom corners. Here rather than in
   Browse.razor.css for the same reason as the rule above: .fam-map is MapView's markup, not Browse's. */
.browse-map-panel .fam-map {
  border-radius: 0;
}

/* Same reasoning as .browse-map-wrapper above, for the who's-near-me panel's own map (P5.06). */
.who-near-me-map-wrapper .fam-map-placeholder {
  position: absolute;
  inset: 0;
  height: auto !important;
  z-index: 1200;
}

/* Shared across the admin listing/venue tables (P10.02 follow-up feedback) rather than repeated in
   each page's own scoped CSS, since AdminListings, AdminShuls and AdminHolidayCamps all use
   them identically.

   The height comes from the viewport, not from the rows. Sizing the box to its own content was the
   bug: before the data arrived there was nothing to size it to, so it rendered one line tall with
   the footer tucked underneath it, and when the rows landed it jumped to a different height. A box
   that is the same height throughout has neither problem, and Virtualize is happier for it — it
   measures this element to decide how much to render, and a height that does not depend on what it
   renders is the one thing that cannot go circular.

   Each page sets its own --admin-table-offset in its scoped CSS: everything above the box on that
   page, plus .site-main's bottom padding and the footer's own height, so the bottom of the box lands
   just short of the footer. max() covers the screens too short or too narrow for that arithmetic to
   leave anything — on a phone the filters alone fill the viewport — where the page scrolls as it
   always did and the table simply keeps a usable height.

   The footer needs nothing special any more, so the .site-main:has(.admin-page) opt-out that used to
   sit here has gone: the shell stretches the main region on these pages exactly as it does on every
   other, and the table now reaches far enough down that there is nothing left to stretch. */
.admin-listings-scroll {
  height: max(18rem, calc(100dvh - var(--admin-table-offset, 595px)));
  overflow: auto;
}

/* Virtualize sizes its spacers from ItemSize, so the rows have to actually be that tall — a row that
   wraps onto a second line would make every estimate below it wrong, and the error compounds down
   the list. Cells stay on one line and ellipsise instead; the text itself is untouched in the DOM,
   so a screen reader still reads the whole of it. */
.admin-listings-table {
  /* Must stay in step with AdminTableConstants.RowHeightPx, which is what ItemSize is set from. */
  --admin-row-height: 48px;
}

.admin-listings-table tbody tr {
  height: var(--admin-row-height);
}

.admin-listings-table tbody td {
  max-width: 18rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.admin-listings-dates {
  white-space: nowrap;
  min-width: 11rem;
}

/* Wide enough that a UK postcode — the .text-nowrap span alongside the address text — never wraps
   onto its own line. */
.admin-listings-address {
  min-width: 16rem;
}

/* A background distinct from --fam-page (the page's own off-white) — that was the bug in the first
   cut: every row already sits on --fam-page by default, since a plain (non-striped) Bootstrap table
   is transparent, so "inactive" rows looked identical to active ones. Applied to the cells as well as
   the row itself, because Bootstrap's own --bs-table-bg variable on <td> would otherwise paint over a
   background set only on <tr>. */
.admin-row-inactive,
.admin-row-inactive > td {
  color: #6c757d;
  background-color: #e9ecef;
}

/* The reported content on the moderation queue (P10.05) — a whole conversation is several lines of
   somebody else's words, so it keeps its line breaks and wraps rather than running off the card, and
   is boxed so it reads as quoted material rather than as the site's own text. */
.admin-report-target {
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 18rem;
  overflow: auto;
  padding: 0.75rem;
  margin-bottom: 1rem;
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
}

/* A problem report's diagnostics on the contact triage screen (P11.04). A user agent string is one
   long unbroken token, so without this one card would push the whole admin page sideways. */
.admin-contact-diagnostics {
  overflow-wrap: anywhere;
}

/* A suggested venue's address on the same screen (#110). It is typed as a postal address, over as
   many lines as it took, and reads back to whoever is chasing it far better kept that way than run
   onto one line. */
.admin-contact-address {
  white-space: pre-line;
}

/* The template editor sits above the list it was opened from, so it needs a visible edge between the
   two — without one the Save/Preview row runs straight into the table's own header. */
.admin-template-editor {
  padding-bottom: 1.5rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid #dee2e6;
}

/* An email template preview is the branded shell in full, so it needs room and its own scrollbar.
   The frame is sandboxed (see AdminMessageTemplates.razor), which is why it can be given the width
   of the page without the wording inside it reaching the page around it. */
.admin-template-preview {
  width: 100%;
  height: 28rem;
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
  background-color: #fff;
}

/* An SMS preview is plain text and is shown as such — no shell, because none is ever added on the
   way to a phone. */
.admin-template-preview-text {
  white-space: pre-wrap;
  word-break: break-word;
  padding: 0.75rem;
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
}

/* Leaflet's own attribution box, unwanted chrome on a site that already credits its data sources
   in the footer. Both classes together, not a comma — .leaflet-control alone is shared with the
   zoom buttons, which stay visible. */
.leaflet-control-attribution.leaflet-control {
  display: none;
}

/* The worked example beneath the date-display choice, on the profile page and "What's changed".
   Tinted rather than bordered, so it reads as a result of the choices above it and not as another
   control to fill in. */
.date-display-sample {
  background: var(--fam-page);
  border-radius: 0.375rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 1rem;
}
