/* ==========================================================================
   Mishnah UI — the plugin's own design system
   ==========================================================================

   Everything the plugin renders lives inside <div class="mishnah-ui">. That
   wrapper is doing real work, not decoration:

     - The reset below only applies inside it, so it cannot flatten Bricks
       headings or ACSS spacing anywhere else on the site.
     - Component classes are prefixed `m-`, so a Bricks-authored `.card` or
       `.badge` dropped inside a plugin section does not collide with ours.
     - Tokens are prefixed `--m-`, so nothing here reads or writes an ACSS
       variable. This file has no dependency on the site's framework at all.

   Nothing consumes this file yet. It is enqueued but inert until each surface
   is rewritten onto it, one at a time. Adding it cannot change how any
   existing page looks.
   ========================================================================== */


/* --------------------------------------------------------------------------
   0. Inter
   --------------------------------------------------------------------------

   Self-hosted variable Inter. One file per subset covering the whole 100-900
   weight axis, so every weight the UI uses costs a single download instead of
   one request per cut.

   Paths are relative to this stylesheet, which is what makes them survive the
   plugin being installed under any directory name.

   font-display: swap renders the fallback immediately and swaps Inter in when
   it arrives. The alternative, `block`, leaves invisible text for up to three
   seconds on a slow connection.

   The latin-ext file carries the accented characters the French and other
   Latin-script translations need. unicode-range means a purely English page
   never downloads it.

   Hebrew is NOT covered — Inter has no Hebrew glyphs. Hebrew interface text
   falls through to --m-font-he. See the note on that token below.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/web/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/web/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
                 U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* --------------------------------------------------------------------------
   1. Tokens
   --------------------------------------------------------------------------

   The two dialog hosts are listed alongside .mishnah-ui because they are not
   inside it - SweetAlert and Plainsheet both append to <body>, and the
   .mishnah-ui wrapper lives *within* the popup they create. Without this the
   host's own rules below (background-color, color, box-shadow) reference
   tokens that do not exist at that level, the declarations are invalid at
   computed-value time, and the popup renders with no background at all.
   -------------------------------------------------------------------------- */
.mishnah-ui,
.swal2-popup.mishnah-ui-modal,
.pbs-container.mishnah-ui-sheet {
  /* ======================================================================
     BRAND — the five colors, and the only block you should need to edit.

     Every accent in the plugin derives from these. Nothing below references
     a raw color, so changing a value here re-skins every surface at once.

     They are HSL channel triplets rather than hex so that any of them can be
     used at a custom alpha — hsl(var(--m-brand) / 12%) — which a hex cannot
     do without a second token for every opacity. The hex you gave me is in
     the comment beside each one; to change a color, convert the new hex to
     HSL and replace the three numbers.

     hex           HSL                    was (ACSS)         used for
     ------------  ---------------------  -----------------  ------------------
     #2e77d1       213 64% 50%            --primary-medium   primary actions
     #da6648       12 66% 57%             --action           links, hovers
     #0a1a2e       213 64% 11%            --primary          high-emphasis fill
     #121416       210 10% 8%             --base             body text
     #392e1d       36 33% 17%             --accent           warm emphasis
     ====================================================================== */
  --m-brand: 213 64% 50%;          /* #2e77d1 */
  --m-action: 12 66% 57%;          /* #da6648 */
  --m-navy: 213 64% 11%;           /* #0a1a2e */
  --m-umber: 36 33% 17%;           /* #392e1d */

  /* ---- Derived from the brand -------------------------------------------
     Same hue, shifted lightness. Kept as their own tokens rather than
     computed inline so a hover or a wash can be hand-tuned without touching
     the base color.
     ----------------------------------------------------------------------- */
  --m-brand-hover: 213 64% 42%;    /* #2560a8 — darker step of --m-brand */
  --m-brand-ink: 0 0% 100%;        /* text on a brand-filled surface */
  --m-brand-soft: 213 85% 96%;     /* #eef4fd — tinted wash */
  --m-brand-border: 213 60% 86%;   /* #c5d9f3 */

  --m-action-hover: 12 60% 48%;    /* #c44f31 */
  --m-action-soft: 12 70% 96%;     /* #fdefec */

  /* Surfaces and text */
  --m-bg: 0 0% 100%;
  --m-fg: 210 10% 8%;              /* #121416 — your --base */
  --m-card: 0 0% 100%;
  --m-card-fg: 210 10% 8%;
  --m-muted: 210 8% 96%;
  --m-muted-fg: 210 6% 44%;
  --m-hover: 210 8% 96%;           /* hover wash. Named --m-hover, not
                                      --m-accent, so it is never confused
                                      with your ACSS --accent (#392e1d),
                                      which is a dark warm brown. */
  --m-hover-fg: 210 10% 8%;

  /* "Ink" — the near-black fill for the single highest-emphasis button on a
     view. Your --primary navy rather than a neutral black. */
  --m-ink: 213 64% 11%;            /* #0a1a2e */
  --m-ink-fg: 0 0% 98%;

  --m-border: 210 8% 90%;
  --m-input: 210 8% 90%;
  --m-ring: 213 64% 11%;

  --m-danger: 0 72% 51%;
  --m-danger-fg: 0 0% 98%;

  /* Warning. Added for the organisation statuses - an application that is
     pending is neither an error nor a success, and painting it as either
     misreports it. Reserved for state, like --m-danger; never an accent. */
  --m-warn: 32 85% 32%;
  --m-warn-soft: 40 90% 94%;
  --m-warn-border: 38 75% 80%;

  /* --- Data colors -------------------------------------------------------
     The track is a lighter step of the SAME hue as the fill, so a bar reads
     as one scale rather than two unrelated colors.

     Green means ONE thing here: finished. It was briefly doing double duty -
     "available to pledge" in the visitor's dialog and "complete" in the
     owner's - which also meant the default state of most perek tiles was the
     loudest colour on screen. Available is neutral now.

     --m-viz-open is the older available-green (#2fb64d) the perek chips on
     the manage-pledge page still use, as literal hex. Kept as a token so that
     screen can be moved onto it when it is rebuilt, and so the value has one
     recorded home rather than being retyped from memory.
     ----------------------------------------------------------------------- */
  --m-viz-fill: 213 64% 50%;       /* matches --m-brand */
  --m-viz-track: 213 85% 89%;
  --m-viz-open: 133 59% 45%;       /* #2fb64d — legacy "available" chips */
  --m-viz-open-border: 141 100% 26%; /* #00861e */
  --m-viz-done: 120 86% 34%;       /* #0ca30c — finished */
  --m-viz-done-track: 120 60% 88%;
  --m-success-text: 120 100% 19%;  /* green that is actually readable as text */

  /* Type
     16px, matching the site's body scale. Expressed in rem against the
     site's 62.5% root, so 1.6rem = 16px - the same convention the rest of
     your CSS is authored in. */
  --m-text-base: 1.6rem;
  --m-font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
            Roboto, "Helvetica Neue", Arial, sans-serif;
  /* Hebrew *interface* text — names in form fields, chart headings. Mishnah
     body text keeps Taamey D; a text face is wrong at UI sizes. */
  --m-font-he: "Heebo", "Assistant", "Arial Hebrew", var(--m-font);

  --m-radius: 1.04rem;

  /* ---- Page width --------------------------------------------------------
     The plugin does NOT constrain page width. Its screens are dropped inside
     a Bricks container, and that container is what lines them up with the
     header and footer - two things both setting a max-width is how they end
     up disagreeing by a few pixels.

     Set --m-page-max to a length if you ever need the plugin to constrain
     itself instead (standalone shortcode, no container around it).

     --m-measure-* are different in kind: those are READING measures, not page
     width. A form column and a hero paragraph have an optimum line length
     regardless of how wide the page is, so they stay capped.
     ----------------------------------------------------------------------- */
  --m-page-max: none;
  --m-page-pad: 0rem;

  /* Gap between the dashboard sidebar and its content. Not a page gutter -
     set it to 0 to butt the two columns together. */
  --m-dash-gutter: 3.2rem;
  --m-measure-form: 70.4rem;
  /* Wider, for a form carrying side-by-side cards rather than single fields */
  --m-measure-form-wide: 92rem;
  --m-measure-hero: 73.6rem;

  --m-shadow-sm: 0 1px 2px 0 hsl(240 6% 10% / 0.05);
  --m-shadow-md: 0 4px 6px -1px hsl(240 6% 10% / 0.07),
                 0 2px 4px -2px hsl(240 6% 10% / 0.05);
  --m-shadow-lg: 0 10px 20px -5px hsl(240 6% 10% / 0.10),
                 0 4px 8px -4px hsl(240 6% 10% / 0.06);

  --m-ease: cubic-bezier(0.16, 1, 0.3, 1);
}


/* --------------------------------------------------------------------------
   1b. Section reset

   Automatic.css pads every section that is not inside another section:

       :where(section:not(section section)) {
         padding-block: var(--section-padding-block);
         padding-inline: var(--gutter);
       }

   That is a page-layout rule, and it was landing on the plugin's own
   sections - .m-seder-group, .m-submissions, .m-chart-hero, .m-section - none
   of which want it. They space themselves, and they sit inside a container
   that already supplies the page gutter, so the framework's padding was a
   second one inside the first.

   `:where()` scores zero, so anything of ours wins. But it only wins on
   properties we actually declare, which is why this states both axes rather
   than trusting a shorthand elsewhere to cover it.

   Sections that DO want padding set it in their own rule, after this.
   -------------------------------------------------------------------------- */
.mishnah-ui section {
  padding-block: 0;
  padding-inline: 0;
}


/* --------------------------------------------------------------------------
   2. Scoped reset
   Deliberately narrow. It normalises the elements the plugin actually emits
   and leaves everything else to the theme, because this selector still
   matches anything a Bricks user nests inside a plugin section.
   -------------------------------------------------------------------------- */
.mishnah-ui,
.mishnah-ui *,
.mishnah-ui *::before,
.mishnah-ui *::after {
  box-sizing: border-box;
}

.mishnah-ui {
  font-family: var(--m-font);
  font-size: var(--m-text-base);
  line-height: 1.5;
  color: hsl(var(--m-fg));
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.mishnah-ui h1,
.mishnah-ui h2,
.mishnah-ui h3,
.mishnah-ui h4,
.mishnah-ui p,
.mishnah-ui figure,
.mishnah-ui blockquote,
.mishnah-ui dl,
.mishnah-ui dd {
  margin: 0;
}

/*
 * Headings inside the app use the UI face, not the site's display face.
 *
 * The theme sets a display font on h1-h6 globally, which is right for a
 * marketing page and wrong for an interface: at 12-15px, a display face
 * applied to two dozen small section labels reads as noise rather than
 * personality.
 *
 * h1 is left out on purpose - the one main heading per screen keeps the site
 * font, so the app still looks like part of the site.
 */
.mishnah-ui h2,
.mishnah-ui h3,
.mishnah-ui h4,
.mishnah-ui h5,
.mishnah-ui h6 {
  font-family: var(--m-font);
}

.mishnah-ui ul,
.mishnah-ui ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

.mishnah-ui a {
  color: inherit;
  text-decoration: none;
}

.mishnah-ui button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

.mishnah-ui svg {
  display: block;
  flex-shrink: 0;
}

.mishnah-ui :focus-visible {
  outline: 2px solid hsl(var(--m-ring));
  outline-offset: 2px;
  border-radius: calc(var(--m-radius) - 4px);
}

/* Visible to screen readers, not to eyes. Used for table captions and for
   labels whose text would be redundant next to an icon. */
.mishnah-ui .m-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* --------------------------------------------------------------------------
   3. Button
   --------------------------------------------------------------------------

   ACSS collision guard, first.

   Automatic.css styles buttons with a SUBSTRING match:

       [class*="btn--"]:where(:not(.btn--none, .wp-block-button)) { ... }

   That matches m-btn--brand, m-icon-btn--ghost, m-icon-btn--danger and every
   other modifier here, because each of them contains the characters "btn--".
   The plugin is meant to be free of ACSS, and by specificity it very nearly
   is: that selector scores 0-1-0 (`:where()` contributes nothing), so
   .mishnah-ui .m-btn at 0-2-0 wins every property we actually declare.

   The leak was the properties we did NOT declare. min-inline-size in
   particular - ACSS sets it to var(--btn-min-width), and an icon button with
   a min width is a wide button with a small glyph in the middle, which is why
   they kept rendering as rectangles however the radius was set.

   So this block declares the full set that rule touches. Nothing in it is a
   design decision: each value is either the property's initial value or what
   the primitives below would have inherited anyway. It sits BEFORE them so
   the real rules win on order - put it after, and `border-color: transparent`
   would flatten the outline and danger borders.

   Remove ACSS from the site and every declaration here is still correct, and
   does nothing.
   -------------------------------------------------------------------------- */
.mishnah-ui .m-btn,
.mishnah-ui .m-icon-btn,
.mishnah-ui .m-link-btn {
  min-inline-size: 0;
  font-style: normal;
  text-transform: none;
  letter-spacing: normal;
  text-align: center;
  text-decoration: none;
  border-style: solid;
  border-color: transparent;
}


.mishnah-ui .m-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.8rem;
  height: 3.6rem;
  padding: 0 1.4rem;
  border-radius: calc(var(--m-radius) - 2px);
  font-size: 1.6rem;
  font-weight: 500;
  white-space: nowrap;
  transition: background-color 0.15s var(--m-ease),
              box-shadow 0.15s var(--m-ease),
              transform 0.1s var(--m-ease);
}

.mishnah-ui .m-btn svg {
  width: 1.6rem;
  height: 1.6rem;
}

.mishnah-ui .m-btn--sm { height: 3.2rem; padding: 0 1.2rem; font-size: 1.5rem; }
.mishnah-ui .m-btn--lg { height: 4.6rem; padding: 0 2.2rem; font-size: 1.7rem; }

/* Ink — highest emphasis, one per view */
.mishnah-ui .m-btn--ink {
  background-color: hsl(var(--m-ink));
  color: hsl(var(--m-ink-fg));
  box-shadow: var(--m-shadow-sm);
}

.mishnah-ui .m-btn--ink:hover {
  background-color: hsl(var(--m-ink) / 0.88);
  box-shadow: var(--m-shadow-md);
}

.mishnah-ui .m-btn--ink:active {
  transform: translateY(1px);
  box-shadow: var(--m-shadow-sm);
}

/* Brand — the action that commits to something (pledge, create) */
.mishnah-ui .m-btn--brand {
  background-color: hsl(var(--m-brand));
  color: hsl(var(--m-brand-ink));
  box-shadow: var(--m-shadow-sm);
}

.mishnah-ui .m-btn--brand:hover { background-color: hsl(var(--m-brand-hover)); }
.mishnah-ui .m-btn--brand:active { transform: translateY(1px); }

.mishnah-ui .m-btn--outline {
  border: 1px solid hsl(var(--m-input));
  background-color: hsl(var(--m-bg));
  color: hsl(var(--m-fg));
  box-shadow: var(--m-shadow-sm);
}

.mishnah-ui .m-btn--outline:hover {
  background-color: hsl(var(--m-hover));
  border-color: hsl(var(--m-fg) / 0.2);
}

/* Destructive actions stay outlined until clicked. A filled red button in a
   dialog footer competes with the confirm action next to it. */
.mishnah-ui .m-btn--danger {
  border: 1px solid hsl(var(--m-danger) / 0.3);
  background-color: transparent;
  color: hsl(var(--m-danger));
}

.mishnah-ui .m-btn--danger:hover {
  background-color: hsl(var(--m-danger) / 0.08);
  border-color: hsl(var(--m-danger) / 0.5);
}

.mishnah-ui .m-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* A button that reads as a link — bulk actions like "Select all" */
.mishnah-ui .m-link-btn {
  padding: 0;
  font-size: 1.5rem;
  font-weight: 500;
  color: hsl(var(--m-brand));
  text-decoration: underline;
  text-underline-offset: 2px;
}

.mishnah-ui .m-link-btn:hover { color: hsl(var(--m-brand-hover)); }

/* Round icon-only button */
.mishnah-ui .m-icon-btn {
  display: grid;
  place-items: center;
  /* A <button> carries UA padding that the reset does not clear. With a fixed
     width and height that padding shifts the glyph off centre instead of
     making the button bigger, which is why the trash icon sat low and left. */
  padding: 0;
  width: 2.8rem;
  height: 2.8rem;
  flex-shrink: 0;
  border: 1px solid hsl(var(--m-border));
  border-radius: 999px;
  background-color: hsl(var(--m-card));
  color: hsl(var(--m-muted-fg));
  transition: background-color 0.15s var(--m-ease), color 0.15s var(--m-ease),
              border-color 0.15s var(--m-ease);
}

.mishnah-ui .m-icon-btn svg { width: 1.3rem; height: 1.3rem; }

.mishnah-ui .m-icon-btn:hover {
  background-color: hsl(var(--m-brand));
  border-color: hsl(var(--m-brand));
  color: hsl(var(--m-brand-ink));
}


/* --------------------------------------------------------------------------
   4. Card
   -------------------------------------------------------------------------- */
.mishnah-ui .m-card {
  background-color: hsl(var(--m-card));
  color: hsl(var(--m-card-fg));
  border: 1px solid hsl(var(--m-border));
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow-sm);
}


/* --------------------------------------------------------------------------
   5. Progress bar
   Square at the baseline, rounded at the data end — the mark's own shape says
   where the scale starts and where the value stops. Width comes from an
   inline `--m-pct` on .m-bar, so the same class serves every bar on the site.
   -------------------------------------------------------------------------- */
.mishnah-ui .m-bar {
  position: relative;
  height: 0.8rem;
  border-radius: 999px;
  background-color: hsl(var(--m-viz-track));
  overflow: hidden;
}

.mishnah-ui .m-bar__fill {
  display: block;
  height: 100%;
  width: var(--m-pct, 0%);
  border-radius: 999px;
  background-color: hsl(var(--m-viz-fill));

  /*
   * The fill, on the way in.
   *
   * The width comes from --m-pct, which the template writes inline at its
   * final value - so with JavaScript off the bar is simply correct and this
   * transition never fires, because nothing ever changes. What animates it is
   * js/mishnah-progress-bar.js: it takes the value away, then puts it back
   * when the bar scrolls into view.
   *
   * 1.5s matches the legacy .progress-bar-fill on the chart hero, so the two
   * kinds of bar still move at the same speed on a page that has both. The
   * ease is the design system's, decelerating hard at the end, which is what
   * makes a bar look like it is settling on a number rather than stopping at
   * one.
   */
  transition: width 1.5s var(--m-ease);
}

@media (prefers-reduced-motion: reduce) {
  .mishnah-ui .m-bar__fill { transition: none; }
}

/* Finished. Paired with a check icon or the word "complete" in the markup —
   never color alone. */
.mishnah-ui .m-bar--done { background-color: hsl(var(--m-viz-done-track)); }
.mishnah-ui .m-bar--done .m-bar__fill { background-color: hsl(var(--m-viz-done)); }

/* RTL: the bar is a quantity growing from the start edge, so the fill sits
   against the right in Hebrew. The radius needs no flip now that both ends
   are round. */
.mishnah-rtl .mishnah-ui .m-bar__fill {
  margin-inline-start: auto;
}


/* --------------------------------------------------------------------------
   6. Badges, pills, status chips
   -------------------------------------------------------------------------- */
.mishnah-ui .m-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.1rem 0.7rem;
  border: 1px solid hsl(var(--m-border));
  border-radius: 999px;
  background-color: hsl(var(--m-muted));
  font-size: 1.3rem;
  font-weight: 500;
  color: hsl(var(--m-muted-fg));
}

.mishnah-ui .m-badge svg { width: 1.1rem; height: 1.1rem; }

.mishnah-ui .m-badge--brand {
  border-color: hsl(var(--m-brand-border));
  background-color: hsl(var(--m-brand-soft));
  color: hsl(var(--m-brand));
}

.mishnah-ui .m-badge--done {
  border-color: hsl(var(--m-viz-done) / 0.3);
  background-color: hsl(var(--m-viz-done) / 0.12);
  color: hsl(var(--m-success-text));
}

.mishnah-ui .m-badge--danger {
  border-color: hsl(var(--m-danger) / 0.3);
  background-color: hsl(var(--m-danger) / 0.08);
  color: hsl(var(--m-danger));
}

.mishnah-ui .m-badge__dot {
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 999px;
  background-color: currentColor;
}


/* --------------------------------------------------------------------------
   7. Form fields
   -------------------------------------------------------------------------- */
/*
 * Stated, not assumed. A field is usually a <div> and block by default, but
 * the hadran form uses a <label> as the field - js/mishnah-hadran.js hides a
 * select by calling closest('label') on it - and an inline label lays its
 * label, hint and control out as one run of text.
 */
.mishnah-ui .m-field { display: block; }

.mishnah-ui .m-field + .m-field,
.mishnah-ui .m-field-row + .m-field,
.mishnah-ui .m-field + .m-field-row,
.mishnah-ui .m-field-row + .m-field-row {
  margin-top: 2rem;
}

/*
 * Fields side by side in a row are siblings too, so the rule above was giving
 * the second one a 2rem top margin and dropping it below the first - Occasion
 * sat lower than Siyum Date. The row's own `gap` is what spaces these.
 */
.mishnah-ui .m-field-row > .m-field + .m-field {
  margin-top: 0;
}

.mishnah-ui .m-field-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2rem;
}

.mishnah-ui .m-label {
  display: block;
  margin-bottom: 0.7rem;
  font-size: 1.6rem;
  font-weight: 500;
}

.mishnah-ui .m-req {
  margin-inline-start: 0.2rem;
  color: hsl(var(--m-brand));
}

.mishnah-ui .m-hint {
  margin-top: 0.7rem;
  font-size: 1.4rem;
  color: hsl(var(--m-muted-fg));
}

.mishnah-ui .m-input,
.mishnah-ui .m-select-wrap select {
  display: block;
  width: 100%;
  height: 4.4rem;
  padding: 0 1.4rem;
  border: 1px solid hsl(var(--m-input));
  border-radius: calc(var(--m-radius) - 2px);
  background-color: hsl(var(--m-card));
  font: inherit;
  font-size: 1.7rem;
  color: hsl(var(--m-fg));
  box-shadow: var(--m-shadow-sm);
  transition: border-color 0.15s var(--m-ease), box-shadow 0.15s var(--m-ease);
}

.mishnah-ui .m-input::placeholder { color: hsl(var(--m-muted-fg) / 0.8); }

.mishnah-ui .m-input:focus,
.mishnah-ui .m-select-wrap select:focus {
  outline: none;
  border-color: hsl(var(--m-ring));
  box-shadow: 0 0 0 3px hsl(var(--m-ring) / 0.14);
}

/* :user-invalid, not :invalid — a required field is invalid the moment the
   page loads, and flagging it red before the visitor has typed anything is
   just scolding them for not having started yet. */
.mishnah-ui .m-input:user-invalid,
.mishnah-ui .m-select-wrap select:user-invalid {
  border-color: hsl(var(--m-danger));
}

.mishnah-ui .m-input:user-invalid:focus {
  box-shadow: 0 0 0 3px hsl(var(--m-danger) / 0.14);
}

/* Hebrew name entry. dir="rtl" belongs on the element itself; this is the
   rest of it. */
.mishnah-ui .m-input--he {
  text-align: right;
  font-size: 2rem;
  font-family: var(--m-font-he);
}

.mishnah-ui .m-input--he::placeholder { text-align: right; }

.mishnah-ui .m-select-wrap { position: relative; }

.mishnah-ui .m-select-wrap select {
  padding-inline-end: 3.6rem;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  /*
   * The theme paints its own chevron on <select> as a background-image.
   * appearance:none removes the NATIVE arrow but not that one, which is why
   * these fields were showing two. We supply our own icon, so clear it.
   */
  background-image: none;
}

/* Hold the placeholder option at muted weight until a real choice is made,
   so an untouched select does not read as answered. */
.mishnah-ui .m-select-wrap select:has(option[value=""]:checked) {
  color: hsl(var(--m-muted-fg) / 0.8);
}

.mishnah-ui .m-select-wrap__icon {
  position: absolute;
  top: 50%;
  inset-inline-end: 1.4rem;
  width: 1.4rem;
  height: 1.4rem;
  transform: translateY(-50%);
  color: hsl(var(--m-muted-fg));
  pointer-events: none;
}

/* Inline error message under a field or fieldset */
.mishnah-ui .m-error {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1rem;
  font-size: 1.5rem;
  font-weight: 500;
  color: hsl(var(--m-danger));
}

.mishnah-ui .m-error svg { width: 1.4rem; height: 1.4rem; }
.mishnah-ui .m-error[hidden] { display: none; }

/*
 * Notices — the counterpart to .m-error, for a result rather than a problem.
 *
 * The change-password form's confirmation uses this. It was rendering
 * unstyled: a bare tick and a sentence with no ground, which read like an
 * accident rather than a success.
 */
.mishnah-ui .m-notice {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-top: 1.6rem;
  padding: 1rem 1.4rem;
  border: 1px solid hsl(var(--m-border));
  border-radius: calc(var(--m-radius) - 3px);
  background-color: hsl(var(--m-muted));
  font-size: 1.4rem;
  color: hsl(var(--m-fg));
}

.mishnah-ui .m-notice svg {
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
}

.mishnah-ui .m-notice[hidden] { display: none; }

.mishnah-ui .m-notice--success {
  border-color: hsl(var(--m-viz-done) / 0.3);
  background-color: hsl(var(--m-viz-done) / 0.1);
  color: hsl(var(--m-success-text));
}

.mishnah-ui .m-notice--danger {
  border-color: hsl(var(--m-danger) / 0.3);
  background-color: hsl(var(--m-danger) / 0.08);
  color: hsl(var(--m-danger));
}


/* --------------------------------------------------------------------------
   8. Selectable controls
   -------------------------------------------------------------------------- */

/* --- Radio card ---------------------------------------------------------- */
/*
 * Side by side from 48rem up. Three visibility choices compared against each
 * other read better in a row - the differences are in the descriptions, and
 * stacking them puts those descriptions a scroll apart.
 */
.mishnah-ui .m-radio-set {
  display: grid;
  /* 26rem, not 22: below about 260px a card with an icon, a title, a pill and
     two lines of description has nowhere to put them. Under that width these
     stack instead, which is the right answer on a phone anyway. */
  grid-template-columns: repeat(auto-fit, minmax(26rem, 1fr));
  gap: 1.2rem;
  align-items: stretch;
}

/*
 * Grid, not flex, so the icon can sit BESIDE the title while the description
 * runs full width underneath both. As a flex row the description was trapped
 * in a column with the title and indented past the icon.
 *
 * width is stated because the visibility cards still carry the legacy
 * .chart-visibility class as a compat hook, and css/manage-chart.css sets
 * `.chart-visibility { width: 33.3% }` for the old flex row. Inside this grid
 * that made each card a third of its own column - three narrow, clipped cards
 * with two thirds of each column empty. auto is the grid default: fill the
 * area the track gives you.
 */
.mishnah-ui .m-radio-card {
  position: relative;
  width: auto;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "icon  title check"
    "desc  desc  desc";
  align-items: center;
  gap: 0.6rem 1.2rem;
  padding: 1.6rem 1.8rem;
  border: 1px solid hsl(var(--m-border));
  border-radius: var(--m-radius);
  background-color: hsl(var(--m-card));
  cursor: pointer;
  transition: border-color 0.15s var(--m-ease),
              background-color 0.15s var(--m-ease);
}

.mishnah-ui .m-radio-card__icon  { grid-area: icon; }
.mishnah-ui .m-radio-card__title { grid-area: title; }
.mishnah-ui .m-radio-card__desc  { grid-area: desc; }
.mishnah-ui .m-radio-card__check { grid-area: check; }

.mishnah-ui .m-radio-card:hover { border-color: hsl(var(--m-fg) / 0.22); }

/* The real radio stays in the DOM and keeps the keyboard and screen-reader
   behaviour; only its rendering is replaced. */
.mishnah-ui .m-radio-card input,
.mishnah-ui .m-chip input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.mishnah-ui .m-radio-card:has(input:checked) {
  border-color: hsl(var(--m-brand));
  background-color: hsl(var(--m-brand-soft));
  box-shadow: 0 0 0 1px hsl(var(--m-brand));
}

.mishnah-ui .m-radio-card:has(input:focus-visible) {
  outline: 2px solid hsl(var(--m-ring));
  outline-offset: 2px;
}

.mishnah-ui .m-radio-card__icon {
  display: grid;
  place-items: center;
  width: 3.2rem;
  height: 3.2rem;
  flex-shrink: 0;
  border-radius: calc(var(--m-radius) - 3px);
  background-color: hsl(var(--m-muted));
  color: hsl(var(--m-muted-fg));
  transition: background-color 0.15s var(--m-ease), color 0.15s var(--m-ease);
}

.mishnah-ui .m-radio-card__icon svg { width: 1.6rem; height: 1.6rem; }

.mishnah-ui .m-radio-card:has(input:checked) .m-radio-card__icon {
  background-color: hsl(var(--m-brand));
  color: hsl(var(--m-brand-ink));
}

.mishnah-ui .m-radio-card__title {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
  min-width: 0;
  font-size: 1.7rem;
  font-weight: 600;
}

.mishnah-ui .m-radio-card__desc {
  font-size: 1.4rem;
  line-height: 1.5;
  color: hsl(var(--m-muted-fg));
}

.mishnah-ui .m-radio-card__check {
  flex-shrink: 0;
  width: 1.8rem;
  height: 1.8rem;
  color: hsl(var(--m-brand));
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 0.15s var(--m-ease), transform 0.15s var(--m-ease);
}

.mishnah-ui .m-radio-card:has(input:checked) .m-radio-card__check {
  opacity: 1;
  transform: scale(1);
}

.mishnah-ui .m-radio-card.is-disabled {
  opacity: 0.5;
  pointer-events: none;
}

/* --- Toggle chip --------------------------------------------------------- */
.mishnah-ui .m-chip-set {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.mishnah-ui .m-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.8rem 1.6rem;
  border: 1px solid hsl(var(--m-input));
  border-radius: 999px;
  background-color: hsl(var(--m-card));
  font-size: 1.6rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: border-color 0.15s var(--m-ease),
              background-color 0.15s var(--m-ease), color 0.15s var(--m-ease);
}

.mishnah-ui .m-chip:hover {
  border-color: hsl(var(--m-fg) / 0.28);
  background-color: hsl(var(--m-hover));
}

.mishnah-ui .m-chip:has(input:checked) {
  border-color: hsl(var(--m-brand));
  background-color: hsl(var(--m-brand));
  color: hsl(var(--m-brand-ink));
}

.mishnah-ui .m-chip:has(input:focus-visible) {
  outline: 2px solid hsl(var(--m-ring));
  outline-offset: 2px;
}

/* A plus when the chip is off, a tick when it is on, so selection is legible
   without relying on the fill colour.

   Both marks are in the markup and one is hidden, rather than one mark being
   transformed. The previous rule rotated the plus 90deg on select, which is
   a no-op: a plus has four-fold symmetry, so a quarter turn lands on itself.
   Nothing changed on screen except the opacity. */
.mishnah-ui .m-chip__mark {
  width: 1.4rem;
  height: 1.4rem;
  opacity: 0.5;
  transition: opacity 0.15s var(--m-ease);
}

.mishnah-ui .m-chip__mark--on { display: none; }

.mishnah-ui .m-chip:has(input:checked) .m-chip__mark--off { display: none; }

.mishnah-ui .m-chip:has(input:checked) .m-chip__mark--on {
  display: block;
  opacity: 1;
}

/* Without :has() the plus stays and the tick never appears - the chip still
   reads as selected from its fill. */
@supports not selector(:has(*)) {
  .mishnah-ui .m-chip__mark--on { display: none; }
}

/* --- Switch -------------------------------------------------------------- */
.mishnah-ui .m-switch {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  font-size: 1.6rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
}

.mishnah-ui .m-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.mishnah-ui .m-switch__track {
  position: relative;
  width: 3.6rem;
  height: 2.1rem;
  flex-shrink: 0;
  border-radius: 999px;
  background-color: hsl(var(--m-muted-fg) / 0.35);
  transition: background-color 0.18s var(--m-ease);
}

.mishnah-ui .m-switch__thumb {
  position: absolute;
  top: 0.3rem;
  inset-inline-start: 0.3rem;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  background-color: #fff;
  box-shadow: var(--m-shadow-sm);
  transition: transform 0.18s var(--m-ease);
}

.mishnah-ui .m-switch:has(input:checked) .m-switch__track {
  background-color: hsl(var(--m-brand));
}

.mishnah-ui .m-switch:has(input:checked) .m-switch__thumb {
  transform: translateX(1.5rem);
}

/* The thumb travels toward the end edge, which is leftward in RTL */
.mishnah-rtl .mishnah-ui .m-switch:has(input:checked) .m-switch__thumb {
  transform: translateX(-0.9375rem);
}

.mishnah-ui .m-switch:has(input:focus-visible) .m-switch__track {
  outline: 2px solid hsl(var(--m-ring));
  outline-offset: 2px;
}

/* --- Perek grid ---------------------------------------------------------- */
.mishnah-ui .m-perek-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.4rem, 1fr));
  gap: 0.6rem;
}

.mishnah-ui .m-perek {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border: 1px solid hsl(var(--m-input));
  border-radius: calc(var(--m-radius) - 4px);
  background-color: hsl(var(--m-bg));
  font-size: 1.5rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color 0.12s var(--m-ease),
              border-color 0.12s var(--m-ease), color 0.12s var(--m-ease);
}

.mishnah-ui .m-perek input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.mishnah-ui .m-perek:hover { border-color: hsl(var(--m-fg) / 0.3); }

.mishnah-ui .m-perek:has(input:focus-visible) {
  outline: 2px solid hsl(var(--m-ring));
  outline-offset: 2px;
}

/* --- Owner's edit dialog: marking a perek finished -----------------------
   Green here means "complete". */
.mishnah-ui .m-perek--done:has(input:checked) {
  background-color: hsl(var(--m-viz-done));
  border-color: hsl(var(--m-viz-done));
  color: #fff;
}

/* --- Visitor's pledge sheet ----------------------------------------------
   Available perakim are NEUTRAL, not green.

   Green used to mean "available" here and "complete" in the owner's dialog -
   one colour doing two jobs. Worse, available is the DEFAULT state of most
   tiles, so a masechta with twenty free perakim rendered as a wall of green
   and the loudest thing in the dialog was the thing the visitor had not done
   anything about yet.

   Now each colour means exactly one thing: green is finished, brand is your
   selection, grey is unavailable, neutral is open. The only coloured tiles in
   the grid are the ones you picked - which is what the dialog is asking about.

   The background is stated explicitly rather than left to inherit, because
   css/display-mishnah-chart.css still carries a green .perek-popup.available
   rule from the old markup.
   ----------------------------------------------------------------------- */
.mishnah-ui .m-perek--open {
  background-color: hsl(var(--m-bg));
  border-color: hsl(var(--m-input));
  color: hsl(var(--m-fg));
}

.mishnah-ui .m-perek--open:hover {
  border-color: hsl(var(--m-brand));
  background-color: hsl(var(--m-brand-soft));
}

/* Selected. `.is-picked` is toggled by js/display-mishnah-chart.js; the
   :has(input:checked) form covers any markup using a real checkbox. */
.mishnah-ui .m-perek--open.is-picked,
.mishnah-ui .m-perek--open:has(input:checked) {
  background-color: hsl(var(--m-brand));
  border-color: hsl(var(--m-brand));
  color: hsl(var(--m-brand-ink));
}

.mishnah-ui .m-perek--open.is-picked:hover {
  background-color: hsl(var(--m-brand-hover));
  border-color: hsl(var(--m-brand-hover));
}

/* The tick. Sits over the number rather than beside it — the tiles are
   square and there is no room for both, and once it is picked the number
   matters less than the fact that it is picked. */
.mishnah-ui .m-perek__check {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 0.12s var(--m-ease), transform 0.12s var(--m-ease);
  pointer-events: none;
}

.mishnah-ui .m-perek__check svg {
  width: 1.8rem;
  height: 1.8rem;
  stroke: currentColor;
}

.mishnah-ui .m-perek.is-picked .m-perek__check,
.mishnah-ui .m-perek:has(input:checked) .m-perek__check {
  opacity: 1;
  transform: scale(1);
}

/* Hide the number once the tick replaces it */
.mishnah-ui .m-perek__num {
  transition: opacity 0.12s var(--m-ease);
}

.mishnah-ui .m-perek.is-picked .m-perek__num,
.mishnah-ui .m-perek:has(input:checked) .m-perek__num {
  opacity: 0;
}

/* Outside this pledge's range */
.mishnah-ui .m-perek--locked {
  opacity: 0.4;
  cursor: not-allowed;
  background-color: hsl(var(--m-muted));
}

/* Already claimed by somebody else. Struck through as well as dimmed, so it
   is not opacity alone carrying the meaning. */
.mishnah-ui .m-perek--taken {
  opacity: 0.45;
  cursor: not-allowed;
  background-color: hsl(var(--m-muted));
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.mishnah-ui .m-perek--locked:hover,
.mishnah-ui .m-perek--taken:hover { border-color: hsl(var(--m-input)); }


/* --------------------------------------------------------------------------
   9. Toolbar controls — search and compact select
   -------------------------------------------------------------------------- */
.mishnah-ui .m-toolbar {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  flex-wrap: wrap;
  margin: 2rem 0;
}

.mishnah-ui .m-search {
  position: relative;
  flex: 1 1 25.6rem;
  max-width: 35.2rem;
}

.mishnah-ui .m-search__icon {
  position: absolute;
  top: 50%;
  inset-inline-start: 1.2rem;
  width: 1.6rem;
  height: 1.6rem;
  transform: translateY(-50%);
  color: hsl(var(--m-muted-fg));
  pointer-events: none;
}

.mishnah-ui .m-search__input {
  width: 100%;
  height: 3.6rem;
  padding-block: 0;
  padding-inline: 3.6rem 1.2rem;
  border: 1px solid hsl(var(--m-input));
  border-radius: calc(var(--m-radius) - 2px);
  background-color: hsl(var(--m-bg));
  font: inherit;
  color: hsl(var(--m-fg));
  box-shadow: var(--m-shadow-sm);
  transition: border-color 0.15s var(--m-ease), box-shadow 0.15s var(--m-ease);
}

.mishnah-ui .m-search__input::placeholder { color: hsl(var(--m-muted-fg)); }

.mishnah-ui .m-search__input:focus {
  outline: none;
  border-color: hsl(var(--m-ring));
  box-shadow: 0 0 0 3px hsl(var(--m-ring) / 0.12);
}

/* WebKit's own clear button duplicates the one the field already implies */
.mishnah-ui .m-search__input::-webkit-search-decoration,
.mishnah-ui .m-search__input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

.mishnah-ui .m-select {
  position: relative;
  display: inline-flex;
}

.mishnah-ui .m-select select {
  height: 3.6rem;
  padding-block: 0;
  padding-inline: 1.2rem 3.2rem;
  background-image: none;   /* see the note on .m-select-wrap select */
  border: 1px solid hsl(var(--m-input));
  border-radius: calc(var(--m-radius) - 2px);
  background-color: hsl(var(--m-bg));
  font: inherit;
  color: hsl(var(--m-fg));
  box-shadow: var(--m-shadow-sm);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.mishnah-ui .m-select select:focus {
  outline: none;
  border-color: hsl(var(--m-ring));
  box-shadow: 0 0 0 3px hsl(var(--m-ring) / 0.12);
}

.mishnah-ui .m-select__icon {
  position: absolute;
  top: 50%;
  inset-inline-end: 1rem;
  width: 1.4rem;
  height: 1.4rem;
  transform: translateY(-50%);
  color: hsl(var(--m-muted-fg));
  pointer-events: none;
}

.mishnah-ui .m-toolbar__count {
  margin-inline-start: auto;
  font-size: 1.5rem;
  color: hsl(var(--m-muted-fg));
  font-variant-numeric: tabular-nums;
}


/* --------------------------------------------------------------------------
   10. Table
   -------------------------------------------------------------------------- */
.mishnah-ui .m-table-card { overflow: hidden; }
.mishnah-ui .m-table-scroll { overflow-x: auto; }

.mishnah-ui .m-table {
  width: 100%;
  border-collapse: collapse;
  text-align: start;
}

.mishnah-ui .m-table th {
  padding: 1.2rem 1.6rem;
  text-align: start;
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: hsl(var(--m-muted-fg));
  background-color: hsl(var(--m-muted) / 0.4);
  border-bottom: 1px solid hsl(var(--m-border));
  white-space: nowrap;
}

.mishnah-ui .m-table td {
  padding: 1.4rem 1.6rem;
  vertical-align: middle;
  border-bottom: 1px solid hsl(var(--m-border));
}

.mishnah-ui .m-table tbody tr {
  transition: background-color 0.12s var(--m-ease);
}

.mishnah-ui .m-table tbody tr:hover { background-color: hsl(var(--m-muted) / 0.45); }
.mishnah-ui .m-table tbody tr:last-child td { border-bottom: none; }

.mishnah-ui .m-table__empty {
  padding: 4rem 1.6rem;
  text-align: center;
  color: hsl(var(--m-muted-fg));
}


/* --------------------------------------------------------------------------
   11. Dialog contents
   --------------------------------------------------------------------------

   These style the INSIDE of a dialog only — head, body, sections, footer.
   They are deliberately container-agnostic, because the plugin does not own
   the container: SweetAlert2 supplies it on desktop and Plainsheet supplies
   the bottom sheet on phones, and both stay.

   So the markup is `<div class="mishnah-ui">…</div>` handed to Swal's `html`
   option or Plainsheet's content, and everything below applies within it. The
   two host containers themselves are themed in section 11b.
   -------------------------------------------------------------------------- */
.mishnah-ui .m-dialog__form {
  display: flex;
  flex-direction: column;
  max-height: inherit;
}

.mishnah-ui .m-dialog__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.6rem;
  padding: 2rem 2rem 1.6rem;
  border-bottom: 1px solid hsl(var(--m-border));
}

.mishnah-ui .m-dialog__title {
  font-size: 2rem;
  font-weight: 650;
  letter-spacing: -0.015em;
}

.mishnah-ui .m-dialog__sub {
  margin-top: 0.3rem;
  font-size: 1.5rem;
  color: hsl(var(--m-muted-fg));
}

.mishnah-ui .m-dialog__close {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  flex-shrink: 0;
  border-radius: calc(var(--m-radius) - 4px);
  color: hsl(var(--m-muted-fg));
  transition: background-color 0.15s var(--m-ease), color 0.15s var(--m-ease);
}

.mishnah-ui .m-dialog__close svg { width: 1.6rem; height: 1.6rem; }

.mishnah-ui .m-dialog__close:hover {
  background-color: hsl(var(--m-hover));
  color: hsl(var(--m-fg));
}

.mishnah-ui .m-dialog__body {
  padding: 2rem;
  overflow-y: auto;
}

.mishnah-ui .m-dialog__section + .m-dialog__section {
  margin-top: 2.4rem;
  padding-top: 2rem;
  border-top: 1px solid hsl(var(--m-border));
}

.mishnah-ui .m-dialog__legend {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.6rem;
  margin-bottom: 1.2rem;
}

.mishnah-ui .m-dialog__legend b { font-size: 1.6rem; font-weight: 600; }

.mishnah-ui .m-dialog__note {
  font-size: 1.4rem;
  color: hsl(var(--m-muted-fg));
  font-variant-numeric: tabular-nums;
}

.mishnah-ui .m-dialog__foot {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.6rem 2rem;
  border-top: 1px solid hsl(var(--m-border));
  background-color: hsl(var(--m-muted) / 0.5);
  /* Rather than overflow. Two worded buttons plus a third in a 544px dialog
     ran past the edge in Hebrew, where every label is longer. */
  flex-wrap: wrap;
}

/* Shrink before clipping. */
.mishnah-ui .m-dialog__foot .m-btn { min-width: 0; }

.mishnah-ui .m-dialog__spacer { margin-inline-start: auto; }

/* The destructive control in a dialog footer: icon only, and visibly apart
   from the pair of buttons that end the dialog. */
.mishnah-ui .m-dialog__foot .m-icon-btn--danger {
  width: 3.4rem;
  height: 3.4rem;
  border-color: transparent;
  background: transparent;
  color: hsl(var(--m-muted-fg));
}

.mishnah-ui .m-dialog__foot .m-icon-btn--danger svg {
  width: 1.6rem;
  height: 1.6rem;
}

.mishnah-ui .m-dialog__foot .m-icon-btn--danger:hover {
  background-color: hsl(var(--m-danger) / 0.1);
  border-color: transparent;
  color: hsl(var(--m-danger));
}

/* The head and foot stay put while only the body scrolls, so the title and
   the confirm button are reachable in a long perek list without scrolling
   back. Needs the host container to have a bounded height — both hosts do,
   see 11b. */
.mishnah-ui .m-dialog__head,
.mishnah-ui .m-dialog__foot {
  flex-shrink: 0;
}


/* --------------------------------------------------------------------------
   11b. Host containers — SweetAlert2 and Plainsheet
   --------------------------------------------------------------------------

   Both are third-party and render outside .mishnah-ui, so these selectors
   are scoped by a marker class the plugin puts on the host instead:
   `mishnah-ui-modal` on the Swal popup (via its customClass option) and
   `mishnah-ui-sheet` on the Plainsheet container.

   That keeps the theming off every other SweetAlert on the site — the error
   handler and the confirm dialogs keep the look they have in
   css/mishnah-global.css.
   -------------------------------------------------------------------------- */

/* --- SweetAlert2, used as the desktop modal ------------------------------ */
.swal2-popup.mishnah-ui-modal {
  width: min(54.4rem, calc(100vw - 3.2rem));
  max-height: min(85vh, 76.8rem);
  padding: 0;
  border-radius: var(--m-radius);
  background-color: hsl(var(--m-card));
  color: hsl(var(--m-fg));
  box-shadow: var(--m-shadow-lg);
  overflow: hidden;
}

/* Swal's own chrome is redundant once .m-dialog__head / __foot are supplying
   the title and the buttons. */
.swal2-popup.mishnah-ui-modal .swal2-title,
.swal2-popup.mishnah-ui-modal .swal2-actions,
.swal2-popup.mishnah-ui-modal .swal2-close,
.swal2-popup.mishnah-ui-modal .swal2-icon {
  display: none;
}

.swal2-popup.mishnah-ui-modal .swal2-html-container {
  margin: 0;
  padding: 0;
  overflow: visible;      /* the inner .m-dialog__body owns the scrolling */
  max-height: none;
  text-align: start;
  font-size: inherit;
  color: inherit;
}

.swal2-popup.mishnah-ui-modal .mishnah-ui {
  display: flex;
  flex-direction: column;
  max-height: min(85vh, 76.8rem);
}

/* --- Plainsheet, used as the phone bottom sheet -------------------------- */
/*
 * Plainsheet's container is a <section>. Automatic.css styles every top-level
 * section:
 *
 *     :where(section:not(section section)) {
 *       padding-block: var(--section-padding-block);
 *       padding-inline: var(--gutter);
 *     }
 *
 * `:where()` scores zero, so this rule wins easily - but only because it sets
 * padding at all. Stating it on both axes rather than relying on the shorthand
 * keeps that true if the shorthand is ever narrowed.
 */
.pbs-container.mishnah-ui-sheet {
  width: 100% !important;
  padding: 0;
  padding-block: 0;
  padding-inline: 0;
  border-radius: var(--m-radius) var(--m-radius) 0 0;
  background-color: hsl(var(--m-card));
  color: hsl(var(--m-fg));
  overflow: hidden;
}

.pbs-container.mishnah-ui-sheet .mishnah-ui {
  display: flex;
  flex-direction: column;
  max-height: 88vh;
}

/* The drag handle. Plainsheet draws its own on some versions; this is ours,
   rendered in the markup and hidden wherever the sheet is not a sheet. */
.mishnah-ui .m-sheet__grab {
  display: block;
  width: 3.6rem;
  height: 0.4rem;
  margin: 1rem auto 0;
  flex-shrink: 0;
  border-radius: 999px;
  background-color: hsl(var(--m-muted-fg) / 0.35);
}

.swal2-popup.mishnah-ui-modal .m-sheet__grab { display: none; }

/*
 * ...and inside a Plainsheet too.
 *
 * The comment on .m-sheet__grab says Plainsheet draws its own "on some
 * versions". The version vendored here does - .pbs-handle with a
 * .pbs-handle-bar inside it - so the sheet was showing two grab bars above a
 * close button, which reads as one bottom sheet inside another.
 *
 * Plainsheet's is the one that works: it is the drag affordance for the
 * gesture Plainsheet itself handles. Ours never did anything.
 */
.pbs-container .m-sheet__grab { display: none; }

/*
 * And the sheet supplies the outer surface, so the dialog inside it must not
 * paint a second one. Without this the card's own background, border and
 * radius sit inset within the sheet's.
 */
.pbs-container.mishnah-ui-sheet .m-dialog__head { padding-top: 0.8rem; }

/* Keep the footer buttons clear of the phone's home indicator */
.pbs-container.mishnah-ui-sheet .m-dialog__foot {
  padding-bottom: max(1.6rem, env(safe-area-inset-bottom));
}


/* --------------------------------------------------------------------------
   12. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 40rem) {
  .mishnah-ui .m-field-row { grid-template-columns: minmax(0, 1fr); }

  /* Stacked footer buttons get equal width rather than hugging their text.
     The icon button is excluded - it is square, and stretching it to a third
     of the row is what made the footer look broken. */
  .mishnah-ui .m-dialog__foot .m-btn { flex: 1; }
  .mishnah-ui .m-dialog__foot .m-dialog__spacer {
    margin-inline-start: 0;
    width: 100%;
  }
}


/* --------------------------------------------------------------------------
   13. Motion preferences
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .mishnah-ui *,
  .mishnah-ui *::before,
  .mishnah-ui *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .mishnah-ui .m-perek__check,
  .mishnah-ui .m-perek__num { transition: none; }
}


/* --------------------------------------------------------------------------
   14. Read-only input
   Used for the profile email, which is shown for reference but is the key
   pledges and invitations are matched on, so it is not editable here.
   -------------------------------------------------------------------------- */
.mishnah-ui .m-input--readonly,
.mishnah-ui .m-input[readonly] {
  background-color: hsl(var(--m-muted));
  color: hsl(var(--m-muted-fg));
  cursor: not-allowed;
  box-shadow: none;
}

.mishnah-ui .m-input[readonly]:focus {
  border-color: hsl(var(--m-input));
  box-shadow: none;
}

/* A set of choices that should stay stacked whatever the width */
.mishnah-ui .m-radio-set--stack { grid-template-columns: minmax(0, 1fr); }
