/* Team Expansion Applications — brand styling, no framework.

   Colour is organised in three layers:
     1. Palette   — the org colour sheet, verbatim. Never edit these values.
     2. Derived   — darkened variants of palette colours, needed where the
                    palette value itself fails WCAG AA (4.5:1) as text on
                    white. Each records its measured contrast ratio.
     3. Semantic  — what the UI actually references. Restyle by repointing
                    these, not by reaching into layer 1 or 2.

   Palette colours that are NOT legible as body text on white — do not use
   them for text: --te-blue (2.2:1), --te-teal (2.8:1), --te-gold (1.9:1),
   --te-sky (1.6:1). --te-slate (3.2:1) is borders/large text only. */
:root {
  /* ---- 1. Palette: Palette 1 (cool; applicant-facing) ---- */
  --te-slate:        #888d8a;
  --te-charcoal:     #414041;
  --te-sky:          #afc9d9;
  --te-blue:         #83b0da;
  --te-navy:         #1c252e;

  /* ---- 1. Palette: Universal ---- */
  --te-white:        #ffffff;
  --te-black:        #000000;
  --te-gold:         #edb73e;
  --te-crimson:      #8c191b;
  --te-bone:         #eae5e1;

  /* ---- 1. Palette: Palette 2 (warm; internal + advisory surfaces) ---- */
  --te-cream:        #ebe2d3;
  --te-taupe:        #c0b9ad;
  --te-brown:        #6e4d37;
  --te-espresso:     #302218;
  --te-teal:         #4ca3a7;

  /* ---- 2. Derived: same hue, darkened to clear AA on white ---- */
  --te-blue-deep:    #2b6696;  /* from --te-blue,  6.1:1 — links, primary actions */
  --te-slate-deep:   #5f6360;  /* from --te-slate, 6.1:1 — secondary / meta text */
  --te-teal-deep:    #2e6a6b;  /* from --te-teal,  6.1:1 — success, completed, ACT buttons */
  --te-teal-deeper:  #234f50;  /* from --te-teal, ~9:1 — ACT button hover */

  /* ---- 2. Derived: pale surface tints ---- */
  --te-teal-tint:    #eaf3f3;  /* success banner fill */
  --te-sunken:       #faf8f7;  /* inset/scrolling regions */

  /* ---- 3. Semantic: text ---- */
  --te-text:         var(--te-charcoal);
  --te-text-muted:   var(--te-slate-deep);
  --te-text-invert:  var(--te-white);

  /* ---- 3. Semantic: surfaces ---- */
  --te-surface:        var(--te-white);
  --te-surface-sunken: var(--te-sunken);
  /* Light, because the org logo is drawn dark-on-transparent: black wordmark,
     grey map, crimson swoosh. On the old navy header the wordmark sat at
     1.35:1 and was invisible. teamexpansion.org serves it on white too.
     Admin stays cream so the internal portal is still unmistakable. */
  --te-header:         var(--te-white);
  --te-header-admin:   var(--te-cream);
  --te-header-edge:    var(--te-border-mid);

  /* ---- 3. Semantic: lines. -strong meets the 3:1 that WCAG 1.4.11
           requires of form-control boundaries; the others are decorative. ---- */
  --te-border:        var(--te-bone);
  --te-border-mid:    var(--te-taupe);
  --te-border-strong: var(--te-slate);

  /* ---- 3. Semantic: interaction ---- */
  /* Links are text on white, where the palette blues are unusable (--te-blue is
     2.2:1), so this is the one place a derived value is still required. */
  --te-link:          var(--te-blue-deep);
  --te-link-hover:    var(--te-navy);

  /* Filled buttons are a different contrast problem: a button's text is measured
     against the button's own fill, not against the page.
     REPOINTED 2026-08-25 (styling pass): the fill moves from the pale palette blue
     to the derived deep blue — white text on --te-blue-deep measures 6.1:1 (AA),
     and the button finally reads as the page's primary act rather than a tinted
     rectangle. Hover stays the navy inversion; the pale blue remains available in
     the palette layer for anyone repointing back. */
  --te-action:            var(--te-blue-deep);
  --te-action-text:       var(--te-white);
  --te-action-hover:      var(--te-navy);
  --te-action-hover-text: var(--te-white);
  --te-action-off:        var(--te-bone);   /* disabled fill */
  --te-focus:         var(--te-navy);   /* 15.9:1 on white, 12.1:1 on cream */

  /* ---- 3. Semantic: status ---- */
  --te-danger:        var(--te-crimson);
  --te-danger-fill:   #f8eeee;  /* pale crimson tint; crimson text on it reads 7.9:1 */
  --te-success:       var(--te-teal-deep);
  --te-success-fill:  var(--te-teal-tint);
  --te-caution:       var(--te-brown);
  --te-caution-fill:  var(--te-cream);
  --te-caution-edge:  var(--te-gold);

  /* ---- 3. Semantic: design-language tokens (docs/DESIGN_LANGUAGE.md §2) ----
     The names the component layer below is written against. Aliases into the
     layers above, so a re-brand is a repoint here and never a restyle.
       primary  = AWAY  (the button takes you to another page)
       accent   = ACT   (submits / reloads this page); its soft tint is the wash
                        that makes dense rows and the summary box readable
       danger   = destructive, regardless of mechanics                         */
  --te-primary:        var(--te-blue-deep);
  --te-primary-hover:  var(--te-navy);
  --te-on-primary:     var(--te-white);
  --te-accent:         var(--te-teal-deep);
  --te-accent-hover:   var(--te-teal-deeper);
  --te-accent-soft:    var(--te-teal-tint);
  --te-on-accent:      var(--te-white);
  --te-danger-soft:    var(--te-danger-fill);
  /* Brand accent: DECORATION ONLY (design language 11) - the short bar under a heading. Never a
     button fill, never a state; crimson as a fill means danger, and that is --te-danger's job. */
  --te-brand-accent:   var(--te-crimson);
  --te-card:           var(--te-white);
  --te-line:           var(--te-border-mid);
  --te-ink:            var(--te-text);
  --te-ink-muted:      var(--te-text-muted);

  /* ---- 3. Semantic: research map data colours (research map plan decision 12) ----
     Data, not brand: a dot's colour is Joshua Project's Bible translation status, grouped in
     three. Only research-map.css and research-map.js read these. Checked 2026-10-06 by
     simulated colour-vision deficiency (CIELAB difference; about 20 separates reliably):
     none/scripture protan 27, deutan 49, tritan 121; none/portions 63/37/58; portions/scripture
     72/79/73. The prototype's green (#2e9e4f) was replaced because it fell to 11.6 against
     red under deuteranopia. Each dot also carries a dark edge, which is what clears WCAG
     1.4.11's 3:1 against the land and sea; gold alone does not. */
  --te-map-status-none:      #d7263d;          /* 0–1: no Scripture yet */
  --te-map-status-portions:  var(--te-gold);   /* 2–3: started, or portions */
  --te-map-status-scripture: #0f8f8a;          /* 4–5: New Testament or whole Bible */
  --te-map-dot-edge:         rgb(0 0 0 / 45%);
  --te-map-sea:              #dfe9f0;
  --te-map-land:             #f4f1ee;
  --te-map-outline:          var(--te-taupe);
  --te-map-ring:             var(--te-navy);   /* the selected group, and the search circle's edge */
  /* Country shading for the barriers section (#324): data, drawn at 55% under the dots. Purple for
     USCIRF, kept off the status hues; a five-step brown ramp for terrain ruggedness by fifths. */
  --te-map-uscirf-cpc:       #5b2a86;          /* Country of Particular Concern */
  --te-map-uscirf-swl:       #b49bd3;          /* Special Watch List */
  --te-map-rugged-1:         #f3ece2;
  --te-map-rugged-2:         #dcc3a1;
  --te-map-rugged-3:         #c39a66;
  --te-map-rugged-4:         #9a6b3a;
  --te-map-rugged-5:         #6b4423;

  /* ---- 3. Semantic: leadership dashboard chart colours (leadership dashboard plan, card 12) ----
     Data colours, not brand, as the research map's are: a series is told apart by its hue, so these are the six series, the
     area under the cash line, the rise and fall of a month's change, and the chart's grid and axis lines, at the light-theme
     values of Jon May's template (the template's dark values are not carried: the suite has no dark theme). Only
     leadership-dashboard.css and leadership-dashboard.js read them. Surfaces, ink, lines and the font come from the --te-*
     tokens above. */
  --te-chart-1:     #2a78d6;
  --te-chart-2:     #eb6834;
  --te-chart-3:     #1baf7a;
  --te-chart-4:     #eda100;
  --te-chart-5:     #e87ba4;
  --te-chart-6:     #008300;
  --te-chart-area:  rgba(42,120,214,0.10);
  --te-chart-up:    #006300;
  --te-chart-down:  #d03b3b;
  --te-chart-grid:  #e1e0d9;
  --te-chart-axis:  #c3c2b7;

  /* Buttons are square (design language §1E); every other control keeps --te-radius. */
  --te-btn-radius: 0;
  --te-btn-border: 2px;
  --te-btn-size:   1.0625rem;  /* ~17px */
  --te-btn-weight: 700;

  /* ---- 3. Semantic: shape. 6px (2026-08-25): softer than the original 4 without
     drifting into the rounded-everything look; one token, so every control agrees. ---- */
  --te-radius: 6px;

  /* Native controls (checkboxes, radios, progress) tint to the brand instead of
     the OS default blue; the page declares itself light so scrollbars and
     form chrome never guess. */
  accent-color: var(--te-blue-deep);
  color-scheme: light;
}

* { box-sizing: border-box; }

/* Text-ish controls, styled on the element for the same reason buttons are: the
   authoring page's inline "new page" inputs shipped with browser-default chrome
   because they sit in a form no scoped rule covered — and forms keep being added.
   Checkboxes/radios/files keep their native look (plus the brand accent-color). */
input[type="text"],
input[type="search"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="url"],
input[type="date"],
input[type="tel"],
input:not([type]),
select,
textarea {
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  font: inherit;
  background: var(--te-surface);
  color: var(--te-text);
}

::placeholder { color: var(--te-text-muted); opacity: 1; }

/* Focused controls trade the ring for a brand border plus soft halo — quieter
   than the navy outline, which stays for everything that is not a text field. */
input[type="text"]:focus-visible,
input[type="search"]:focus-visible,
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="number"]:focus-visible,
input[type="url"]:focus-visible,
input[type="date"]:focus-visible,
input[type="tel"]:focus-visible,
input:not([type]):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  border-color: var(--te-blue-deep);
  box-shadow: 0 0 0 3px rgb(43 102 150 / 20%);
}

html {
  font-size: 16px;
  /* Phones in landscape inflate text unpredictably without this. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh; /* mobile: the real viewport, not the URL-bar-inclusive one */
  display: flex;
  flex-direction: column;
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  background: var(--te-surface);
  color: var(--te-text);
  line-height: 1.5;
}

img { max-width: 100%; height: auto; }

/* Motion is a courtesy, never load-bearing — everything works identically without it. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  a, button, input[type="submit"], .link-button {
    transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
  }
}

.container {
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0 1rem;
}

.site-header {
  background: var(--te-header);
  /* A light header against a light page needs an explicit edge. */
  border-bottom: 1px solid var(--te-header-edge);
  padding: 0.75rem 0;
}

/* Logo + product qualifier as one home link. The logo carries the org name, so
   the text alongside it is only the product ("Applications"); together with the
   image's alt they read as the accessible name the text brand used to give. */
.site-header .brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  color: var(--te-text);
  font-size: 1.25rem;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}

.site-header .brand .logo {
  height: 40px;
  width: auto;
  display: block;
}

.site-header .brand span {
  font-weight: 300;
  color: var(--te-text-muted);
}

/* The wordmark is black artwork, so it needs room to breathe rather than
   shrinking into the nav on narrow screens. */
@media (max-width: 560px) {
  .header-row { flex-wrap: wrap; gap: 0.5rem; }
  .site-header .brand { font-size: 1.0625rem; }
  .site-header .brand .logo { height: 32px; }
}

main {
  padding: 2rem 0;
  flex: 1;
}

.site-footer {
  margin-top: auto;
  border-top: 1px solid var(--te-border);
  padding: 1rem 0;
  color: var(--te-text-muted);
  font-size: 0.875rem;
}

/* Links carry colour at rest and take their underline on hover/focus — the
   modern convention (owner call, 2026-08-25). The non-colour cue WCAG 1.4.1
   wants for in-prose links is served by the hover/focus underline plus the
   6.1:1 link blue, which also sits clearly apart from the charcoal body text. */
a { color: var(--te-link); text-decoration: none; }
a:hover, a:focus-visible { color: var(--te-link-hover); text-decoration: underline; }

/* Filled buttons, styled on the element rather than per container.
   "Publish this plan" was already shipping with browser-default chrome because it
   sits in an .inline-form, which styles no buttons — and admin pages keep being
   added. Making the element default-correct means a new bare <button> cannot ship
   off-brand by forgetting the right wrapper.

   Kept as a bare element selector on purpose. An earlier attempt excluded the
   link-styled variants with :not(.link-button):not(...) etc, which raised this to
   four classes of specificity and silently outranked button:disabled — disabled
   buttons rendered fully enabled. A single-element selector lets every variant
   below win on its own class, and lets :disabled win on source order. Each variant
   therefore owns its :hover too. */
button,
input[type="submit"] {
  padding: 0.5625rem 1.125rem;
  /* A bare <button> submits the form it sits in, which reloads THIS page: that is
     the ACT consequence, so the element default is the accent fill (design
     language §1E). Links dressed as buttons that go elsewhere take .te-btn-away. */
  background: var(--te-accent);
  color: var(--te-on-accent);
  border: var(--te-btn-border) solid var(--te-accent);
  border-radius: var(--te-btn-radius);
  font: inherit;
  font-size: var(--te-btn-size);
  font-weight: var(--te-btn-weight);
  line-height: 1.25;
  cursor: pointer;
  /* Depth cues, kept quiet: a hairline shadow at rest, a touch more on hover,
     none while pressed — the 1px press shift is the tactile half. */
  box-shadow: 0 1px 2px rgb(28 37 46 / 10%);
}

button:hover,
input[type="submit"]:hover {
  background: var(--te-accent-hover);
  border-color: var(--te-accent-hover);
  color: var(--te-on-accent);
  box-shadow: 0 2px 6px rgb(28 37 46 / 16%);
}

button:active,
input[type="submit"]:active {
  box-shadow: none;
  transform: translateY(1px);
}

/* After :hover deliberately — equal specificity, so source order decides.
   Custom-styled controls get no native dimming, and the authoring UI disables
   "Publish this plan" until the plan validates. */
button:disabled,
button:disabled:hover {
  background: var(--te-action-off);
  border-color: var(--te-border-mid);
  color: var(--te-text-muted);
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

/* Outline variant: navy outline on white, so a pair of them reads as one control
   group rather than a button next to a link. Self-sufficient (padding, radius,
   weight) rather than leaning on the button element rule, because EditSection's
   Cancel is an <a class="secondary-button"> — an anchor gets none of the element
   chrome, and rendered as a bordered text link until this carried its own. */
.secondary-button {
  display: inline-block;
  padding: 0.5625rem 1.125rem;
  background: var(--te-surface);
  color: var(--te-navy);
  border: var(--te-btn-border) solid var(--te-navy);
  border-radius: var(--te-btn-radius);
  font: inherit;
  font-size: var(--te-btn-size);
  font-weight: var(--te-btn-weight);
  line-height: 1.25;
  text-decoration: none;
  cursor: pointer;
}
.secondary-button:hover {
  background: var(--te-accent-soft);
  border-color: var(--te-navy);
  color: var(--te-navy);
  text-decoration: none;
}

/* Link-shaped actions that sit in an action row beside a real button (Reset next
   to Filter, and anywhere .ghost-button is asked for) read as quiet buttons, not
   underlined prose. Genuine in-text links keep their underlines — that stays the
   rule for prose, this is only for control rows. */
.filter-bar > a,
.ghost-button {
  display: inline-block;
  padding: 0.375rem 0.875rem;
  border: var(--te-btn-border) solid var(--te-navy);
  border-radius: var(--te-btn-radius);
  background: var(--te-surface);
  color: var(--te-navy);
  font-weight: var(--te-btn-weight);
  line-height: 1.25;
  text-decoration: none;
}
.filter-bar > a:hover,
.ghost-button:hover {
  background: var(--te-accent-soft);
  border-color: var(--te-navy);
  color: var(--te-navy);
  text-decoration: none;
}

/* Row-sized ghost: for action links living inside table rows, where full button
   padding would inflate every row. */
.ghost-button.small {
  padding: 0.1875rem 0.625rem;
  font-size: 0.875rem;
  white-space: nowrap;
}

/* Interactive controls below are restyled away from their native look, so
   pin an explicit focus ring rather than trusting the UA default to stay
   visible against brand surfaces. */
/* One ring everywhere now that the headers are light; the gold invert variant
   existed only for the dark navy/espresso headers. */
:focus-visible {
  outline: 2px solid var(--te-focus);
  outline-offset: 2px;
}

.header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem; /* the brand must never sit flush against the first nav item */
}

/* An empty name list hides its own parentheses — "0 praying now", not
   "0 praying now ()". :has() keeps the 5-second poll honest with zero JS. */
.names-wrap:has(> [data-names]:empty) { display: none; }

/* The admin nav carries ten items now, which no longer fit inside the 960px content
   container — so the HEADER's container gets the real window width while page content
   below stays at 960 for readability. One row on a desktop; the fallback below wraps
   whole items on narrower screens, and nothing ever breaks inside a link. */
.site-header .container { max-width: 1360px; }

.site-nav {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-size: 0.9375rem;
  /* The nav may shrink (min-width: 0 is what lets the address ellipsize inside a
     flex row) but the brand may not — without both, a mid-width window makes the
     links slide over the logo instead of the email giving way. */
  flex: 1 1 auto;
  min-width: 0;
  justify-content: flex-end;
}

.site-header .brand { flex-shrink: 0; }

.site-nav a,
.site-nav .link-button,
.site-nav .admin-who { white-space: nowrap; }

/* The signed-in address shows in full, always (owner call, 2026-08-25 - no
   truncation, no tooltip). Nothing in the row shrinks, so on windows too narrow
   for everything the nav wraps whole links instead - see the media query below. */
.site-nav .admin-who { flex: 0 0 auto; }

@media (max-width: 1300px) {
  .site-nav { flex-wrap: wrap; row-gap: 0.25rem; justify-content: flex-end; }
}

.site-nav a { color: var(--te-text); text-decoration: none; }
.site-nav a:hover { text-decoration: underline; color: var(--te-link); }

.inline-form { display: inline; }

.link-button {
  background: none;
  border: none;
  color: var(--te-text);
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.link-button:hover { text-decoration: underline; color: var(--te-link); }

/* Forms */
.stacked-form {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  max-width: 420px;
}

.stacked-form label { font-weight: 600; margin-top: 0.75rem; }

.stacked-form input,
.stacked-form select {
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  font: inherit;
}

/* Spacing only — fill, hover and disabled all come from the element rule above. */
.stacked-form button[type="submit"] { margin-top: 1.25rem; }

.code-input {
  font-size: 1.5rem;
  letter-spacing: 0.5rem;
  max-width: 12rem;
  text-align: center;
}

.field-error, .validation-summary { color: var(--te-danger); font-size: 0.875rem; }
/* "(required)" after a section field's label (TagHelpers/SectionLabelTagHelper): said before the
   save, quieter than the question. */
.field-required { font-weight: 400; color: var(--te-text-muted); }

/* Belt and braces for the CSP. asp-validation-summary="All" emits a placeholder
   <li style="display:none"> for jQuery to clone, and `style-src 'self'` blocks the attribute —
   so the empty list renders. Every summary here is ModelOnly, which emits nothing when clean,
   but this keeps a future "All" from silently costing a blank bulleted line. A nonce cannot fix
   that case: CSP nonces do not apply to style attributes. */
.validation-summary-valid { display: none; }

/* Error.cshtml carries Bootstrap's .text-danger, but no framework is loaded
   here — without this the error headings render as plain body text. */
.text-danger { color: var(--te-danger); }

/* Honeypot: visually removed but still submittable by naive bots. */
.hp-field {
  position: absolute;
  left: -9999px;
  height: 1px;
  overflow: hidden;
}

.stacked-form.wide { max-width: 640px; }

.stacked-form textarea {
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  font: inherit;
}

.stacked-form h2 { margin: 1.5rem 0 0; font-size: 1.125rem; }

.check-row {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  margin-top: 0.75rem;
}
.check-row label { margin-top: 0; font-weight: 400; }
.check-row input { width: auto; }

.section-buttons { display: flex; gap: 0.75rem; margin-top: 1.25rem; }
/* Spacing only; the outline colours live on .secondary-button itself. */
.section-buttons .secondary-button { margin-top: 1.25rem; }

.section-list { padding-left: 1.25rem; max-width: 640px; }
.section-list li { margin-bottom: 1rem; }
.section-list li a { font-weight: 600; }
/* Standalone, not scoped to .section-list: the authoring page puts these pills
   inside <h2>s (program codes, page keys), where the scoped selector left them
   rendering as plain text run into the heading. Weight and size are pinned so
   a heading cannot inflate its own pill. */
.section-status {
  margin-left: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 400;
  vertical-align: middle;
  white-space: nowrap;
  color: var(--te-text-muted);
  border: 1px solid var(--te-border-mid);
  border-radius: 10px;
  padding: 0.0625rem 0.5rem;
}
.section-list li.done .section-status { color: var(--te-success); border-color: var(--te-success); }
.section-list li.started .section-status { color: var(--te-caution); border-color: var(--te-caution); }
.section-list .section-desc { margin: 0.25rem 0 0; color: var(--te-text-muted); font-size: 0.875rem; }

.question { margin-bottom: 1.25rem; display: flex; flex-direction: column; gap: 0.375rem; }
.question > label { font-weight: 600; }
.question.has-error > label { color: var(--te-danger); }

.submitted-banner {
  background: var(--te-success-fill);
  border: 1px solid var(--te-success);
  border-radius: var(--te-radius);
  padding: 0.75rem 1rem;
  color: var(--te-success);
  max-width: 640px;
}

.reveal-link {
  background: none;
  border: none;
  color: var(--te-link);
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: none;
}

/* Deliberately loud: the values inside are visible for this one response only.
   The gold edge carries the alarm; brown-on-cream carries the text at 5.9:1. */
.revealed-block {
  background: var(--te-caution-fill);
  border: 1px solid var(--te-caution);
  border-left: 4px solid var(--te-caution-edge);
  border-radius: var(--te-radius);
  padding: 0.75rem 1rem;
  margin-bottom: 0.75rem;
  color: var(--te-caution);
}

.revealed-block h3 { margin-top: 0; font-size: 0.95rem; }

/* Staff copy each value into the background-check vendor's form: label above value, the value on one
   line in a fixed-width face, and one click selects all of it. The side card's overflow-wrap:anywhere
   is what broke these digit by digit, so it is undone here. */
.revealed-fields { display: grid; gap: 0.625rem; margin: 0 0 0.75rem; }
.revealed-fields dt { font-size: 0.875rem; }
.revealed-fields dd { margin: 0; }
.revealed-value {
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-size: 1.125rem; font-weight: 700; letter-spacing: 0.03em;
  white-space: nowrap; overflow-wrap: normal; overflow-x: auto;
  user-select: all; -webkit-user-select: all;
}

/* A value and its Copy button share a row; on a narrow side column the button drops beneath. */
.revealed-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.revealed-value { display: inline-block; max-width: 100%; }
.revealed-copy { display: inline-flex; align-items: center; gap: 0.375rem; }
.revealed-copy svg { flex: none; }

.caution-banner {
  background: var(--te-caution-fill);
  border: 1px solid var(--te-caution);
  border-left: 4px solid var(--te-caution-edge);
  border-radius: var(--te-radius);
  padding: 0.75rem 1rem;
  color: var(--te-caution);
  max-width: 640px;
}

.review-section { max-width: 720px; margin-bottom: 1.5rem; }
.review-section h2 { font-size: 1.125rem; border-bottom: 1px solid var(--te-border); padding-bottom: 0.375rem; }
/* The per-section Edit on the applicant review page: a row-sized ghost beside its
   heading, so the action reads as a control rather than underlined heading text. */
.review-section .edit-link {
  display: inline-block;
  margin-left: 0.75rem;
  padding: 0.1875rem 0.625rem;
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  background: var(--te-surface);
  color: var(--te-text);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
  vertical-align: middle;
}
.review-section .edit-link:hover {
  background: var(--te-surface-sunken);
  border-color: var(--te-border-strong);
  color: var(--te-text);
  text-decoration: none;
}
.review-fields { display: grid; grid-template-columns: minmax(160px, 260px) 1fr; gap: 0.375rem 1rem; }
.review-fields dt { color: var(--te-text-muted); }
.review-fields dd { margin: 0; white-space: pre-wrap; }



.slot-list { max-width: 640px; }

.slot {
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  padding: 1rem;
  margin-bottom: 1rem;
}
.slot.has-error { border-color: var(--te-danger); }
.slot h2 { margin: 0; font-size: 1.0625rem; }
.slot .section-desc { margin: 0.25rem 0 0.75rem; }

.uploaded-file { margin: 0 0 0.75rem; }
.uploaded-file .section-desc { display: block; margin: 0.125rem 0 0; }

.upload-form { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
/* Size only; colour comes from the element rule. */
.upload-form button { padding: 0.375rem 0.875rem; }

/* Link-styled, so it must also reset :hover — the element rule's hover would
   otherwise turn it into a navy button. */
.danger-link {
  background: none;
  border: none;
  color: var(--te-danger);
  cursor: pointer;
  font: inherit;
  padding: 0;
  margin-top: 0.5rem;
  text-decoration: none;
}

/* Hover reset for every link-styled button. Their base rules declare no
   background, but `button:hover` is (0,1,1) and outranks a lone class at (0,1,0),
   so without this a "Sign out" or "Delete" link fills navy on hover. Two classes
   here take it back. Each keeps its own colour. */
.link-button,
.reveal-link,
.danger-link { box-shadow: none; }
.link-button:hover,
.reveal-link:hover,
.danger-link:hover {
  background: none;
  padding: 0;
  box-shadow: none;
}
.link-button:active,
.reveal-link:active,
.danger-link:active { transform: none; }
.reveal-link:hover { color: var(--te-link-hover); text-decoration: underline; }
.danger-link:hover { color: var(--te-danger); text-decoration: underline; }

/* Admin portal — Palette 2's cream keeps the internal portal distinct from the
   applicant-facing site while staying light enough for the logo to read. */
.admin-header { background: var(--te-header-admin); border-bottom-color: var(--te-brown); }
.admin-who { color: var(--te-text-muted); font-size: 0.875rem; }

.status-summary { display: flex; flex-wrap: wrap; gap: 1rem; font-size: 0.9375rem; }

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem 0.875rem; /* wrapped rows breathe; controls in a row sit close */
  align-items: center;
  margin: 1rem 0 1.25rem;
}

/* The search box leads the bar and absorbs spare row width, so the bar reads as
   one designed strip rather than controls dropped at their natural sizes. */
.filter-bar input[type="search"] {
  flex: 1 1 14rem;
  min-width: 12rem;
  max-width: 24rem;
}
/* Every text-ish input, not just search: the grant field on /Admin/Roles is type="email" and
   went unstyled beside its own select for want of being listed here. */
.filter-bar input[type="search"],
.filter-bar input[type="email"],
.filter-bar input[type="text"],
.filter-bar input[type="date"],
.filter-bar input[type="number"],
.filter-bar select {
  padding: 0.375rem 0.5rem;
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  font: inherit;
}
.filter-bar button { padding: 0.375rem 0.875rem; }
/* A count, such as how many runs the sync page shows: room for three digits and the spinner. */
.filter-bar input[type="number"] { width: 5.5rem; }

/* Wide enough for a full work address without scrolling it, and allowed to grow into spare
   space rather than sitting at a fixed size on a wide screen. */
.filter-bar .subject-picker { position: relative; flex: 1 1 24rem; min-width: 18rem; max-width: 32rem; }
.filter-bar .subject-picker .subject-input { width: 100%; box-sizing: border-box; }

/* The name picker's dropdown. Absolute so it overlays the page rather than shoving the role
   select and Grant button down as matches arrive. */
.subject-matches {
  position: absolute;
  z-index: 20;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 17rem;
  overflow-y: auto;
  background: var(--te-surface);
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  box-shadow: 0 4px 12px rgb(0 0 0 / 12%);
}
.subject-matches li {
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
  padding: 0.375rem 0.625rem;
  cursor: pointer;
}
.subject-matches li + li { border-top: 1px solid var(--te-border-mid); }
.subject-matches li.is-active { background: var(--te-surface-sunken); }
.subject-name { font-weight: 600; }
.subject-address { font-size: 0.875rem; color: var(--te-text-muted); word-break: break-all; }
.inline-check { display: flex; align-items: center; gap: 0.375rem; font-size: 0.9375rem; }

.detail-meta { color: var(--te-text-muted); }

.admin-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); gap: 2rem; }
@media (max-width: 800px) { .admin-grid { grid-template-columns: 1fr; } }

.admin-side .side-panel {
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  padding: 1rem;
  margin-bottom: 1rem;
}
.side-panel h2 { margin-top: 0; font-size: 1.0625rem; }
.side-panel .stacked-form { max-width: none; }

.note { border-top: 1px solid var(--te-border); padding-top: 0.5rem; margin-top: 0.75rem; }
.note-meta { color: var(--te-text-muted); font-size: 0.8125rem; margin: 0; display: block; }
.note-body { margin: 0.25rem 0 0; white-space: pre-wrap; }

.timeline { list-style: none; padding: 0; margin: 0; }
.timeline li { border-top: 1px solid var(--te-border); padding: 0.5rem 0; }
.timeline li:first-child { border-top: none; }

.agreement-text {
  white-space: pre-wrap;
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  padding: 1rem 1.25rem;
  max-width: 720px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--te-surface-sunken);
}

.app-table.wide { max-width: none; }
.app-table { border-collapse: collapse; width: 100%; max-width: 640px; }
.app-table th, .app-table td {
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--te-border);
}
.app-table th { color: var(--te-text-muted); font-weight: 600; }

/* ---- Help assistant (top of /Admin/Help) -----------------------------------
   Answers are model output shown as TEXT, never markup, so their line breaks come
   from white-space here rather than from anything the model writes. */
/* scroll-margin keeps the returned answer clear of the sticky top bar. */
.help-assistant { margin: 1.5rem 0 2rem; max-width: 48rem; scroll-margin-top: 5rem; }
.help-assistant textarea { display: block; width: 100%; box-sizing: border-box; }
.help-question-note { margin: 0.25rem 0 0.75rem; font-weight: 600; }
.help-conversation { margin: 0.75rem 0 1rem; }
.help-asked { margin: 0.75rem 0 0.25rem; }
.help-answer {
  white-space: pre-line;
  margin: 0 0 0.5rem;
  padding: 0.75rem 1rem;
  background: var(--te-accent-soft);
  border-radius: var(--te-radius);
}
.help-sources { margin: 0.25rem 0 0; }
/* Focus is moved to the answer (or the refusal) for screen readers; it is not a control, so no ring. */
.help-assistant [tabindex="-1"]:focus { outline: none; }

/* While a background ask is out (help-assistant.js): a panel where the answer will land, and a
   small indicator that stays in view while the reader explores the guides below. Both carry the
   hidden attribute until the script reveals them; the [hidden] rules keep display:flex from
   overriding it. The spinner only spins for readers who have not reduced motion — the words say
   "working" either way. */
.help-working {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin: 0.75rem 0 1rem;
  padding: 0.75rem 1rem;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  border-left: 4px solid var(--te-accent);
  border-radius: var(--te-radius);
}
.help-working p { margin: 0; }
.help-working p + p { margin-top: 0.25rem; }
.help-working-toast {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 20;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0;
  padding: 0.5rem 0.875rem;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  border-left: 4px solid var(--te-accent);
  border-radius: var(--te-radius);
  box-shadow: 0 2px 6px rgb(28 37 46 / 16%);
  font-size: 0.875rem;
  font-weight: 600;
}
.help-working[hidden], .help-working-toast[hidden] { display: none; }
.help-spinner {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  box-sizing: border-box;
  border: 3px solid var(--te-accent-soft);
  border-top-color: var(--te-accent);
  border-radius: 50%;
}
@media (prefers-reduced-motion: no-preference) {
  .help-spinner { animation: help-spin 0.9s linear infinite; }
}
@keyframes help-spin { to { transform: rotate(360deg); } }

/* ---- Admin help page ------------------------------------------------------
   A contents column beside the article, collapsing to a single column on narrow
   screens. Sections are shown and hidden by help.js via the hidden attribute. */
.help-layout {
  display: grid;
  grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
}

.help-contents {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1rem;
  border: 1px solid var(--te-border);
  border-radius: var(--te-radius);
  background: var(--te-surface-sunken);
}

.help-contents label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.help-contents input[type="search"] { width: 100%; }

#help-toc {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

#help-toc li { margin: 0.15rem 0; }
#help-toc li[hidden] { display: none; }
.help-toc-level-3 { padding-left: 1rem; font-size: 0.9em; }

.help-body { max-width: 46rem; }
.help-body h2 { margin-top: 2rem; }
.help-body h3 { margin-top: 1.25rem; }
.help-body [hidden] { display: none; }

.help-body table {
  border-collapse: collapse;
  width: 100%;
  margin: 0.75rem 0;
}

.help-body th,
.help-body td {
  text-align: left;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--te-border);
}

.help-body th { color: var(--te-text-muted); font-weight: 600; }

.help-body blockquote {
  margin: 1rem 0;
  padding: 0.5rem 1rem;
  border-left: 3px solid var(--te-border-mid);
  color: var(--te-text-muted);
}

.help-body code {
  background: var(--te-surface-sunken);
  padding: 0.1rem 0.3rem;
  border-radius: 3px;
}

@media (max-width: 800px) {
  .help-layout { grid-template-columns: 1fr; }
  .help-contents { position: static; max-height: none; }
}

/* Non-production banner. Loud on purpose: its whole job is to be impossible to miss before
   someone types a real person's details into a copy of the site. Crimson on gold uses the
   existing palette rather than inventing a colour, and sticky keeps it visible on long
   authoring pages where the header has scrolled away. */
.env-banner {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--te-gold);
  color: var(--te-crimson);
  border-bottom: 3px solid var(--te-crimson);
  padding: 0.5rem 1rem;
  text-align: center;
  font-weight: 700;
  letter-spacing: 0.02em;
}

@media print {
  /* A printed application packet is a record; the banner is screen furniture. */
  .env-banner { display: none; }
}

/* Acting as another role. Distinct from the environment banner on purpose: they can appear
   together, and "wrong environment" and "reduced permissions" are different mistakes. */
.acting-banner {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  background: var(--te-navy);
  color: var(--te-white);
  border-bottom: 3px solid var(--te-blue);
  padding: 0.5rem 1rem;
  text-align: center;
}

.acting-banner form { margin: 0; }

@media print {
  .acting-banner { display: none; }
}

/* ---- Shared vocabulary --------------------------------------------------
   The classes the newer pages (prayer room, moderation, help hub, Pathways
   forms) are written in. They were used on 300+ elements before any of them
   had a rule here, so those pages rendered browser defaults beside the styled
   applicant funnel. Styled in the same language as everything above: palette
   tokens only, one radius, borders from the line scale. */

/* Screen-reader-only. An accessibility utility, not a convenience: without it
   the "sr-only" labels on the cards page rendered visibly. */
/* Also answers to Bootstrap's name, visually-hidden, which Finance and Funds pages use; the site
   does not load Bootstrap, so without this the class did nothing and the text showed. */
.sr-only,
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.lede {
  color: var(--te-text-muted);
  font-size: 1.0625rem;
  max-width: 46rem;
  margin-top: 0.25rem;
}

.muted { color: var(--te-text-muted); font-size: 0.9375rem; }

.error { color: var(--te-danger); }
.success { color: var(--te-success); }

/* One stacked field: label above control, generous rhythm. .field and
   .form-field are the same idea written by different pages; they stay
   synonyms here rather than forcing a rename across 84 usages. */
.form-field,
.field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  margin: 0 0 1.25rem;
  max-width: 640px;
}
.form-field label,
.field label { font-weight: 600; }
.form-field input,
.form-field select,
.form-field textarea,
.field input,
.field select,
.field textarea {
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--te-border-strong);
  border-radius: var(--te-radius);
  font: inherit;
  background: var(--te-surface);
}

/* Checkbox/radio groups (e.g. MultiSelect questions): a bare fieldset, one
   choice per line, the control beside its label rather than stacked. */
.choices {
  border: 0;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.choices label {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-weight: 400;
}
.choices input { width: auto; }

/* The general-purpose data table; same voice as .app-table, full width. */
.data {
  border-collapse: collapse;
  width: 100%;
  margin: 0.75rem 0;
}
.data th,
.data td {
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--te-border);
  vertical-align: top;
}
.data th { color: var(--te-text-muted); font-weight: 600; }
/* A date and time, a count or a short label that should not break over two lines (#386). */
.data td.nowrap { white-space: nowrap; }
.data caption {
  text-align: left;
  color: var(--te-text-muted);
  font-size: 0.875rem;
  padding-bottom: 0.375rem;
}

/* Flash notices: neutral by default; error and success repaint via the
   status tokens. Same shape as the banners above. */
.flash {
  background: var(--te-surface-sunken);
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  padding: 0.75rem 1rem;
  margin: 0.75rem 0;
  max-width: 640px;
}
.flash.error {
  background: var(--te-danger-fill);
  border-color: var(--te-danger);
  color: var(--te-danger);
}
.flash.success {
  background: var(--te-success-fill);
  border-color: var(--te-success);
  color: var(--te-success);
}

/* Content panel: the generic sibling of .side-panel. A .danger panel carries
   the caution shape but in crimson, for the room-block section. */
.panel {
  border: 1px solid var(--te-border-mid);
  border-radius: var(--te-radius);
  padding: 1rem 1.25rem;
  margin: 0 0 1.25rem;
}
.panel > h2:first-child { margin-top: 0; font-size: 1.0625rem; }
.panel.danger { border-left: 4px solid var(--te-danger); }

/* Destructive actions fill crimson so they can never be mistaken for the
   default action; hover deepens rather than inverting to navy. */
button.danger,
.panel.danger button.danger {
  background: var(--te-danger);
  border-color: var(--te-danger);
  color: var(--te-white);
}
button.danger:hover {
  background: var(--te-espresso);
  border-color: var(--te-espresso);
  color: var(--te-white);
}

/* The hub list (help guides, Pathways blocks): plain list, roomy rows. */
.hub {
  list-style: none;
  margin: 0.75rem 0;
  padding: 0;
  max-width: 46rem;
}
.hub li { padding: 0.625rem 0; border-top: 1px solid var(--te-border); }
.hub li:first-child { border-top: none; }
.hub li > a { font-weight: 600; }
.hub-note { margin: 0.25rem 0 0; color: var(--te-text-muted); font-size: 0.875rem; }

/* The roles page's per-assignment program scope: a small checkbox row under the revoke button. */
.scope-form { display: block; margin-top: 0.375rem; }
.scope-choices { border: none; margin: 0; padding: 0; }
.scope-choices legend { padding: 0; }
.scope-choice { display: inline-flex; align-items: center; gap: 0.25rem; margin-right: 0.75rem; font-size: 0.875rem; }

/* The /start program chooser: one card per active program — radio, name, blurb. */
.program-choices { border: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.program-choices legend { font-weight: 600; padding: 0; margin-bottom: 0.25rem; }
.program-choice {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.625rem;
  align-items: baseline;
  border: 1px solid var(--te-border);
  border-radius: 6px;
  padding: 0.75rem 0.875rem;
  cursor: pointer;
  margin: 0;
}
.program-choice:has(input:checked) { border-color: var(--te-teal); background: var(--te-teal-tint); }
.program-choice-name { font-weight: 600; }
.program-choice-desc { grid-column: 2; color: var(--te-text-muted); font-size: 0.875rem; }

/* Small status pill, same shape as .section-status. */
.tag {
  font-size: 0.8125rem;
  color: var(--te-text-muted);
  border: 1px solid var(--te-border-mid);
  border-radius: 10px;
  padding: 0.0625rem 0.5rem;
  white-space: nowrap;
}

/* Sensitive values: the mask is quiet, the revealed number is deliberately
   not — both tabular so digits align in lists. */
.mask { font-variant-numeric: tabular-nums; letter-spacing: 0.0625em; color: var(--te-text-muted); }
.revealed-number { font-variant-numeric: tabular-nums; letter-spacing: 0.0625em; font-weight: 600; }

/* ---- Quality of life ------------------------------------------------------
   Standard modern-web affordances, all framework-free and CSP-safe. */

/* Keyboard users' first tab lands on a way past the nav. Visible only while
   focused; parked far off-screen otherwise. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--te-navy);
  color: var(--te-white);
  padding: 0.5rem 1rem;
  border-radius: 0 0 var(--te-radius) var(--te-radius);
  text-decoration: none;
}
.skip-link:focus { left: 1rem; }

/* Scanning wide tables: the row under the pointer says so. */
.data tbody tr:hover,
.app-table tbody tr:hover { background: var(--te-surface-sunken); }

/* Long lists keep their column headers in view. */
.data thead th,
.app-table thead th {
  position: sticky;
  top: 0;
  background: var(--te-surface);
  z-index: 1;
}

/* Jumped-to headings (help contents, anchors) clear the sticky banner instead
   of landing underneath it. */
h2[id], h3[id], :target { scroll-margin-top: 5rem; }

/* Selected text in brand colours rather than OS default. */
::selection { background: var(--te-sky); color: var(--te-navy); }

/* Sub-navigation chips: sibling pages of one section, the current one filled.
   aria-current carries the active state, so the styling and the screen-reader
   announcement cannot disagree. Pill-round on purpose — visually distinct from
   the 6px ghost buttons, which are actions rather than places. */
.subnav { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1.5rem; }
.subnav a {
  display: inline-block;
  padding: 0.375rem 0.9375rem;
  border: 1px solid var(--te-border-mid);
  border-radius: 999px;
  color: var(--te-text);
  font-weight: 600;
  text-decoration: none;
}
.subnav a:hover {
  background: var(--te-surface-sunken);
  border-color: var(--te-border-strong);
  color: var(--te-text);
  text-decoration: none;
}
.subnav a[aria-current="page"] {
  background: var(--te-navy);
  border-color: var(--te-navy);
  color: var(--te-white);
}
.subnav a[aria-current="page"]:hover { text-decoration: none; }
/* A chip's count is muted ink on a light chip; on the selected (dark) chip it must be the chip's own light ink. */
.subnav a[aria-current="page"] .muted { color: inherit; }

/* Wayfinding back links: one consistent affordance instead of twenty ad-hoc
   arrows. Pill-shaped like the subnav (it points at a PLACE), quiet like meta
   text, and the arrow comes from CSS so call sites cannot each invent their own. */
.back-link {
  display: inline-block;
  padding: 0.25rem 0.8125rem 0.25rem 0.6875rem;
  border: 1px solid var(--te-border-mid);
  border-radius: 999px;
  color: var(--te-text-muted);
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
}
.back-link::before { content: "← "; }
.back-link:hover {
  background: var(--te-surface-sunken);
  border-color: var(--te-border-strong);
  color: var(--te-text);
  text-decoration: none;
}

/* Row-scale forms and buttons: an input and its button sit side by side inside a
   table cell, at row scale — full-size primary buttons in every row make the page
   shout, so row actions wear the quiet outline at small size and the page's one
   filled button stays the loudest thing on it. */
.row-form {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-wrap: nowrap;
}
.row-form.wrap {
  flex-wrap: wrap;
}
.row-form input:not([type="hidden"]) {
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
  min-width: 9rem;
  max-width: 15rem;
}
button.small,
.secondary-button.small,
.ghost-button.small {
  padding: 0.25rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  box-shadow: none;
}

/* The applicant funnel's next-step CTA ("Review & submit") is the most important
   click in the product; it dresses as the primary action rather than bold text. */
.review-cta {
  display: inline-block;
  padding: 0.5625rem 1.125rem;
  background: var(--te-primary);
  color: var(--te-on-primary);
  border: var(--te-btn-border) solid var(--te-primary);
  border-radius: var(--te-btn-radius);
  font-weight: var(--te-btn-weight);
  font-size: var(--te-btn-size);
  text-decoration: none;
  box-shadow: 0 1px 2px rgb(28 37 46 / 10%);
}
.review-cta:hover {
  background: var(--te-primary-hover);
  border-color: var(--te-primary-hover);
  color: var(--te-on-primary);
  text-decoration: none;
  box-shadow: 0 2px 6px rgb(28 37 46 / 16%);
}

/* Destructive row action: crimson-outlined ghost, so a Remove in every row reads
   as dangerous without shouting; the filled crimson stays for page-level acts.
   The background is stated explicitly because on a <button> the filled
   `button.danger` rule (0,1,1) outranks bare `.ghost-button` (0,1,0) for the
   fill while this pair (0,2,0) wins the text — which briefly shipped crimson
   words on a crimson block. Both properties owned here, no fight left. */
.ghost-button.danger {
  background: var(--te-surface);
  color: var(--te-danger);
  border-color: var(--te-danger);
}
.ghost-button.danger:hover {
  background: var(--te-danger-fill);
  border-color: var(--te-danger);
  color: var(--te-danger);
}

/* Page-level ghosts stand shoulder to shoulder with filled buttons, so they share
   the primary's padding; .small keeps row scale, and the filter bar's Reset keeps
   its own compact rule. */
.ghost-button:not(.small) { padding: 0.5625rem 1.125rem; line-height: 1.25; font-size: var(--te-btn-size); }

/* A toggle chip's selected state: filled navy, the same voice as the subnav's
   current page. Used by the plan editor's prerequisite pickers. */
.ghost-button.on,
.ghost-button.on:hover {
  background: var(--te-navy);
  border-color: var(--te-navy);
  color: var(--te-white);
}


/* =========================================================================
   Design-language components (docs/DESIGN_LANGUAGE.md)
   -------------------------------------------------------------------------
   Usable from a Razor page by class alone. Every colour below is a token from
   the semantic layer at the top of this file — no hex here, so a re-brand is a
   token change and never a restyle. The vocabulary:

     .te-summary        facts before buttons: the bordered box of figures a
                        page is about, most important figure first and bold
     .te-rows / .te-row dense clickable rows on a light wash; the row IS the link
     .te-chip           status: .ok / .info / .due / .off
     .te-section-label  a heading that is a label, never a button
     .te-card           the compact card, when a row will not do
     .te-btn-*          away / act / inpage / danger, plus the .te-btn-hero width
     .te-actions        actions stack one per line at snug width
     .te-save-pending   the Save that appears only once something changed
     .te-arm            two-step destructive action with no confirm() dialog
     .te-scroll         a table scrolls inside itself; the page never does
                        (.bounded holds its head in view, .tall lets it grow to 70vh,
                         .hold-first holds its first column)
   ========================================================================= */

/* ---- New-tab mark: a small arrow after a link that opens elsewhere ---------- */
.te-new-tab {
  color: var(--te-text-muted);
  font-size: 0.85em;
  margin-left: 0.25em;
}

/* ---- Summary box -------------------------------------------------------- */
.te-summary {
  background: var(--te-card);
  border: 2px solid var(--te-accent);
  border-left-width: 8px;
  padding: 0.875rem 1.125rem;
  margin: 0 0 1.25rem;
  max-width: 46rem;
}
.te-summary-lead {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.35;
}
.te-summary-lead strong,
.te-summary-lead .te-figure {
  font-size: 1.75rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--te-ink);
  margin-right: 0.125rem;
}
.te-summary-figures {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1.5rem;
  color: var(--te-ink-muted);
  font-size: 0.9375rem;
}
.te-summary-figures .te-figure {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--te-ink);
}
.te-summary-note {
  margin: 0.5rem 0 0;
  color: var(--te-ink-muted);
  font-size: 0.875rem;
}
.te-summary-figures a { color: inherit; }
.te-summary-figures a:hover { color: var(--te-link-hover); }

/* ---- Rows ---------------------------------------------------------------- */
.te-rows {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  max-width: 46rem;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.te-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  flex-wrap: wrap;
  padding: 0.625rem 0.875rem;
  background: var(--te-accent-soft);
  border: 1px solid color-mix(in srgb, var(--te-accent) 25%, transparent);
  color: var(--te-ink);
  text-decoration: none;
}
a.te-row:hover,
a.te-row:focus-visible {
  border-color: var(--te-accent);
  background: color-mix(in srgb, var(--te-accent) 16%, var(--te-card));
  color: var(--te-ink);
  text-decoration: none;
}
a.te-row:hover .te-row-title { text-decoration: underline; }
.te-row-main { display: flex; flex-direction: column; gap: 0.0625rem; min-width: 0; flex: 1 1 14rem; }
.te-row-title { font-weight: 600; }
.te-row-meta { color: var(--te-ink-muted); font-size: 0.875rem; }
.te-row-side {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}
/* A row that is a fact rather than a place (a donor, a line item): same wash, no hover. */
.te-row.static { cursor: default; }
/* One line on a phone: the label shrinks and wraps, the amount keeps its own column. */
.te-row.line { flex-wrap: nowrap; }
.te-row.line .te-row-main { flex: 1 1 0; }
/* A long pick-list (every group in the tenant) scrolls inside its card rather than
   stretching the page; the rows keep their wash. */
.te-rows.bounded { max-height: 24rem; overflow-y: auto; padding-right: 0.25rem; }

/* ---- Amex charges (the cardholder page, /Amex) -----------------------------
   One item per card, phone width first: nothing here has a fixed width, every
   control takes the card's width and long merchant text wraps. Tokens only. */
.amex-items {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  max-width: 46rem;
}
.amex-item {
  min-width: 0;
  padding: 0.75rem 0.875rem;
  background: var(--te-card);
  border: 1px solid var(--te-line);
}
.amex-item-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.125rem 0.75rem;
}
.amex-item-title { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.amex-item-amount { font-weight: 700; font-variant-numeric: tabular-nums; }
.amex-item p { margin: 0.25rem 0; }
.amex-item .form-field { max-width: none; margin: 0.625rem 0 0; }
.amex-item select,
.amex-item textarea,
.amex-item input[type="file"] { width: 100%; max-width: 100%; box-sizing: border-box; }
.amex-returned {
  margin: 0.5rem 0;
  padding: 0.5rem 0.75rem;
  background: var(--te-caution-fill);
  border-left: 4px solid var(--te-caution-edge);
  overflow-wrap: anywhere;
}
.amex-coding { margin: 0.5rem 0 0; }
.amex-coding dt { font-weight: 600; margin-top: 0.375rem; }
.amex-coding dd { margin: 0; overflow-wrap: anywhere; }

/* Finance's review (/Admin/Finance/Amex/Review): one table per cardholder inside .te-scroll, and each charge's history in a row of its own
   under it. No fixed widths: the table scrolls inside its card. */
.amex-review-group { margin: 0 0 1rem; }
.amex-review-actions form { margin: 0 0 0.375rem; }
.amex-review-actions .form-field { max-width: none; margin: 0.375rem 0; }
.amex-review-actions textarea { width: 100%; max-width: 100%; box-sizing: border-box; }
.amex-review-history td { padding-top: 0; }

/* ---- Chips ---------------------------------------------------------------- */
.te-chip {
  display: inline-block;
  padding: 0.0625rem 0.5625rem;
  border: 1px solid var(--te-line);
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  background: var(--te-card);
  color: var(--te-ink-muted);
}
.te-chip.ok   { color: var(--te-success); border-color: var(--te-success); background: var(--te-success-fill); }
.te-chip.info { color: var(--te-primary); border-color: var(--te-primary); background: color-mix(in srgb, var(--te-primary) 8%, var(--te-card)); }
.te-chip.due  { color: var(--te-caution); border-color: var(--te-caution-edge); background: var(--te-caution-fill); }
.te-chip.off  { color: var(--te-ink-muted); border-color: var(--te-line); background: var(--te-surface-sunken); }

/* ---- Section label -------------------------------------------------------- */
.te-section-label {
  display: block;
  margin: 1.75rem 0 0.625rem;
  padding: 0.25rem 0.625rem;
  background: color-mix(in srgb, var(--te-accent) 12%, transparent);
  border: 0;
  border-left: 3px solid var(--te-accent);
  color: var(--te-ink);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  max-width: 46rem;
}
.te-section-label:first-child { margin-top: 0.5rem; }
/* A <legend> is a label too: same look, sitting on the fieldset's top edge. */
fieldset > legend.te-section-label { margin: 0 0 0.5rem; padding-left: 0.625rem; }
fieldset.te-fieldset { border: 0; padding: 0; margin: 0 0 1rem; }

/* ---- Compact card --------------------------------------------------------- */
.te-card {
  background: var(--te-card);
  border: 1px solid var(--te-line);
  padding: 0.75rem 0.875rem;
  margin: 0 0 0.75rem;
  max-width: 46rem;
}
.te-card > h2:first-child,
.te-card > h3:first-child { margin: 0 0 0.375rem; font-size: 1rem; }
.te-card p { margin: 0.25rem 0; }

/* ---- Instructions: what the reader should do while they wait ---------------
   The accent wash with an accent edge, like the summary box, so a card that is
   waiting on us but asks something of the applicant reads as "do this", not as
   an error. pre-line keeps the coordinator's line breaks without letting
   markup through. */
.te-instructions {
  background: var(--te-accent-soft);
  border-left: 3px solid var(--te-accent);
  padding: 0.625rem 0.875rem;
  margin: 0.5rem 0 0.25rem;
  max-width: 46rem;
}
.te-instructions > strong { display: block; margin-bottom: 0.25rem; }
.te-instructions p { margin: 0.25rem 0; white-space: pre-line; }

/* Keeps the line breaks in a stored instruction. A style attribute cannot do this:
   the CSP is style-src 'self', so the browser blocks it. */
.te-pre-line { white-space: pre-line; }

/* A devotion passage set as scripture: larger than body text, quoted, reference muted beneath. */
.te-scripture {
  margin: 1rem 0 0.25rem;
  padding: 0.25rem 0 0.25rem 1rem;
  border-left: 3px solid var(--te-accent);
  font-size: 1.125rem;
  line-height: 1.6;
}
.te-scripture-ref { margin-top: 0; }

/* ---- Pipeline board ---------------------------------------------------------
   Columns side by side, scrolling inside their own strip (the page never scrolls
   sideways); each card is a link, drawn as a compact card on the accent wash. */
.te-board { display: flex; gap: 0.75rem; overflow-x: auto; padding-bottom: 0.75rem; align-items: flex-start; }
.te-board-col {
  flex: 0 0 15rem;
  background: var(--te-accent-soft);
  border-top: 3px solid var(--te-accent);
  padding: 0.5rem 0.625rem;
}
.te-board-col > h2 {
  font-size: 0.95rem;
  margin: 0 0 0.5rem;
  display: flex; justify-content: space-between; align-items: center; gap: 0.5rem;
}
.te-board-card {
  display: block;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  padding: 0.5rem 0.625rem;
  margin-bottom: 0.5rem;
  color: var(--te-ink);
  text-decoration: none;
}
.te-board-card:hover, .te-board-card:focus { border-color: var(--te-accent); text-decoration: none; }
.te-board-card small { display: block; color: var(--te-ink-muted); margin-top: 0.125rem; }
.te-board-empty { color: var(--te-ink-muted); font-size: 0.9rem; margin: 0.25rem 0; }

/* ---- Buttons: the consequence tells the colour --------------------------
   AWAY  primary fill    — you leave this page
   ACT   accent fill     — this page submits / reloads
   IN    outlined        — reveal / toggle, you go nowhere
   RED   danger fill     — destructive, however it is wired
   All: square, bold, 2px border. Written for <a> and <button> alike, and with
   two classes of specificity so the element rules above cannot win the fight. */
.te-btn-away, .te-btn-act, .te-btn-inpage, .te-btn-danger,
a.te-btn-away, a.te-btn-act, a.te-btn-inpage, a.te-btn-danger,
button.te-btn-away, button.te-btn-act, button.te-btn-inpage, button.te-btn-danger {
  display: inline-block;
  padding: 0.5625rem 1.125rem;
  border: var(--te-btn-border) solid transparent;
  border-radius: var(--te-btn-radius);
  font: inherit;
  font-size: var(--te-btn-size);
  font-weight: var(--te-btn-weight);
  line-height: 1.25;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  box-shadow: none;
}
a.te-btn-away, button.te-btn-away { background: var(--te-primary); border-color: var(--te-primary); color: var(--te-on-primary); }
a.te-btn-away:hover, button.te-btn-away:hover,
a.te-btn-away:focus-visible, button.te-btn-away:focus-visible { background: var(--te-primary-hover); border-color: var(--te-primary-hover); color: var(--te-on-primary); text-decoration: none; }

a.te-btn-act, button.te-btn-act { background: var(--te-accent); border-color: var(--te-accent); color: var(--te-on-accent); }
a.te-btn-act:hover, button.te-btn-act:hover,
a.te-btn-act:focus-visible, button.te-btn-act:focus-visible { background: var(--te-accent-hover); border-color: var(--te-accent-hover); color: var(--te-on-accent); text-decoration: none; }

a.te-btn-inpage, button.te-btn-inpage, summary.te-btn-inpage { background: var(--te-card); border-color: var(--te-navy); color: var(--te-navy); }
a.te-btn-inpage:hover, button.te-btn-inpage:hover, summary.te-btn-inpage:hover,
a.te-btn-inpage:focus-visible, button.te-btn-inpage:focus-visible { background: var(--te-accent-soft); border-color: var(--te-navy); color: var(--te-navy); text-decoration: none; }

a.te-btn-danger, button.te-btn-danger, summary.te-btn-danger { background: var(--te-danger); border-color: var(--te-danger); color: var(--te-white); }
a.te-btn-danger:hover, button.te-btn-danger:hover, summary.te-btn-danger:hover,
a.te-btn-danger:focus-visible, button.te-btn-danger:focus-visible { background: var(--te-espresso); border-color: var(--te-espresso); color: var(--te-white); text-decoration: none; }

/* Width says importance: at most one hero per page. */
.te-btn-hero,
a.te-btn-hero, button.te-btn-hero { display: block; width: 100%; max-width: 46rem; padding: 0.75rem 1.25rem; }

/* Actions stack one per line at their natural width — never a shared row of equal buttons. */
.te-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0.75rem 0 1rem;
}
.te-actions form { margin: 0; }
.te-actions .te-btn-hero { align-self: stretch; }

/* Disabled: any variant, same quiet fill. After the variants, so source order decides. */
button.te-btn-away:disabled, button.te-btn-act:disabled, button.te-btn-inpage:disabled, button.te-btn-danger:disabled,
button.te-btn-away:disabled:hover, button.te-btn-act:disabled:hover, button.te-btn-inpage:disabled:hover, button.te-btn-danger:disabled:hover {
  background: var(--te-action-off);
  border-color: var(--te-line);
  color: var(--te-ink-muted);
  cursor: not-allowed;
}

/* ---- Pending save --------------------------------------------------------
   Settings forms carry data-dirty-save; site.js adds .is-dirty when a field
   differs from its loaded value. The Save is hidden until then and dressed in
   a light translucent red rather than the primary — a page of settings must
   not become a wall of dark buttons. Without JavaScript the html element never
   gains .js, so the button simply shows. */
button.te-save-pending {
  background: color-mix(in srgb, var(--te-danger) 9%, var(--te-card));
  border: var(--te-btn-border) solid color-mix(in srgb, var(--te-danger) 55%, transparent);
  color: var(--te-danger);
}
button.te-save-pending:hover,
button.te-save-pending:focus-visible {
  background: color-mix(in srgb, var(--te-danger) 18%, var(--te-card));
  border-color: var(--te-danger);
  color: var(--te-danger);
}
html.js form[data-dirty-save]:not(.is-dirty) .te-save-pending { display: none; }

/* ---- Reveal ---------------------------------------------------------------
   <details class="te-reveal" open="@Model.ShowX"><summary class="te-btn-inpage">Do the unusual thing</summary>
     <div class="te-reveal-body">…the fields only that case needs…</div></details>
   An exception's fields behind an in-page button, so a form shows only what
   everyone fills in. The page opens it itself when it holds a value or an error,
   so nothing typed is ever hidden. Native, so it works without JS. */
.te-reveal { margin: 0.5rem 0; }
.te-reveal > summary { list-style: none; display: inline-block; cursor: pointer; user-select: none; }
.te-reveal > summary::-webkit-details-marker { display: none; }
.te-reveal[open] > summary { background: var(--te-accent-soft); }
.te-reveal-body {
  margin-top: 0.5rem;
  padding: 0.75rem 0.875rem;
  background: var(--te-accent-soft);
  border-left: 4px solid var(--te-accent);
}

/* ---- Availability blocks ---------------------------------------------------
   One fieldset per block of free time: a date, a start and an end, with its own
   error under it (Pages/Shared/_AvailabilityBlocks.cshtml). The fields sit side
   by side and stack at phone width. site.js adds and removes rows in place; without
   it the same two buttons post. The [hidden] rule is here because the button
   classes set a display that would otherwise beat the attribute. */
.te-block {
  border: 1px solid var(--te-line);
  background: var(--te-card);
  padding: 0.5rem 0.875rem 0.875rem;
  margin: 0 0 0.75rem;
  max-width: 46rem;
}
.te-block-fields { display: flex; flex-wrap: wrap; gap: 0.75rem 1rem; }
.te-block-fields .field { margin: 0; flex: 1 1 11rem; max-width: 14rem; }
.te-block-error { margin: 0.5rem 0 0; font-weight: 600; }
.te-block button.te-btn-act.small { margin-top: 0.75rem; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 600; }
.te-block [hidden] { display: none; }

/* ---- Copy buttons ----------------------------------------------------------
   A button with data-copy copies the element it names (site.js): the close check's
   verdict. It is drawn hidden and shown by the script. The [hidden] rule is here because
   the button classes set a display that would otherwise beat the attribute. */
button[data-copy][hidden] { display: none; }

/* The container is the positioned ancestor of the invisible default send button, so that
   button (sr-only is position: absolute) lands at the container's top-left instead of its
   static position, which inside the office's scroll area sat past a phone's right edge and
   widened the whole page. Nothing else in .te-blocks is positioned. */
.te-blocks { position: relative; }
.te-block-default-submit { top: 0; left: 0; }
@media (max-width: 560px) {
  .te-block-fields { flex-direction: column; }
  .te-block-fields .field { flex: none; max-width: none; }
}

/* ---- Arm / confirm --------------------------------------------------------
   <details class="te-arm"><summary class="te-btn-danger">Discard</summary>
     <div class="te-arm-body">…the real form and button…</div></details>
   The first click reveals; the second acts. Native, so it works without JS and
   never blocks the page the way confirm() does. */
.te-arm { display: inline-block; max-width: 46rem; }
.te-arm > summary {
  list-style: none;
  display: inline-block;
  padding: 0.5625rem 1.125rem;
  border-width: var(--te-btn-border);
  border-style: solid;
  border-radius: var(--te-btn-radius);
  font-size: var(--te-btn-size);
  font-weight: var(--te-btn-weight);
  line-height: 1.25;
  cursor: pointer;
  user-select: none;
}
.te-arm > summary::-webkit-details-marker { display: none; }
.te-arm > summary.small { padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 600; }
.te-arm[open] > summary { opacity: 0.55; }
.te-arm-body {
  margin-top: 0.5rem;
  padding: 0.75rem 0.875rem;
  background: var(--te-danger-soft);
  border: 1px solid var(--te-danger);
  border-left-width: 4px;
  color: var(--te-ink);
}
/* An arm's body often names an address, which is one unbreakable token; inside a table cell it
   would otherwise set the column's minimum width and push the table into its scroll container. */
.te-arm-body { overflow-wrap: anywhere; }
.te-arm-body p { margin: 0 0 0.625rem; }
.te-arm-body form { margin: 0; }

/* ---- Title row and grid table ----------------------------------------------
   A card's title row (a name that is an input, its consequence on the right) and a compact
   table of rows that are each a form. A form cannot wrap a <tr>, and an input tied to a form by
   the form attribute raises no input event on it, so the table is a grid: each row's form is
   display: contents and the inputs stay inside it. Four columns: name, amount, save, act.
     <div class="te-title-row"><form class="te-title-form">…</form><div class="te-title-side">…</div></div>
     <div class="te-grid"><div class="te-grid-head">…</div><form class="te-grid-row">
       <input class="te-grid-label"><input class="te-grid-amount"><button class="te-grid-save">
       </form> … <div class="te-grid-foot">…</div></div> */
.te-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  max-width: 46rem;
}
.te-title-form { display: flex; align-items: center; gap: 0.5rem; flex: 1 1 16rem; margin: 0; min-width: 0; }
.te-title-form input { flex: 1 1 auto; min-width: 0; font-weight: 600; }
.te-title-side { display: flex; align-items: center; gap: 0.5rem; flex: 0 0 auto; }
.te-title-row .te-arm[open] { flex: 1 1 100%; }
.te-title-side:has(.te-arm[open]) { flex: 1 1 100%; }

.te-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 8rem 4.5rem 5.5rem;
  gap: 0.375rem 0.5rem;
  align-items: center;
  max-width: 46rem;
  margin: 0.75rem 0;
}
.te-grid-head,
.te-grid-foot,
.te-grid-row { display: contents; }
.te-grid .te-grid-label { grid-column: 1; min-width: 0; width: 100%; box-sizing: border-box; }
.te-grid .te-grid-amount { grid-column: 2; min-width: 0; width: 100%; box-sizing: border-box; text-align: right; font-variant-numeric: tabular-nums; }
.te-grid .te-grid-save { grid-column: 3; }
.te-grid .te-grid-remove { grid-column: 4; }
.te-grid-head .te-grid-label,
.te-grid-head .te-grid-amount { color: var(--te-ink-muted); font-size: 0.875rem; font-weight: 600; }
.te-grid-foot .te-grid-label,
.te-grid-foot .te-grid-amount { border-top: 1px solid var(--te-line); padding-top: 0.5rem; }
.te-grid-note { grid-column: 1 / -1; margin: 0; }
@media (max-width: 40rem) {
  .te-grid { grid-template-columns: minmax(0, 1fr) 6.5rem; }
  .te-grid .te-grid-save { grid-column: 1; justify-self: start; }
  .te-grid .te-grid-remove { grid-column: 2; justify-self: end; }
}

/* The Goals page's grid: one more row shape on the same classes. Intern, field, own goal, the goal
   that applies and where it came from, save, and a link that sits outside the row's form. */
.te-grid.te-grid-interns {
  grid-template-columns: minmax(7rem, 1fr) minmax(8rem, 12rem) 7rem minmax(9rem, 12rem) 4.5rem 5.5rem;
  max-width: 62rem;
}
.te-grid-interns .te-grid-label { grid-column: 1; }
.te-grid-interns .te-grid-field { grid-column: 2; min-width: 0; width: 100%; box-sizing: border-box; }
.te-grid-interns .te-grid-amount { grid-column: 3; }
.te-grid-interns .te-grid-source { grid-column: 4; }
.te-grid-interns .te-grid-save { grid-column: 5; }
.te-grid-interns .te-grid-end { grid-column: 6; }
.te-grid-head .te-grid-field,
.te-grid-head .te-grid-source { color: var(--te-ink-muted); font-size: 0.875rem; font-weight: 600; }
@media (max-width: 40rem) {
  .te-grid.te-grid-interns { grid-template-columns: minmax(0, 1fr) 6.5rem; }
  .te-grid-interns .te-grid-head { display: none; }
  .te-grid-interns .te-grid-label { grid-column: 1 / -1; font-weight: 600; }
  .te-grid-interns .te-grid-field { grid-column: 1; }
  .te-grid-interns .te-grid-amount { grid-column: 2; }
  .te-grid-interns .te-grid-source { grid-column: 1; }
  .te-grid-interns .te-grid-save { grid-column: 1; justify-self: start; }
  .te-grid-interns .te-grid-end { grid-column: 2; justify-self: end; }
}

/* ---- Scrolling tables ------------------------------------------------------ */
.te-scroll { overflow-x: auto; max-width: 100%; margin: 0.75rem 0; }
.te-scroll > table { margin: 0; }
.te-scroll .app-table,
.te-scroll .data { min-width: 36rem; }
/* A long table (every Employee ID) scrolls inside its card as well as sideways, head held in view. */
.te-scroll.bounded { max-height: 28rem; overflow-y: auto; }
.te-scroll.bounded thead th { position: sticky; top: 0; background: var(--te-card); }
/* A wide table (a donor's giving by month, 36 columns) holds its first column in view as the rest
   scrolls sideways, so a row still says whose it is. The card's ground hides what scrolls beneath. */
.te-scroll.hold-first > table > * > tr > :first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--te-card);
  box-shadow: inset -1px 0 0 var(--te-border);
}
/* Held both ways (a long, wide grid): the corner cell sits above the column and the head row alike. */
.te-scroll.bounded.hold-first > table > thead > tr > :first-child { z-index: 2; }
/* A table read at length (every donor of a fund) may use most of the screen before it scrolls. */
.te-scroll.bounded.tall { max-height: 70vh; }

/* ---- Prayer cards (rule O, docs/DESIGN_LANGUAGE.md §10, 2026-10-20) ---------
   The prayer room's cards are the product's own metaphor, so they are drawn as
   cards: bordered, rounded, lightly raised, with a head (initials avatar and
   name), a band that says whose words the card holds and how fresh they are, a
   body, and a footer with who is praying and the Pray button. Rule B (rows)
   still governs every list, including the admin card list; this is the one
   exception, and it is a grid of these and nothing else.

     .prayer-grid            auto-fill columns; one column at phone width
     .prayer-card            the card; .is-here marks the one you are praying at,
                             .is-together one with two or more praying
     .prayer-card-head       avatar + name (+ a Topic chip)
     .prayer-card-avatar     initials in a circle (PrayerInitials, never a photo)
     .prayer-card-band       .own / .newsletter / .empty, a token wash each
     .prayer-card-body       counts and the way in
     .prayer-card-foot       presence, the week's count, the actions
     .prayer-progress-bar    today's coverage, a native <progress> in the header card
     .prayer-celebrate       the "every card covered" band; its animation is off
                             under prefers-reduced-motion
     .prayer-streak          the room's streak and this week, in the header card
     .prayer-mine            "Your praying", the person's own figures on My card
                             (PC-3.7): figure strip, milestone chips, one privacy line
     .prayer-nudges          up to three "be the first" Join rows in the header card
     .prayer-tools           the name filter and order button, revealed by script
     .prayer-answered-*      the room's answered view (PC-2.6): banner, headline,
                             pager; its entries are .prayer-card in a .prayer-grid

   Tokens only, no hex. The room's face is content-free by decision (plan D7):
   nothing in these classes ever holds a request's words. */
.prayer-grid {
  display: grid;
  /* min() lets a column shrink below 16rem on a narrow phone rather than overflow it. */
  grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
  margin: 0 0 1.25rem;
}
.prayer-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: anywhere;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  border-radius: 10px;
  overflow: hidden; /* the band's wash meets the rounded corners cleanly */
  box-shadow: 0 1px 2px rgb(28 37 46 / 8%), 0 2px 8px rgb(28 37 46 / 6%);
}
.prayer-card.is-together { border-color: var(--te-accent); box-shadow: 0 0 0 1px var(--te-accent), 0 2px 8px rgb(28 37 46 / 10%); }
.prayer-card.is-here { border-color: var(--te-accent); box-shadow: 0 0 0 2px var(--te-accent), 0 2px 8px rgb(28 37 46 / 10%); }

.prayer-card-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem 0.75rem;
}
.prayer-card-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: var(--te-accent-soft);
  border: 2px solid var(--te-accent);
  color: var(--te-accent-hover);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}
.prayer-card-who { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; min-width: 0; }
.prayer-card-name { margin: 0; font-size: 1.0625rem; font-weight: 700; line-height: 1.25; }
.prayer-card-name a { color: var(--te-ink); text-decoration: none; }
.prayer-card-name a:hover,
.prayer-card-name a:focus-visible { color: var(--te-link-hover); text-decoration: underline; }

/* The band: whose words the card holds, and how fresh. Three washes, one per state, so a glance
   down the grid says which cards are in their own words, which are from a newsletter, and which
   are empty and still want prayer. */
.prayer-card-band {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.125rem 0.625rem;
  padding: 0.4375rem 1rem;
  border-block: 1px solid var(--te-border);
  font-size: 0.8125rem;
}
.prayer-card-band-label { font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; font-size: 0.75rem; }
.prayer-card-band-meta { color: var(--te-ink-muted); }
.prayer-card-band.own {
  background: var(--te-accent-soft);
  border-color: color-mix(in srgb, var(--te-accent) 25%, transparent);
}
.prayer-card-band.own .prayer-card-band-label { color: var(--te-accent-hover); }
.prayer-card-band.newsletter {
  background: color-mix(in srgb, var(--te-primary) 8%, var(--te-card));
  border-color: color-mix(in srgb, var(--te-primary) 25%, transparent);
}
.prayer-card-band.newsletter .prayer-card-band-label { color: var(--te-primary); }
.prayer-card-band.empty { background: var(--te-surface-sunken); }
.prayer-card-band.empty .prayer-card-band-label { color: var(--te-ink-muted); }

.prayer-card-body { flex: 1 1 auto; padding: 0.75rem 1rem 0.5rem; }
.prayer-card-body p { margin: 0 0 0.375rem; }
.prayer-card-counts { color: var(--te-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.prayer-card-invite { color: var(--te-ink-muted); font-size: 0.9375rem; }
.prayer-card-open { font-size: 0.9375rem; font-weight: 600; }

.prayer-card-foot {
  padding: 0.625rem 1rem 0.875rem;
  border-top: 1px solid var(--te-border);
  background: var(--te-surface-sunken);
  font-size: 0.875rem;
}
.prayer-card-foot p { margin: 0 0 0.25rem; }
.prayer-card-presence { color: var(--te-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.prayer-card-stats { color: var(--te-ink-muted); font-variant-numeric: tabular-nums; }
.prayer-card-stats strong { color: var(--te-ink); }
.prayer-card-actions { margin-top: 0.5rem; }
.prayer-card-actions form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem 0.75rem; margin: 0; }
.prayer-card-actions > strong { display: block; margin-bottom: 0.375rem; color: var(--te-accent-hover); }
.prayer-card-actions label { display: inline-flex; align-items: center; gap: 0.375rem; font-weight: 400; }

/* The open card and the owner's card (PC-2.3) are this same card, larger: the part classes above, plus
   a list of requests inside the bands. .prayer-card-open keeps it a readable column rather than a grid cell,
   and .is-yours marks the owner's own page with the accent edge the card you are praying at wears. A request
   is plain text with its age or end date quietly beneath; the forms that belong to a request sit under it. */
.prayer-card.prayer-card-open { max-width: 46rem; margin: 0 0 1.25rem; }
.prayer-card-open .prayer-card-head { padding: 1.125rem 1.25rem 0.875rem; }
.prayer-card-open .prayer-card-avatar { width: 3.5rem; height: 3.5rem; font-size: 1.25rem; }
.prayer-card-open .prayer-card-name { font-size: 1.375rem; }
.prayer-card-open .prayer-card-band { padding: 0.5rem 1.25rem; }
.prayer-card-open .prayer-card-body { padding: 0.5rem 1.25rem 0.75rem; }
.prayer-card-open .prayer-card-foot { padding: 0.75rem 1.25rem 1rem; }
.prayer-card.is-yours { border-color: var(--te-accent); }
.prayer-card-band.answered {
  background: var(--te-success-fill);
  border-color: color-mix(in srgb, var(--te-success) 25%, transparent);
}
.prayer-card-band.answered .prayer-card-band-label { color: var(--te-success); }

/* The request history (PC-2.5): an answered row reads as good news, a cleared row as quiet, honest absence. */
.prayer-card-request.is-answered {
  background: var(--te-success-fill);
  border-left: 3px solid var(--te-success);
  padding-left: 0.75rem;
  border-radius: 6px;
}
/* The Answered view's band is the glad one: the warm cream-and-gold wash the cautions use, turned to good news,
   with a gold edge and deep-brown text so it still reads at contrast. */
.prayer-card-band.answered.celebrate {
  background: var(--te-caution-fill);
  border-top: 3px solid var(--te-caution-edge);
  border-bottom: 1px solid var(--te-caution-edge);
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}
.prayer-card-band.answered.celebrate .prayer-card-band-label { color: var(--te-caution); font-size: 0.9375rem; }
.prayer-history-glad { color: var(--te-success); font-weight: 600; }
.prayer-history-purged { color: var(--te-ink-muted); font-style: italic; }

/* The room's answered view (PC-2.6): the same glad band as the history's, standing alone as the page's header, then a
   grid of small cards, each an answered prayer as a headline. Tokens only; nothing here holds a request's words. */
.prayer-answered-banner {
  max-width: 46rem;
  margin: 0 0 0.75rem;
  border-radius: 10px;
  border-inline: 1px solid var(--te-caution-edge);
}
.prayer-answered-headline { font-size: 1.0625rem; font-weight: 600; line-height: 1.45; }
.prayer-answered-entry .prayer-card-body { padding-bottom: 0.875rem; }
.prayer-answered-pager { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin: 0 0 1.25rem; }
.prayer-room-links { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem 0.75rem; }
/* On a phone the room's title takes its own line and the two links sit under it, side by side or wrapped, rather
   than squeezing the title beside them. Desktop is untouched; no other card head is affected. */
@media (max-width: 560px) {
  .portal-card-head:has(> .prayer-room-links) { flex-direction: column; align-items: stretch; gap: 0.5rem; }
  .prayer-room-links { justify-content: flex-start; }
}
.prayer-card-open .subnav { margin-bottom: 0.25rem; }

.prayer-card-requests { list-style: none; margin: 0; padding: 0; }
.prayer-card-request { padding: 0.75rem 0; border-top: 1px solid var(--te-border); }
.prayer-card-request:first-child { border-top: 0; }
.prayer-card-request p { margin: 0; }
.prayer-card-request-text { font-size: 1.0625rem; line-height: 1.5; white-space: pre-line; }
.prayer-card-request-meta { margin-top: 0.1875rem; color: var(--te-ink-muted); font-size: 0.8125rem; }
.prayer-card-request-note { margin-top: 0.375rem; font-size: 0.9375rem; font-style: italic; }
.prayer-card-request-flag { display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem 0.5rem; margin: 0.375rem 0 0; }
.prayer-card-request-flag input { flex: 1 1 12rem; min-width: 0; width: auto; font-size: 0.875rem; }
/* A request's actions are one quiet row of same-size small controls under it: the reveals and the arm are
   restyled here to the .ghost-button.small scale, and Retire keeps its consequence colour (the crimson
   outline of .ghost-button.danger) and its two-click arm. An opened reveal or arm takes the full row. */
.prayer-card-request-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.375rem 0.5rem; margin-top: 0.5rem; }
.prayer-card-request-actions .te-reveal,
.prayer-card-request-actions .te-arm { margin: 0; }
.prayer-card-request-actions .te-reveal[open],
.prayer-card-request-actions .te-arm[open] { flex: 1 1 100%; }
.prayer-card-request-actions .te-reveal > summary,
.prayer-card-request-actions .te-arm > summary {
  padding: 0.1875rem 0.625rem;
  border-width: var(--te-btn-border);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
}
.prayer-card-request-actions .te-reveal > summary:hover,
.prayer-card-request-actions .te-reveal > summary:focus-visible { background: var(--te-accent-soft); }
.prayer-card-request-actions .te-arm > summary.te-btn-danger {
  background: var(--te-surface);
  color: var(--te-danger);
  border-color: var(--te-danger);
}
.prayer-card-request-actions .te-arm > summary.te-btn-danger:hover,
.prayer-card-request-actions .te-arm > summary.te-btn-danger:focus-visible {
  background: var(--te-danger-fill);
  color: var(--te-danger);
  border-color: var(--te-danger);
}

/* Reporting is there when wanted and quiet until then: a small link-style summary opens the same one-line form. */
.prayer-card-flag { margin-top: 0.375rem; }
.prayer-card-flag > summary {
  display: inline-block;
  list-style: none;
  cursor: pointer;
  user-select: none;
  color: var(--te-ink-muted);
  font-size: 0.8125rem;
  text-decoration: underline;
}
.prayer-card-flag > summary::-webkit-details-marker { display: none; }
.prayer-card-flag > summary:hover,
.prayer-card-flag > summary:focus-visible { color: var(--te-link-hover); }
.prayer-card-add { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--te-border); }
.prayer-card-add-title { margin: 0 0 0.5rem; font-size: 1rem; }
.prayer-card-open textarea { max-width: 100%; }
.prayer-card-open .te-reveal-body,
.prayer-card-open .te-arm-body { max-width: 100%; }

/* Today's coverage sits in the header card: the figure strip, then a native <progress> (no style attribute
   needed, so the CSP is untouched) and a quiet note. The bar is accent-tinted by the global accent-color. */
.prayer-progress-bar { display: block; width: 100%; max-width: 32rem; height: 0.75rem; margin: 0.375rem 0 0.25rem; }
.prayer-progress-bar + .portal-figures-note { margin-bottom: 0; }
/* display:inline-block on a chip and flex on the band would otherwise beat the hidden attribute the poll sets. */
.te-chip[hidden], .prayer-celebrate[hidden] { display: none; }

/* "Every card has been prayed for today" (plan §7): the accent wash with an accent edge, like the
   summary box. The entrance is a courtesy: with reduced motion it simply appears. */
.prayer-celebrate {
  background: var(--te-accent-soft);
  border: 2px solid var(--te-accent);
  border-radius: 10px;
  padding: 0.75rem 1.125rem;
  margin: 0 0 1.25rem;
  font-weight: 600;
}
/* The streak line and "be the first" (plan §7, PC-3.3 / PC-3.4). Tokens only. The display values below would
   otherwise beat the hidden attribute the filter, the poll and the page itself rely on. */
.prayer-streak { margin-bottom: 0; }
/* Your praying: a quiet section under the card. The chips are te-chip.ok (token colours), laid in a row. */
.prayer-mine { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--te-line); }
.prayer-mine .portal-card-title { margin-top: 0; }
.prayer-mine-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0; padding: 0; list-style: none; }
.prayer-streak strong { color: var(--te-ink); }
.prayer-nudges { margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--te-border); }
.prayer-nudges-title { margin: 0 0 0.5rem; font-size: 1rem; }
.prayer-nudge-list { list-style: none; margin: 0; padding: 0; }
.prayer-nudge { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.375rem 1rem; padding: 0.375rem 0; }
.prayer-nudge-text { min-width: 0; overflow-wrap: anywhere; }
.prayer-tools { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem 1rem; margin: 0 0 0.75rem; }
.prayer-filter { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.875rem; color: var(--te-ink-muted); }
.prayer-filter input { width: 16rem; max-width: 100%; }
.prayer-tools button[aria-pressed="true"] { background: var(--te-accent-soft); border-color: var(--te-accent); }
.prayer-filter-empty { margin: 0 0 1rem; color: var(--te-ink-muted); }
.prayer-card[hidden], .prayer-nudge[hidden], .prayer-nudges[hidden], .prayer-tools[hidden], .prayer-filter-empty[hidden] { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .prayer-card { transition: box-shadow 150ms ease, border-color 150ms ease; }
  .prayer-card:hover { box-shadow: 0 2px 4px rgb(28 37 46 / 10%), 0 6px 16px rgb(28 37 46 / 10%); }
  .prayer-card.is-together:hover,
  .prayer-card.is-here:hover { box-shadow: 0 0 0 2px var(--te-accent), 0 6px 16px rgb(28 37 46 / 12%); }
  .prayer-celebrate { animation: prayer-celebrate-in 600ms ease-out both; }
  @keyframes prayer-celebrate-in {
    from { opacity: 0; transform: translateY(-0.375rem); }
    to   { opacity: 1; transform: none; }
  }
}

/* =========================================================================
   Internal portal shell (docs/DESIGN_LANGUAGE.md §6)
   -------------------------------------------------------------------------
   Desktop-first by decision (owner, 2026-09-07): a dark sidebar that is the
   navigation, a light ground, white cards laid out in a two-column grid, the
   way the coordinator's Bonfire dashboard reads. Built for the Pathways
   console first and lifted to every staff page the same day. Tokens only.
   Below ~900px the sidebar becomes a top strip so nothing breaks on a tablet,
   but the layout is tuned for a laptop screen and does not pretend otherwise.
   ========================================================================= */
.portal-body { background: var(--te-surface-sunken); }
.portal-shell {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  min-height: 100dvh;
}

/* ---- Sidebar ---- */
.portal-sidebar {
  background: var(--te-navy);
  color: var(--te-white);
  display: flex;
  flex-direction: column;
  padding: 1.25rem 0.875rem 1rem;
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--te-white) 25%, transparent) transparent;
}
/* The site-wide focus ring is navy, the sidebar's own background, so inside the sidebar it was
   invisible (1:1). Gold reads on navy (accessibility check, 2026-10-22). */
.portal-sidebar :focus-visible { outline-color: var(--te-gold); }
.portal-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  padding: 0.25rem 0.75rem 1.25rem;
  color: var(--te-white);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--te-white) 14%, transparent);
  margin-bottom: 0.75rem;
}
/* The wordmark is dark-on-transparent artwork; on navy it needs a light plate. */
.portal-brand .logo { height: 44px; width: auto; background: var(--te-white); padding: 0.25rem 0.5rem; }
.portal-brand span { font-size: 1.125rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.portal-brand:hover { text-decoration: none; color: var(--te-white); }

.portal-nav { display: flex; flex-direction: column; gap: 0.125rem; }
.portal-nav-label {
  margin: 0.875rem 0.75rem 0.25rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--te-white) 55%, transparent);
}
.portal-nav a {
  display: block;
  padding: 0.5rem 0.75rem;
  color: color-mix(in srgb, var(--te-white) 86%, transparent);
  font-weight: 600;
  font-size: 0.9375rem;
  text-decoration: none;
  border-left: 3px solid transparent;
}
.portal-nav a:hover { background: color-mix(in srgb, var(--te-white) 8%, transparent); color: var(--te-white); text-decoration: none; }
.portal-nav a[aria-current="page"] {
  background: color-mix(in srgb, var(--te-white) 14%, transparent);
  border-left-color: var(--te-teal);
  color: var(--te-white);
}
.portal-sub { display: flex; flex-direction: column; margin: 0.125rem 0 0.375rem; }
.portal-sub a {
  padding: 0.375rem 0.75rem 0.375rem 1.625rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: color-mix(in srgb, var(--te-white) 74%, transparent);
}
.portal-who { color: color-mix(in srgb, var(--te-white) 70%, transparent); font-size: 0.8125rem; word-break: break-all; }
.portal-sidebar-foot .link-button { color: color-mix(in srgb, var(--te-white) 70%, transparent); text-align: left; }
.portal-sidebar-foot .link-button:hover { color: var(--te-white); }
.portal-sidebar-foot {
  margin-top: auto;
  padding: 1rem 0.75rem 0;
  border-top: 1px solid color-mix(in srgb, var(--te-white) 14%, transparent);
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  font-size: 0.875rem;
}
.portal-sidebar-foot a { color: color-mix(in srgb, var(--te-white) 70%, transparent); }
.portal-sidebar-foot a:hover { color: var(--te-white); }

/* ---- Collapsing the sidebar (John, 2026-10-16) ----
   The arrow at the left of the top bar hides the menu and gives its width to the page;
   portal-nav.js sets the class from the saved choice before the body draws. It points left
   while the menu is open and right while it is hidden. */
.portal-nav-toggle { margin-right: auto; }
html.portal-nav-collapsed .portal-shell { grid-template-columns: minmax(0, 1fr); }
html.portal-nav-collapsed .portal-sidebar { display: none; }
html.portal-nav-collapsed .portal-nav-toggle svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: no-preference) {
  .portal-nav-toggle svg { transition: transform 150ms ease; }
}

/* ---- Main column ---- */
.portal-main { display: flex; flex-direction: column; min-width: 0; }
.portal-topbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  padding: 0.625rem 2rem;
  background: var(--te-card);
  border-bottom: 1px solid var(--te-border);
  font-size: 0.9375rem;
}
.portal-topbar a { color: var(--te-text); }
.portal-main > main { padding: 1.5rem 2rem 2rem; max-width: 1400px; width: 100%; flex: 1; }
/* A canvas page (ViewData["FullWidth"], the research map) uses the whole window, not the reading cap. */
.portal-main > main.portal-full-width { max-width: none; }
.portal-foot { padding: 0.75rem 2rem 1rem; color: var(--te-ink-muted); font-size: 0.8125rem; }

/* A non-dashboard page sits in one white card so it reads in the same voice. */
.portal-page-card { padding: 1.5rem 2rem 2rem; }
.portal-page-card > h1:first-child { margin-top: 0; }
/* Rule K (DESIGN_LANGUAGE.md §7, 2026-09-25): the page title inside the shell is the card-title
   scale, and its lead paragraph the card-note scale, so a single-card page and a dashboard read
   at one size. Two rules here rather than an edit to every worker page. */
.portal-page-card > h1 { font-size: 1.375rem; font-weight: 700; margin-bottom: 0.5rem; }
.portal-page-card > .lede { font-size: 0.9375rem; margin-top: 0; }
/* Section headings step down from the title, as h2.portal-card-title does inside a dashboard;
   left at their document size they would sit larger than the title above them. */
.portal-page-card h2 { font-size: 1.125rem; }

/* ---- Cards ---- */
.portal-card {
  background: var(--te-card);
  border: 1px solid var(--te-border);
  border-radius: 10px;
  padding: 1.25rem 1.5rem;
  margin: 0 0 1.25rem;
  box-shadow: 0 1px 2px rgb(28 37 46 / 4%);
}
.portal-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 0.75rem; }
.portal-card-title { margin: 0; font-size: 1.375rem; font-weight: 700; }
h2.portal-card-title { font-size: 1.125rem; }
.portal-card-action { font-weight: 600; white-space: nowrap; }
.portal-card-note { color: var(--te-ink-muted); font-size: 0.875rem; }
.portal-card-foot { display: flex; justify-content: flex-end; margin-top: 0.75rem; }

/* ---- Grid: main + side ---- */
.portal-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr);
  gap: 1.25rem;
  align-items: start;
}
.portal-col-main, .portal-col-side { min-width: 0; }
/* A dashboard whose main card is a table (the review queue) gives the table the room. */
.portal-grid.wide-main { grid-template-columns: minmax(0, 2.6fr) minmax(260px, 1fr); }

/* ---- Promo row ---- */
.portal-promo-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
  margin-bottom: 1.25rem;
}
.portal-promo {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto;
  gap: 0.875rem;
  align-items: start;
  background: var(--te-card);
  border: 1px solid var(--te-border);
  border-radius: 10px;
  padding: 1rem 1.125rem;
  color: var(--te-ink);
  text-decoration: none;
  box-shadow: 0 1px 2px rgb(28 37 46 / 4%);
}
.portal-promo:hover { border-color: var(--te-accent); color: var(--te-ink); text-decoration: none; }
.portal-promo:hover .portal-promo-title { text-decoration: underline; }
.portal-promo-text { display: flex; flex-direction: column; gap: 0.25rem; }
.portal-promo-title { font-weight: 700; font-size: 1.0625rem; }
.portal-promo-desc { color: var(--te-ink-muted); font-size: 0.875rem; line-height: 1.4; }
.portal-promo-arrow { color: var(--te-ink-muted); font-size: 1.125rem; }
/* Art plates: token-coloured blocks in place of product photography. */
.portal-promo-art { display: block; width: 64px; height: 64px; border-radius: 8px; }
.portal-art-people { background: color-mix(in srgb, var(--te-blue) 45%, var(--te-card)); }
.portal-art-book   { background: color-mix(in srgb, var(--te-gold) 45%, var(--te-card)); }
.portal-art-money  { background: color-mix(in srgb, var(--te-teal) 45%, var(--te-card)); }

/* Status chip links inside a dashboard card: the queue's per-status counts. */
.portal-status-links { margin: 0 0 1rem; }
.portal-status-links a { display: inline-flex; align-items: center; gap: 0.375rem; color: inherit; }
/* The view the list is showing (the event sign-ups list): underlined and bold, so it does not rest on colour alone. */
.portal-status-links a[aria-current="page"] { font-weight: 700; text-decoration: underline; text-underline-offset: 0.25rem; }

/* A unit or denominator beside a figure ("9 of 15", "412 KB"). */
.portal-figure-of { font-size: 0.9375rem; font-weight: 500; color: var(--te-ink-muted); }
/* Two canvases side by side inside one card (a program's plans and pages). */
.portal-two-up { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; align-items: start; }
.portal-two-up .te-section-label:first-child { margin-top: 0; }
/* A list row that stacks its title over a control, for narrow side cards. */
.portal-list-row-stacked { grid-template-columns: 1fr; gap: 0.375rem; }
@media (max-width: 1100px) { .portal-two-up { grid-template-columns: 1fr; } }

/* A summary box that lives inside a portal card: the card is the frame, the accent edge stays. */
.portal-card .te-summary-inline { border-width: 0 0 0 8px; padding: 0.25rem 0 0.25rem 1rem; margin: 0.5rem 0 1rem; max-width: none; }
.portal-card .te-rows { max-width: none; }
ol.te-rows { padding-left: 0; }

/* ---- Figures inside a card ---- */
.portal-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2.5rem;
  margin: 0.5rem 0 0.25rem;
}
.portal-figures div { display: flex; flex-direction: column-reverse; }
.portal-figures dt { color: var(--te-ink-muted); font-size: 0.9375rem; }
.portal-figures dd { margin: 0; font-size: 1.75rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.2; }
/* A headline figure is a link to the rows it counts (/Admin, 2026-11-05). */
.portal-figures dd a { color: inherit; text-decoration: underline; text-decoration-color: var(--te-line); text-underline-offset: 0.2em; }
.portal-figures dd a:hover, .portal-figures dd a:focus-visible { text-decoration-color: currentColor; }
/* Daily active staff (Admin/Activity, work item 452): a server-drawn line chart, no script. */
.activity-chart { display: block; width: 100%; height: auto; margin: 0.5rem 0 1.25rem; }
.activity-grid { stroke: var(--te-border); stroke-width: 1; }
.activity-axis { fill: var(--te-text-muted); font-size: 13px; }
.activity-area { fill: var(--te-blue); fill-opacity: 0.18; }
.activity-line { fill: none; stroke: var(--te-blue-deep); stroke-width: 2.5; stroke-linejoin: round; }
.activity-point { fill: var(--te-blue-deep); }
.activity-point.shown { fill: var(--te-gold); stroke: var(--te-blue-deep); stroke-width: 2; }
a:focus-visible .activity-point { stroke: var(--te-focus); stroke-width: 3; }
.activity-live { display: inline-block; width: 0.625rem; height: 0.625rem; border-radius: 50%; background: var(--te-teal-deep); }
.portal-figures-note { margin: 0.25rem 0 1rem; color: var(--te-ink-muted); font-size: 0.875rem; }

/* ---- List with status and a gear ---- */
.portal-list-head, .portal-list-row {
  display: grid;
  grid-template-columns: minmax(9rem, 1fr) 6rem minmax(0, auto);
  gap: 1rem;
  align-items: center;
}
.portal-list-head {
  padding: 0 0.25rem 0.375rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--te-ink-muted);
  border-bottom: 1px solid var(--te-border);
}
.portal-list { list-style: none; margin: 0; padding: 0; }
.portal-list-row { padding: 0.75rem 0.25rem; border-bottom: 1px solid var(--te-border); }
.portal-list-row:last-child { border-bottom: 0; }
.portal-list-main { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.portal-list-title { font-weight: 600; color: var(--te-ink); }
.portal-list-meta { color: var(--te-ink-muted); font-size: 0.875rem; }
.portal-list-actions { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 0.375rem; }
.portal-gear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  color: var(--te-ink-muted);
  font-size: 1.125rem;
  text-decoration: none;
}
/* One-line modifier: the hub's cohort row keeps its four row-scale buttons and the gear on a
   single line above the 900px breakpoint (where the list already stacks). Text stays .small. */
@media (min-width: 901px) {
  .portal-list-actions.one-line { flex-wrap: nowrap; gap: 0.25rem; white-space: nowrap; }
  .portal-list-actions.one-line .ghost-button.small { padding: 0.25rem 0.5rem; }
  .portal-list-actions.one-line .portal-gear { width: 1.75rem; height: 1.75rem; font-size: 1rem; flex: none; }
}
.portal-gear:hover { background: var(--te-surface-sunken); color: var(--te-ink); text-decoration: none; }

/* ---- Tool tiles ---- */
.portal-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.75rem;
}
.portal-tile {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.875rem 1rem;
  background: var(--te-accent-soft);
  border: 1px solid color-mix(in srgb, var(--te-accent) 25%, transparent);
  border-radius: 8px;
  color: var(--te-ink);
  text-decoration: none;
}
.portal-tile:hover { border-color: var(--te-accent); background: color-mix(in srgb, var(--te-accent) 16%, var(--te-card)); color: var(--te-ink); text-decoration: none; }
.portal-tile:hover .portal-tile-title { text-decoration: underline; }
.portal-tile-title { font-weight: 700; }
.portal-tile-desc { color: var(--te-ink-muted); font-size: 0.8125rem; line-height: 1.4; }

/* Forms inside a side card stack and never push the card wider: the Roles grant form's
   subject picker asks for 24rem of flex basis, which a 280px column cannot give. */
.portal-col-side .portal-card { min-width: 0; overflow-wrap: anywhere; }
.portal-col-side .filter-bar { flex-direction: column; align-items: stretch; }
.portal-col-side .filter-bar .subject-picker { flex: 1 1 auto; min-width: 0; max-width: none; }
.portal-col-side .filter-bar input[type="search"],
.portal-col-side .filter-bar input[type="email"],
.portal-col-side .filter-bar input[type="text"],
.portal-col-side .filter-bar select { max-width: none; width: 100%; }
.portal-col-side .filter-bar button { align-self: flex-start; }
.portal-col-side .stacked-form { max-width: none; }
.portal-card .te-scroll { max-width: 100%; }
/* A command to copy into a shell (the onboarding Exchange steps) wraps inside its card rather
   than running off the edge; copying it still gives one line, because the breaks are visual. */
.portal-card pre { max-width: 100%; white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---- Side column: status card and activity feed ---- */
.portal-status-card .te-btn-away { margin-top: 0.5rem; }
.portal-status-art { display: block; width: 44px; height: 44px; border-radius: 50%; margin-bottom: 0.75rem; }
.portal-status-art.is-on  { background: color-mix(in srgb, var(--te-teal) 55%, var(--te-card)); }
.portal-status-art.is-off { background: color-mix(in srgb, var(--te-gold) 55%, var(--te-card)); }

.portal-feed { list-style: none; margin: 0.5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.875rem; }
.portal-feed-item { display: grid; grid-template-columns: 12px minmax(0, 1fr); gap: 0.75rem; align-items: start; }
.portal-feed-dot { display: block; width: 12px; height: 12px; border-radius: 50%; margin-top: 0.375rem; background: var(--te-line); }
.portal-feed-dot.gift { background: var(--te-teal); }
.portal-feed-dot.intern { background: var(--te-blue); }
.portal-feed-text { display: flex; flex-direction: column; gap: 0.125rem; font-size: 0.9375rem; }
.portal-feed-when { color: var(--te-ink-muted); font-size: 0.8125rem; }

/* ---- Top bar: help, settings, account (the Microsoft 365 pattern) ---- */
.portal-topbar .site-nav { display: flex; align-items: center; gap: 0.25rem; }
.portal-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; border-radius: 6px;
  color: var(--te-ink-muted); background: transparent; border: 0; cursor: pointer;
  list-style: none;
  /* On a real <button> (the menu's arrow) the bare button rule's padding would leave the icon no
     width at all, and its shadow would draw an empty box: what John saw on 2026-10-16. */
  padding: 0; box-shadow: none;
}
.portal-iconbtn:hover, .portal-iconbtn:focus-visible { background: var(--te-surface-sunken); color: var(--te-ink); text-decoration: none; }
.portal-iconbtn::-webkit-details-marker, .portal-avatar-btn::-webkit-details-marker { display: none; }
.portal-avatar-btn { list-style: none; display: inline-flex; align-items: center; padding: 0.125rem; border-radius: 50%; cursor: pointer; }
.portal-avatar-btn:hover, .portal-avatar-btn:focus-visible { outline: 2px solid var(--te-focus); outline-offset: 1px; }
.portal-avatar { width: 32px; height: 32px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; object-fit: cover; background: var(--te-navy); color: var(--te-white); font-weight: 600; font-size: 0.8125rem; letter-spacing: 0.02em; }
.portal-avatar-lg { width: 48px; height: 48px; font-size: 1.125rem; }
.portal-menu { position: relative; }
.portal-menu > summary { display: inline-flex; }
.portal-menu-panel {
  position: absolute; top: calc(100% + 0.375rem); left: 0; z-index: 50;
  min-width: 15rem; padding: 0.5rem; display: flex; flex-direction: column; gap: 0.125rem;
  background: var(--te-card); border: 1px solid var(--te-border); border-radius: 8px;
  box-shadow: 0 8px 24px rgb(28 37 46 / 14%);
}
.portal-menu-right .portal-menu-panel { left: auto; right: 0; }
.portal-menu-panel a, .portal-menu-panel .link-button {
  display: block; width: 100%; text-align: left; padding: 0.5rem 0.75rem; border-radius: 6px;
  color: var(--te-ink); font-weight: 500; text-decoration: none;
}
.portal-menu-panel a:hover, .portal-menu-panel .link-button:hover { background: var(--te-surface-sunken); color: var(--te-ink); text-decoration: none; }
.portal-menu-panel .inline-form { display: block; }
.portal-menu-label { display: block; padding: 0.625rem 0.75rem 0.25rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--te-ink-muted); }
.portal-menu-identity { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0.75rem 0.75rem; border-bottom: 1px solid var(--te-border); margin-bottom: 0.25rem; }
.portal-menu-identity div { display: flex; flex-direction: column; min-width: 0; }
/* Both lines can be an address, which is one unbreakable token: the bold line carries it when
   the identity has no separate display name (the dev sign-in, or a directory name that is the
   address). Without a wrapping rule it overflowed the panel. overflow-wrap rather than
   break-all, so a real name still breaks at its spaces first. */
.portal-menu-identity strong { font-size: 0.9375rem; overflow-wrap: anywhere; }
.portal-menu-identity .muted { font-size: 0.8125rem; overflow-wrap: anywhere; }
/* The panel's containing block is the avatar button, so it never grows with its content: its
   width IS its min-width. 22rem fits an ordinary address on one line; a longer one wraps at the
   <wbr> the layouts place after the @, so it breaks as name@ / domain rather than mid-word. */
.portal-menu-account { min-width: 22rem; max-width: calc(100vw - 2rem); }

/* ---- Narrow screens: a strip, not a broken grid ---- */
@media (max-width: 900px) {
  .portal-shell { grid-template-columns: 1fr; }
  .portal-sidebar { position: static; height: auto; }
  .portal-nav { flex-direction: row; flex-wrap: wrap; gap: 0.25rem; }
  .portal-nav a { border-left: 0; border-bottom: 3px solid transparent; }
  .portal-nav a[aria-current="page"] { border-bottom-color: var(--te-teal); }
  .portal-nav-label { display: none; }
  .portal-sidebar-foot { display: none; }               /* the top bar carries name + sign out */
  .portal-sub { flex-direction: row; flex-wrap: wrap; gap: 0.125rem; margin: 0; }
  .portal-sub a { padding: 0.25rem 0.5rem; }
  .portal-sidebar { padding: 0.75rem 0.75rem 0.5rem; }
  .portal-brand { flex-direction: row; align-items: center; gap: 0.625rem; padding: 0 0.5rem 0.625rem; margin-bottom: 0.375rem; }
  .portal-brand .logo { height: 32px; }
  .portal-grid, .portal-promo-row { grid-template-columns: 1fr; }
  .portal-main > main { padding: 1rem; }
  .portal-list-head { display: none; }
  .portal-list-row { grid-template-columns: 1fr; gap: 0.5rem; }
}

/* ---- Legal pages and the footer line ----
   /privacy and /terms reuse the help layout (contents column beside the article) without the
   search box; the footer carries the copyright and, on the applicant side, the two links. */
.legal-contents-label { margin: 0; font-weight: 600; }

.legal-toc {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

.legal-toc li { margin: 0.15rem 0; }

.legal-body h2:first-child { margin-top: 0; }

.legal-links { margin-left: 0.75rem; }
.legal-links a { margin-right: 0.75rem; }
.legal-links a:last-child { margin-right: 0; }

/* The staff footer stacks its confidentiality line above the copyright. */
.portal-foot > span { display: inline-block; margin-right: 0.75rem; }

/* A raw API response on the Aplos probe: wrapped, scrollable, and visibly "data, not page". */
.te-raw {
  max-height: 24rem;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 0.8125rem;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  padding: 0.5rem 0.625rem;
  margin: 0.5rem 0 0;
}

/* A question answered by several controls is a fieldset; its legend reads as the field's label. */
.field > legend { font-weight: 600; padding: 0; }

/* =========================================================================
   Booth page (event sign-ups plan card 4; docs/DESIGN_LANGUAGE.md)
   -------------------------------------------------------------------------
   A tablet on a table at a conference. The tablets in use are about 690 x 1,090 CSS px in portrait (owner's photos,
   2026-11-05): the open form, staff strip included, must fit one such screen without scrolling. Every control keeps 3rem
   (48px), and the church results overlay the fields below so a search doesn't push the form down. Four tabs, one row at 690px.
   Tokens only, no hex, in the design-language component layer's voice. A booth-tab is a button that switches the panel you
   are looking at (IN-PAGE, it goes nowhere), so the selected one is the only filled tab. Submit is ACT, Add a church and
   Next person are IN-PAGE. The element rules above style every <button>, so each booth button restates its colours with
   a selector that outranks `button:hover`.

   THE TABLETS USE THE COLOUR SHEET'S OWN VALUES (plan 9c.1 decision 4; docs/DESIGN_LANGUAGE.md section 12, 2026-11-11).
   The body of a booth page carries the class booth-page, which nothing else uses, and that one rule redeclares every
   layer-3 colour token as a palette name, so a booth rule that reads a token gets one of the 15 sheet colours and never a
   derived shade. It must redeclare the leaf names (--te-ink, --te-primary, --te-accent-soft and the rest), not only their
   sources: a custom property holding var() is resolved where it is declared, so --te-ink inherited from :root arrives
   already computed as charcoal through --te-text, and repointing --te-text here would not move it. Every token is
   redeclared, not only those a booth rule reads today, so a component added later cannot pull a derived shade through a
   token nobody repointed. Layers 1 and 2 and :root are untouched and still serve every other page. BoothPaletteTests
   pins the rule, the role table and the absence of any other colour in this block.
   ========================================================================= */
.booth-page {
  /* text: charcoal 10.32:1 on white, 8.25:1 on bone, 5.99:1 on sky; muted is told apart by size and weight */
  --te-text:               var(--te-charcoal);
  --te-text-muted:         var(--te-charcoal);
  --te-text-invert:        var(--te-white);
  --te-ink:                var(--te-charcoal);
  --te-ink-muted:          var(--te-charcoal);
  /* surfaces */
  --te-surface:            var(--te-white);
  --te-surface-sunken:     var(--te-bone);
  --te-header:             var(--te-white);
  --te-header-admin:       var(--te-white);
  --te-card:               var(--te-white);
  /* lines: taupe is decorative; slate is the control boundary (3.37:1 on white) */
  --te-header-edge:        var(--te-taupe);
  --te-border:             var(--te-bone);
  --te-border-mid:         var(--te-taupe);
  --te-border-strong:      var(--te-slate);
  --te-line:               var(--te-taupe);
  /* interaction: navy fills with white text 15.52:1, hover charcoal 10.32:1 */
  --te-link:               var(--te-navy);
  --te-link-hover:         var(--te-charcoal);
  --te-action:             var(--te-navy);
  --te-action-text:        var(--te-white);
  --te-action-hover:       var(--te-charcoal);
  --te-action-hover-text:  var(--te-white);
  --te-action-off:         var(--te-bone);
  --te-focus:              var(--te-navy);
  --te-primary:            var(--te-navy);
  --te-primary-hover:      var(--te-charcoal);
  --te-on-primary:         var(--te-white);
  --te-accent:             var(--te-navy);
  --te-accent-hover:       var(--te-charcoal);
  --te-accent-soft:        var(--te-bone);
  --te-on-accent:          var(--te-white);
  /* status: crimson 9.25:1 on white, 7.40:1 on bone */
  --te-danger:             var(--te-crimson);
  --te-danger-fill:        var(--te-bone);
  --te-danger-soft:        var(--te-bone);
  --te-success:            var(--te-charcoal);
  --te-success-fill:       var(--te-sky);
  --te-caution:            var(--te-brown);
  --te-caution-fill:       var(--te-cream);
  --te-caution-edge:       var(--te-gold);
  --te-brand-accent:       var(--te-crimson);
  /* native checkboxes */
  accent-color: var(--te-navy);
}
/* The root element holds :root's own accent-color (the derived blue). It paints nothing, but the body inherits from it
   only until .booth-page redeclares it, and a computed-style audit reads the root too. */
html:has(> body.booth-page) { accent-color: var(--te-navy); }

/* Four global rules that render on the tablets paint a colour no token reaches, so each has a booth-scoped override. */
/* 1. A focused text field: navy border plus a one pixel navy ring, not the blue border with its alpha halo (4.60:1 against the slate edge). */
.booth-page input:not([type="checkbox"]):not([type="hidden"]):focus-visible,
.booth-page select:focus-visible,
.booth-page textarea:focus-visible {
  border-color: var(--te-navy);
  box-shadow: 0 0 0 1px var(--te-navy);
}
/* 2. The section label: an opaque bone wash with a navy left edge, not a translucent accent. */
.booth-page .te-section-label {
  background: var(--te-bone);
  border-left-color: var(--te-gold);
}
/* 3. The open arm: full opacity, an outlined crimson button, not crimson blended into pink. */
.booth-page .te-arm[open] > summary {
  opacity: 1;
  background: var(--te-card);
  color: var(--te-danger);
}
/* 4. The bare button rule's hairline shadows are alpha colours: none on the tablets, at rest and on hover. */
.booth-page button,
.booth-page button:hover {
  box-shadow: none;
}
/* Submit and Upload, the ACT buttons: gold with navy lettering (8.46:1) and a 2px navy edge, because gold on white is only 1.9:1
   (owner's choice, 2026-11-11, later that evening). Hover, keyboard focus and :active stay gold with navy lettering: the global hover
   is charcoal with white lettering, which navy lettering would not survive, and a tapped tablet button keeps its hover look. The
   focus ring stays navy (--te-focus). Disabled is excluded so it keeps the wash, a taupe edge and charcoal lettering (8.25:1). The
   tokens are left alone: --te-accent still points at navy, which the checkbox, the arm and the thank-you rule read. */
.booth-page button.te-btn-act:not(:disabled),
.booth-page button.te-btn-act:not(:disabled):hover,
.booth-page button.te-btn-act:not(:disabled):focus-visible,
.booth-page button.te-btn-act:not(:disabled):active {
  background: var(--te-gold);
  border-color: var(--te-navy);
  color: var(--te-navy);
}

.booth-header {
  background: var(--te-header);
  border-bottom: 1px solid var(--te-header-edge);
  padding: 0.5rem 1rem;
}
.booth-header .logo { display: block; height: 32px; width: auto; }

.booth-main { width: 100%; max-width: 52rem; margin: 0 auto; padding: 0.75rem 1rem; }
.booth-title { margin: 0 0 0.5rem; font-size: 1.125rem; }

/* ---- Tabs: large buttons, one filled ---- */
.booth-tabs { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 0.75rem; }
button.booth-tab, button.booth-tab:hover {
  flex: 1 1 auto;
  min-height: 3rem;
  padding: 0.25rem 0.75rem;
  background: var(--te-card);
  border: var(--te-btn-border) solid var(--te-navy);
  border-radius: var(--te-btn-radius);
  color: var(--te-navy);
  font-size: 1.125rem;
  box-shadow: none;
}
button.booth-tab:hover { background: var(--te-sky); }
button.booth-tab[aria-selected="true"], button.booth-tab[aria-selected="true"]:hover {
  background: var(--te-primary);
  border-color: var(--te-primary);
  color: var(--te-on-primary);
}

/* ---- Fields ---- */
.booth-panel { max-width: 100%; }
.booth-panel .lede { margin: 0 0 0.625rem; font-size: 1rem; line-height: 1.4; }
.booth-panel fieldset.te-fieldset { margin: 0 0 0.5rem; }
.booth-panel fieldset > legend.te-section-label { margin: 0 0 0.375rem; }
/* The First name / Last name labels say it; the Name legend stays for screen readers (same declarations as .sr-only). */
.booth-group > legend {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.booth-field { display: flex; flex-direction: column; gap: 0.125rem; margin: 0 0 0.5rem; min-width: 0; }
.booth-field label { font-weight: 600; line-height: 1.35; }
.booth-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 1rem; }
.booth-panel input:not([type="checkbox"]):not([type="hidden"]),
.booth-panel select {
  width: 100%;
  min-height: 3rem;
  font-size: 1.125rem;
}
.booth-panel input[aria-invalid="true"],
.booth-panel select[aria-invalid="true"] { border-color: var(--te-danger); border-width: 2px; }
/* A control the picker has filled from a listed church, or has not yet opened: visibly not for typing. */
.booth-panel input:disabled,
.booth-panel select:disabled {
  background: var(--te-surface-sunken);
  border-color: var(--te-line);
  color: var(--te-ink-muted);
  cursor: not-allowed;
}

/* ---- Interests: one wash row each, the whole row is the target ---- */
.booth-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 0.375rem; }
.booth-choice {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3rem;
  padding: 0 0.75rem;
  background: var(--te-accent-soft);
  border: 1px solid var(--te-taupe);
}
.booth-choice.has-detail { grid-column: 1 / -1; }
.booth-choice input[type="checkbox"] { flex: 0 0 auto; width: 1.5rem; height: 1.5rem; margin: 0; }
.booth-choice label { flex: 1 1 auto; display: flex; align-items: center; min-height: 3rem; font-weight: 600; cursor: pointer; }
.booth-choice.has-detail label:not(.sr-only) { flex: 0 0 auto; }
/* A control on a bone wash takes a navy border: slate would be 2.70:1 on bone, a fail. */
.booth-choice input[type="text"] { flex: 1 1 12rem; min-width: 0; border-color: var(--te-navy); }

/* ---- Church picker ---- */
.booth-church { position: relative; }
/* Always rendered: it is a role="status" live region. Only its spacing goes when it is empty. */
.booth-status { min-height: 0; margin: 0; color: var(--te-ink-muted); }
.booth-status:not(:empty) { margin: 0 0 0.375rem; }
/* The results drop over the fields below instead of pushing them down; with top auto it sits right under the status line. */
.booth-results {
  position: absolute;
  z-index: 5;
  left: 0;
  right: 0;
  max-height: 22rem;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0.375rem;
  background: var(--te-card);
  border: 2px solid var(--te-navy);
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.booth-results[hidden] { display: none; }
button.booth-result, button.booth-result:hover {
  display: block;
  width: 100%;
  min-height: 3rem;
  padding: 0.5rem 0.875rem;
  background: var(--te-accent-soft);
  border: 1px solid var(--te-taupe);
  border-radius: var(--te-btn-radius);
  color: var(--te-ink);
  font-size: 1.0625rem;
  font-weight: 600;
  text-align: left;
  box-shadow: none;
}
button.booth-result:hover, button.booth-result:focus-visible {
  border-color: var(--te-navy);
  background: var(--te-sky);
}
.booth-church .te-btn-inpage { min-height: 3rem; margin: 0 0 0.5rem; }

/* ---- Messages, privacy line, Submit ---- */
.booth-notice {
  margin: 0.75rem 0;
  padding: 0.5rem 0.75rem;
  border-left: 4px solid var(--te-danger);
  background: var(--te-danger-soft);
  color: var(--te-danger);
  font-weight: 600;
}
.booth-notice:empty { display: none; }
.booth-privacy { margin: 0.5rem 0; color: var(--te-ink-muted); font-size: 0.875rem; }
.booth-submit { min-height: 3rem; }

/* ---- Thank you ---- */
.booth-thanks {
  padding: 3rem 1.5rem;
  text-align: center;
  background: var(--te-cream);
  border: 2px solid var(--te-gold);
  border-left-width: 8px;
}
.booth-thanks[hidden] { display: none; }
.booth-thanks-text { margin: 0 0 1.5rem; font-size: 2rem; font-weight: 700; color: var(--te-ink); overflow-wrap: anywhere; }
.booth-thanks-text:focus { outline: none; }
.booth-thanks .te-btn-inpage { min-height: 3.5rem; }

/* ---- A closed event ---- */
.booth-closed { padding: 3rem 0; text-align: center; }
.booth-closed .lede { margin: 0.5rem auto; font-size: 1.375rem; }

/* ---- The staff strip at the foot ---- */
.booth-strip {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 0.125rem 1.25rem;
  padding: 0.375rem 1rem;
  background: var(--te-surface-sunken);
  border-top: 1px solid var(--te-line);
  color: var(--te-ink-muted);
  font-size: 0.8125rem;
  align-items: center;
}
.booth-strip p { margin: 0; }
.booth-tag { font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: 0.08em; color: var(--te-ink); }
/* Card 5: the counts, Ready for offline, Upload and the discard arm. Counts only, never an entry. */
.booth-count { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--te-ink); }
.booth-warning { color: var(--te-danger); font-weight: 600; }
.booth-warning[hidden] { display: none; }
.booth-strip-actions { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem; margin-top: 0; }
.booth-strip-actions .booth-upload { min-height: 3rem; }
.booth-strip .booth-upload-status { flex: 1 1 16rem; align-self: center; color: var(--te-ink); }
/* .te-arm sets a display, which would otherwise show an arm the script has hidden. */
.booth-strip .te-arm[hidden] { display: none; }
.booth-strip .te-arm-body .te-btn-danger { min-height: 3rem; }

/* ---- Tablet width: two columns, so the open form fits one portrait screen ----
   Phone width still stacks. The church rows are pinned to explicit grid rows because the results overlay is
   absolutely positioned: it needs a grid area to be its containing block, and row 4 (the church fields) is where it opens. */
@media (min-width: 36rem) {
  .booth-panel [data-role="body"] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; }
  .booth-panel [data-role="body"] > * { grid-column: 1 / -1; }
  .booth-panel [data-role="body"] > .booth-field { grid-column: auto; }
  .booth-church { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 0.75rem; }
  .booth-church > * { grid-column: 1 / -1; }
  .booth-church-find { grid-column: 1; grid-row: 1; }
  .booth-church > [data-role="church-add"] { grid-column: 2; grid-row: 1; align-self: end; }
  .booth-church > .booth-status { grid-row: 2; }
  .booth-church > .field-error { grid-row: 3; }
  .booth-church-fields { grid-row: 4; }
  .booth-church > .booth-results { grid-row: 4; grid-column: 1 / -1; }
  .booth-church-fields { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) 11rem; column-gap: 0.75rem; }
  .booth-church-fields select { font-size: 1rem; }
}

/* ---- Devotion editor -------------------------------------------------------
   The list's editor sits full width under it (Areas/Admin/Pages/Pathways/Devotions/List). .wide
   lifts a field's 640px cap, .narrow keeps a date picker the size of a date. The question boxes
   are plain inputs that site.js hides and shows one at a time; the [hidden] rule is here because
   the button classes set a display that would otherwise beat the attribute. Row actions stay on
   one line until a delete is armed, whose body then takes a line of its own. */
.form-field.wide, .field.wide { max-width: none; }
.form-field.narrow, .field.narrow { max-width: 14rem; }
.te-questions input[hidden], .te-questions button[hidden] { display: none; }
.te-questions button.te-btn-inpage { align-self: flex-start; }
.te-row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.te-row-actions form { margin: 0; }
.te-row-actions .te-arm[open] { flex: 1 1 100%; }
/* A refusal sits in its row, under the row's words and actions, on a line of its own (Card 14). */
.te-row-error { flex: 1 1 100%; margin: 0; }
/* An inline form whose fields show their labels: each field is a label over its input, side by
   side with the others and the button, wrapping on a phone. The sr-only tail on a label names the
   row, as the buttons that repeat do (design language 9). */
.inline-form.te-inline-labelled { display: inline-flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem; }
.te-inline-field { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.te-inline-field label { font-size: 0.875rem; font-weight: 600; }
.te-inline-field .muted { font-size: 0.8125rem; }

/* =========================================================================
   Signed-out header buttons and the applicant landing page
   (docs/DESIGN_LANGUAGE.md section 11, 2026-11-04)
   -------------------------------------------------------------------------
   The header is the logo and two square buttons: Sign in (outlined secondary
   navigation, .ghost-button) and Start an application (the AWAY fill). Bold
   uppercase with a little letter-spacing echoes the main site's condensed
   caps. Written against .site-nav a so the nav's link rules cannot recolour
   or underline them. Every colour is a token.
   ========================================================================= */
.site-header .site-nav { flex-wrap: nowrap; gap: 0.5rem; }

.site-header .site-nav a.header-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;                 /* 44px touch target */
  padding: 0.375rem 1rem;
  font-size: 0.8125rem;
  font-weight: var(--te-btn-weight);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
}
.site-header .site-nav a.ghost-button.header-btn,
.site-header .site-nav a.ghost-button.header-btn:hover,
.site-header .site-nav a.ghost-button.header-btn:focus-visible { color: var(--te-navy); text-decoration: none; }
.site-header .site-nav a.te-btn-away.header-btn,
.site-header .site-nav a.te-btn-away.header-btn:hover,
.site-header .site-nav a.te-btn-away.header-btn:focus-visible { color: var(--te-on-primary); text-decoration: none; }

/* Phone: the logo scales down and both buttons stay on one line beside it; "Start an application"
   may take two lines inside its 44px-high box rather than push the pair onto a second row. */
@media (max-width: 560px) {
  .header-row { flex-wrap: nowrap; gap: 0.5rem; }
  .site-header .site-nav { gap: 0.375rem; }
  .site-header .site-nav a.header-btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    line-height: 1.15;
  }
  .site-header .site-nav a.te-btn-away.header-btn { white-space: normal; max-width: 6.25rem; }
}

/* One width for every signed-out applicant page: the header, the page and the footer share a left
   edge. Scoped to the signed-out body, so the admin layout and the signed-in shell are untouched. */
body.public-body .container { max-width: 1100px; }
.public-body .site-header .brand .logo { height: 40px; }
@media (min-width: 900px) {
  .public-body .site-header .brand .logo { height: 52px; }
}

/* Full-bleed pages draw their own bands; the page container comes off. */
main.full-bleed { padding: 0; }

.landing-band { padding: 2.5rem 0; }
.landing-hero,
.landing-serve { background: var(--te-surface-sunken); }
.landing-hero-grid { display: grid; grid-template-columns: 1fr; gap: 2rem; }
@media (min-width: 900px) {
  .landing-hero-grid { grid-template-columns: 1.15fr 1fr; gap: 3.5rem; align-items: center; }
}
.landing-hero { border-bottom: 1px solid var(--te-border); }
.landing-serve { border-top: 1px solid var(--te-border); border-bottom: 1px solid var(--te-border); }

.landing-eyebrow {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--te-ink-muted);
}

/* One heading voice: bold uppercase with letter-spacing, and a short brand-accent bar under it. */
.landing-title,
.landing-heading {
  margin: 0;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.1;
  color: var(--te-navy);
  overflow-wrap: anywhere;
}
.landing-title { font-size: clamp(2rem, 7vw, 3.25rem); }
.landing-heading { font-size: clamp(1.375rem, 4.5vw, 1.875rem); }
.landing-title::after,
.landing-heading::after {
  content: "";
  display: block;
  width: 4.5rem;
  height: 0.3125rem;
  margin-top: 1rem;
  background: var(--te-brand-accent);
}
.landing-heading::after { width: 3rem; height: 0.25rem; margin-top: 0.75rem; }

.landing-lead {
  max-width: 42rem;
  margin: 1.25rem 0 0;
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--te-ink);
}
.landing-lead + .landing-lead { margin-top: 0.75rem; }

.landing-actions { margin: 1.75rem 0 1rem; }
.landing-actions .landing-secondary { align-self: stretch; padding: 0.75rem 1.25rem; font-size: var(--te-btn-size); text-align: center; }
.landing-aside { margin: 0.5rem 0 0; font-size: 0.9375rem; color: var(--te-ink-muted); }
.landing-aside a { text-decoration: underline; }

@media (min-width: 720px) {
  .landing-band { padding: 4rem 0; }
  .landing-actions { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 0.75rem; }
  .landing-actions .te-btn-hero { width: auto; align-self: auto; padding: 0.875rem 2rem; font-size: 1.1875rem; }
  .landing-actions .landing-secondary { align-self: auto; padding: 0.875rem 2rem; }
}

/* How applying works: a white card in the hero's right column, three numbered steps as a vertical
   list, each a primary circle with a white number beside a bold title and its sentence. */
.te-card.landing-how-card {
  max-width: none;
  margin: 0;
  padding: 1.5rem;
  box-shadow: 0 2px 10px rgb(28 37 46 / 10%);
}
.landing-how-card .landing-heading { font-size: 1.375rem; }
.landing-steps {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  counter-reset: landing-step;
}
.landing-step {
  counter-increment: landing-step;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  column-gap: 1rem;
  align-items: start;
}
.landing-step::before {
  content: counter(landing-step);
  grid-row: 1 / span 2;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--te-primary);
  color: var(--te-on-primary);
  font-size: 1.125rem;
  font-weight: 800;
}
.landing-step h3 { margin: 0 0 0.25rem; font-size: 1.1875rem; }
.landing-step p { margin: 0; color: var(--te-ink); line-height: 1.5; }

/* Ways to serve: one compact card per program, two columns on a desktop. An open program's card IS
   the link (design language 1B), so the page keeps one solid button for the hero to own. */
.landing-programs {
  list-style: none;
  margin: 1.75rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
.landing-programs > li { display: flex; }
.landing-program {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 1.25rem;
  background: var(--te-card);
  border: 1px solid var(--te-line);
  color: var(--te-ink);
  text-decoration: none;
}
.landing-program h3 { margin: 0; font-size: 1.1875rem; color: var(--te-navy); }
.landing-program p { margin: 0; color: var(--te-ink-muted); line-height: 1.5; }
.landing-program-note { font-weight: 700; color: var(--te-ink); }
.landing-program-cta { margin-top: auto; padding-top: 0.5rem; font-weight: 700; color: var(--te-link); }
a.landing-program:hover,
a.landing-program:focus-visible {
  border-color: var(--te-primary);
  box-shadow: 0 2px 10px rgb(28 37 46 / 14%);
  color: var(--te-ink);
  text-decoration: none;
}
a.landing-program:hover .landing-program-cta,
a.landing-program:focus-visible .landing-program-cta { text-decoration: underline; }
@media (min-width: 760px) {
  .landing-programs { grid-template-columns: repeat(2, 1fr); }
}
