/* West Coast In-Home — shared responsive base.
 * ============================================================================
 *
 * THE FIRST SHARED STYLESHEET IN THIS CODEBASE. Everything else is inline
 * <style> in a template. Read this header before adding to it.
 *
 * Served at /static/css/wci-core.css from the app-level static folder. That
 * path is deliberate and is the only one that works: the per-blueprint static
 * dirs (/admin/assets/, /assets/) belong to ONE site each, and the apex 302s
 * /admin/... to the admin host — so a stylesheet under /admin/assets/ can
 * never be fetched by the public site or the PWA. The app-level ``static``
 * endpoint is mapped to the pseudo-site "shared" in app/__init__.py and skips
 * the host gate entirely, so this one file serves identically on
 * westcoastinhome.com, admin.westcoastinhome.com, app.westcoastinhome.com and
 * statue-of-us.com.
 *
 * ── WHAT THIS FILE MUST NOT DO ──────────────────────────────────────────────
 *
 * 1. IT DECLARES NO PALETTE TOKENS. Not one --navy, not one hex from
 *    docs/PALETTE.md. Colour still lives in each shell's own :root, which
 *    keeps the drift check in docs/PALETTE.md working unchanged and means a
 *    mistake here cannot re-skin four surfaces at once. This file owns the
 *    RESPONSIVE system; the shells keep owning colour. The two layout tokens
 *    below are not colours.
 *
 * 2. THE FIVE STANDALONE LINK-TAP PAGES MUST NEVER LINK IT — scheduling_pick,
 *    scheduling_confirmed, offer_response, offer_confirmed, offer_invalid.
 *    An applicant opens those by tapping a link in an SMS on a phone and they
 *    make ZERO external requests on purpose; a stylesheet adds a blocking
 *    round-trip to exactly the pages that can least afford one. They are
 *    already phone-first (single column, rem max-widths, 100%-width controls,
 *    >=16px inputs) and need nothing from here. docs/PALETTE.md:175-189 warned
 *    that introducing a shared stylesheet would tempt someone to point them at
 *    it. Don't.
 *
 * ── CASCADE POSITION ────────────────────────────────────────────────────────
 *
 * Linked EARLY — after Bootstrap/fonts but BEFORE each shell's inline
 * <style>. This is the base layer: shells and pages are meant to override it.
 * public_base.html's {% block extra_css %} lives inside its inline <style>,
 * so loading this first is what lets a child page win.
 *
 * wci-admin.css is the opposite: it loads LAST, because it deliberately
 * reshapes the navbar and the SPA app-shell at compact widths.
 *
 * ── BREAKPOINTS ─────────────────────────────────────────────────────────────
 *
 * Bootstrap 5's scale, because the ATS already loads Bootstrap and leans on
 * col-md-* / col-lg-* heavily. Any other scale means custom rules fighting the
 * grid at a 20px offset.
 *
 *   compact   <= 767.98px   phones + small tablets  <- the important one
 *   tablet    768 - 991.98px
 *   desktop   >= 992px      (the SPA's existing left-sidebar flip)
 *   wide      >= 1200px
 *
 * Custom properties cannot be used inside @media, so these are literal values
 * everywhere. docs/RESPONSIVE.md is the record and carries a drift-check grep.
 */

:root{
  /* Layout tokens only — no colour. See the header. */
  --wci-bottomnav-h:56px;   /* compact-width bottom bar; 0 above the breakpoint */
  --wci-tap:44px;           /* minimum touch target, per WCAG 2.5.5 / iOS HIG */
}

/* ── Overflow safety ────────────────────────────────────────────────────────
   The single most common cause of a page that scrolls sideways on a phone is
   a replaced element with an intrinsic width wider than its container. These
   three rules prevent most of it before anyone writes a media query.

   min-width:0 on flex/grid children is the other half: those default to
   min-width:auto, which refuses to shrink below their content and is why a
   long unbroken string blows out a flex row. index.html already documents
   this at its .min-width-0 helper; this generalises it. */
img, svg, video, canvas, iframe{max-width:100%}
img, video{height:auto}
.wci-min0{min-width:0}

/* FORM CONTROLS BELONG IN THAT LIST, and leaving them out is the single
   biggest source of sideways scroll in this codebase.

   A <select> has an intrinsic width: it sizes itself to its WIDEST <option>,
   whatever the layout around it wants. Every filter bar here is populated
   from the database — office names, service areas, family names — so the
   width of a control is really the length of the longest row someone typed.
   One long area name and the select is 429px inside a 312px row, the page
   is 93px wider than the phone, and it drags sideways under the thumb on
   every screen that bar appears on. Nothing in the markup hints at it.

   `min-width:0` is the other half and is what actually does the work: a flex
   item defaults to `min-width:auto`, which refuses to shrink below its
   content, so `max-width:100%` alone still loses to the intrinsic width.

   Truncating the closed control is the right trade — the native dropdown
   still shows every option in full when it is opened. */
select, input, textarea, button{max-width:100%}
select, input, textarea{min-width:0}

/* The control is usually not the flex item — a <label> wrapping it is, and
   the label keeps min-width:auto, so it refuses to shrink below the control's
   intrinsic width and the rule above never gets to help. Two date pickers in
   one row on a 360px phone is the case that found this. */
label{min-width:0}

/* Long words / URLs / email addresses in a narrow column. Still here for
   deliberate use at any width; below 768px it is the default instead (see
   the compact block further down). */
.wci-wrap-anywhere{overflow-wrap:anywhere; word-break:break-word}

/* ── Containers ─────────────────────────────────────────────────────────────
   Gutters step down on small screens rather than staying at a desktop 24px,
   which wastes ~13% of a 375px viewport. */
.wci-container{
  width:100%;
  max-width:1120px;
  margin-inline:auto;
  padding-inline:24px;
}
@media (max-width:767.98px){
  .wci-container{padding-inline:16px}
}

/* ── Safe-area insets ───────────────────────────────────────────────────────
   Only meaningful once installed to a home screen: in standalone mode there
   is no browser chrome, so content runs under the notch, the rounded corners
   and the home indicator. env() resolves to 0 where it does not apply, so
   every one of these is a no-op in a desktop browser.

   Requires <meta name="viewport" content="... viewport-fit=cover"> — without
   it the insets are always 0 and these silently do nothing. */
.wci-safe-x{
  padding-left:env(safe-area-inset-left);
  padding-right:env(safe-area-inset-right);
}
.wci-safe-top{padding-top:env(safe-area-inset-top)}
.wci-safe-bottom{padding-bottom:env(safe-area-inset-bottom)}

/* ── Touch targets ──────────────────────────────────────────────────────────
   A 24px icon button is fine with a mouse and a miss with a thumb. Applied
   only at compact widths so desktop density is untouched. */
@media (max-width:767.98px){
  .wci-tap,
  .wci-taps > a,
  .wci-taps > button{
    min-width:var(--wci-tap);
    min-height:var(--wci-tap);
    display:inline-flex;
    align-items:center;
    justify-content:center;
  }
}

/* ── Form controls: stop iOS zoom-on-focus ──────────────────────────────────
   Mobile Safari zooms the viewport when a focused field's font-size is below
   16px, and does not zoom back out. It is the single most-reported "the form
   is broken on my phone" bug, and it is invisible in DevTools emulation.

   Bootstrap's .form-control is 1rem (fine) but .form-control-sm is .875rem
   (14px) and the ATS uses the -sm variants throughout. This forces 16px on
   phones only; desktop density is untouched.

   Checkbox/radio/range are excluded — font-size does not size them, and
   Bootstrap sizes .form-check-input in em, so touching it would scale them. */
@media (max-width:767.98px){
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea{
    font-size:16px;
  }
}

/* ── The page itself never scrolls sideways on a phone ──────────────────────
   A BACKSTOP, not the fix. The rules above remove the causes; this makes the
   symptom impossible while the next one is still undiscovered. Accidental
   horizontal scroll is worse on a phone than anywhere else: the page slides
   under your thumb while you are trying to scroll down, and whatever is out
   there parks itself off the right edge with nothing to suggest it exists.

   It also breaks a feedback loop that is otherwise very hard to read. A bar
   fixed with `left:0;right:0` sizes to the initial containing block, and the
   ICB grows with the document — so ONE overflowing element widens the page,
   the page widens every fixed bar on it, and the bars then measure as the
   offenders. The staff app's tab bar read as 398px wide on a 360px phone for
   exactly this reason, and deleting it did not narrow the page. Clipping at
   the root stops the ICB growing, so the bars stay honest.

   `clip`, not `hidden`: `hidden` makes the root a scroll container, which
   silently kills `position:sticky` inside it. `clip` does neither. The
   `hidden` line before it is the fallback for anything too old to know
   `clip`, where a working sticky matters less than a page that behaves.

   Deliberately compact-only. A desktop window can be narrower than a dense
   console table, and there scrolling to reach a column is the correct
   behaviour — `.wci-hscroll` is unaffected either way, being its own
   scroller rather than the document.

   scripts/audit_overflow.py turns this off before it measures. Without that
   it would report every page as clean forever, which is worse than having no
   audit at all. */
@media (max-width:767.98px){
  html, body{
    overflow-x:hidden;
    overflow-x:clip;
  }

  /* AND text wraps rather than sticking out, because almost every string on
     these screens came out of the database. An email address, a hyphen-free
     surname, a street with no spaces in it — none of them offer the browser
     a break opportunity, so by default they simply run past the edge of
     whatever is holding them. That is not a rare case: it is what a staff
     list, a family name and a shift panel are made of.

     `anywhere` and not `break-word` on purpose. Only `anywhere` reduces the
     min-content width, and that is the half that matters here — it is what
     lets a flex or grid child, or a table cell turned card, actually give
     way instead of forcing its parent wider.

     This was `.wci-wrap-anywhere`, opt-in, on the reasoning that wrapping
     everywhere "breaks table cells that are meant to stay one line". Below
     this breakpoint those cells are already stacked into cards, so there is
     no line to keep — and the alternative turned out to be a page that
     scrolls sideways whenever a real name is longer than a demo one.
     Anything that genuinely must stay on one line still can: white-space
     :nowrap is unaffected by this. */
  body{overflow-wrap:anywhere}
}

/* ── Horizontal scrollers ───────────────────────────────────────────────────
   For strips that are MEANT to scroll sideways (tab rails, chip rows).
   overscroll-behavior-x:contain stops a horizontal fling from turning into a
   browser back-navigation on iOS. */
.wci-hscroll{
  display:flex;
  flex-wrap:nowrap;
  overflow-x:auto;
  overflow-y:hidden;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin;
}
.wci-hscroll > *{flex:0 0 auto}

/* ── Visibility helpers ─────────────────────────────────────────────────────
   Prefer restyling over duplicating markup — two copies of a control drift.
   Use these only when one layout genuinely cannot serve both. */
@media (max-width:767.98px){ .wci-regular-only{display:none !important} }
@media (min-width:768px){    .wci-compact-only{display:none !important} }

/* ── Tables as cards ────────────────────────────────────────────────────────
   The core pattern for this codebase. An 8-column table inside a horizontally
   scrolling wrapper is technically not broken, but on a 375px screen it is
   unusable — you cannot see a row and its header at the same time.

   Opt in per table:
       <table class="table wci-cards-md">
         <thead><tr><th>Name</th><th>Job</th>...</tr></thead>
         <tbody><tr>
           <td data-label="Name">Ada</td>
           <td data-label="Job">Nanny</td>
           <td data-label="">   <-- empty label: actions, avatars, checkboxes
         </tr></tbody>
       </table>

   Below 768px each <tr> becomes a card and each <td> a label/value row, with
   the label taken from data-label. Above 768px the rules do not exist and the
   table is an ordinary table.

   THE data-label ATTRIBUTES ARE REQUIRED. Without them the cells render with
   no label and the card is unreadable — there is no automatic fallback,
   because CSS cannot read the matching <th>.

   Three details that are easy to get wrong and are handled here:
     - thead is clipped, not display:none — display:none removes it from the
       accessibility tree, so a screen reader loses the column names that the
       data-labels are duplicating.
     - td[colspan] (the "No results found" empty-state row every one of these
       tables has) is NOT turned into a label/value row. It spans the card.
     - .table-responsive must go overflow-x:visible, or the cards sit inside a
       scroller that no longer has anything to scroll and clips shadows.

   The :has() below is load-bearing for a PHASED rollout, not a flourish: it
   switches scrolling off only for wrappers that actually contain a converted
   table, so a .table-responsive still holding a plain wide table keeps
   scrolling instead of blowing out the page. Blanket-targeting
   .table-responsive would regress every table not yet converted. On a browser
   without :has() the cards simply render inside a harmless scroller. */
@media (max-width:767.98px){
  .table-responsive:has(> .wci-cards-md){overflow-x:visible}

  /* The table, tbody and rows ALL have to leave table layout together.
     Making only the rows display:block leaves the <table> as display:table,
     which shrink-wraps to its content: the rows then collapse to about one
     character wide and the card renders as a vertical column of letters.
     Every computed-style check still passes in that state — thead is
     clipped, cells are flex, labels resolve — so it looks correct to
     assertions and is unusable on screen. Do not drop these three rules. */
  .wci-cards-md{display:block; width:100%; border-collapse:separate; border-spacing:0}
  .wci-cards-md > tbody{display:block; width:100%}

  /* Percentage <col> widths are meaningless outside table layout, and an
     unhidden colgroup can still contribute a box in some engines. */
  .wci-cards-md > colgroup{display:none}

  .wci-cards-md > thead{
    position:absolute;
    width:1px; height:1px;
    overflow:hidden;
    clip-path:inset(50%);
    white-space:nowrap;
  }

  .wci-cards-md > tbody > tr{
    display:block;
    margin-bottom:.6rem;
    padding:.55rem .7rem;
    border:1px solid rgba(0,0,0,.08);
    border-radius:12px;
    background:#fff;
  }
  .wci-cards-md > tbody > tr:last-child{margin-bottom:0}

  /* The cell is a BLOCK with a left gutter, and the label is absolutely
     positioned into that gutter.

     Not flex, and that matters. A flex cell makes every child its own flex
     item, so a cell like
         <td>{{ phone }}<div class="ats-meta">{{ email }}</div></td>
     puts the phone and the email side by side in two squeezed columns
     instead of stacking them. Cells in these tables routinely hold a value
     plus one or two meta lines, so that is the common case, not the edge
     one. Block flow stacks any number of children correctly, whatever
     they are. */
  .wci-cards-md > tbody > tr > td{
    display:block;
    position:relative;
    width:auto !important;
    min-height:1.6rem;
    padding:.3rem 0 .3rem 38%;
    border:0;
    text-align:left !important;
    white-space:normal;
  }

  .wci-cards-md > tbody > tr > td::before{
    content:attr(data-label);
    position:absolute;
    left:0;
    top:.3rem;
    width:35%;
    font-size:.75rem;
    font-weight:600;
    text-transform:uppercase;
    letter-spacing:.04em;
    color:#8a94a3;         /* --faint; literal because this file declares no
                              palette tokens, see the header */
    line-height:1.6;
  }

  /* An empty data-label means "no label" — the name headline, actions,
     avatars, checkboxes. The cell takes the full card width. */
  .wci-cards-md > tbody > tr > td[data-label=""]{padding-left:0}
  .wci-cards-md > tbody > tr > td[data-label=""]::before{content:none}

  /* Empty-state rows span the card rather than becoming a label/value pair. */
  .wci-cards-md > tbody > tr > td[colspan]{
    display:block;
    padding-left:0;
    text-align:center !important;
    color:#6c757d;
  }
  .wci-cards-md > tbody > tr > td[colspan]::before{content:none}

  /* A card whose every cell is empty-state should not look like a card. */
  .wci-cards-md > tbody > tr:has(> td[colspan]:only-child){
    border:0; background:transparent; padding:0;
  }
}

/* ── Shift status ───────────────────────────────────────────────────────────
   One vocabulary for "what state is this shift in", used by the console's
   schedule and booking lists and by the caregiver app's agenda. Shared
   because a caregiver and an admin looking at the same shift should not have
   to learn two colour schemes.

   Declares NO palette tokens — it only *uses* the ones every shell sets on
   :root, which is what keeps PALETTE.md's drift check honest (it greps
   templates for declarations, so colour must not start being declared here).
   Custom properties resolve at computed-value time, so using them from a
   stylesheet that loads before the shell is fine.

   CONFIRMED IS PLAIN on purpose: it is the normal case and by far the most
   common, so marking it would make the whole list shout. Everything that is
   NOT simply fine gets a tint and a left edge.

   Cancelled is stripes rather than another tint: it is categorically
   different — not a state of the work but the absence of it — and stripes
   read as "void" at a glance without needing a colour nobody has learned. */
/* ``.wci-st`` OWNS THE BACKGROUND, including the plain one. That is not
   tidiness — it is the whole reason these rules reach the screen.

   Every carrier (.sc-row, .bd-row, .shift) is styled in a <style> block in
   its own template, and those blocks render AFTER this file is linked. A
   carrier declaring `background:#fff` therefore beats `.wci-st-open` on the
   later-wins rule: same specificity, one class each. The classes were on the
   markup and the rules were in this file and the rows were still plain
   white, which is a hard thing to see by reading either file alone.

   So: the carrier sets layout, this sets colour, and the plain default lives
   here where the variants can override it. scripts/audit_status_css.py fails
   the build if a carrier starts declaring a background again. */
.wci-st{
  background:#fff;
  border-left:4px solid transparent;
}

.wci-st-open{
  background:#fff8e8;
  border-left-color:var(--tangerine,#f9b800);
}
.wci-st-offered,
.wci-st-tentative{
  background:color-mix(in srgb, var(--navy,#163B5C) 7%, transparent);
  border-left-color:var(--navy,#163B5C);
  border-left-style:dashed;
}
.wci-st-completed{
  background:var(--well,#fafbfc);
  border-left-color:#cfd6de;
}
.wci-st-no_show{
  background:#fff0f1;
  border-left-color:#d98b92;
}
.wci-st-cancelled{
  border-left-color:#cfd6de;
  color:var(--muted,#6c757d);
  /* 6px of stripe over whatever background the row already has. Low
     contrast on purpose — this must read as "struck through", not as a
     warning competing with the open rows above it. */
  background-image:repeating-linear-gradient(
    -45deg,
    rgba(0,0,0,.055) 0 6px,
    transparent 6px 12px
  );
}
.wci-st-cancelled .wci-st-strike{ text-decoration:line-through; }

/* ── Toggle chips ───────────────────────────────────────────────────────────
   A checkbox that looks like something you would tap. Still a real
   <input type=checkbox> underneath — keyboard, screen readers and form
   submission all work exactly as before; only the paint changes.

   Used anywhere a list of options is picked from: age bands, capabilities,
   restrictions, the children on a shift, what is in a home. A column of bare
   checkboxes is both harder to hit on a phone and harder to scan, because
   the checked ones do not stand out until you look at each box. */
.wci-toggles{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
}
.wci-toggle{
  position:relative;
  display:inline-flex;
  align-items:center;
  gap:8px;
  min-height:44px;               /* WCAG 2.5.5 — see docs/RESPONSIVE.md */
  padding:8px 15px 8px 13px;
  border:1px solid var(--hairline,#e5e7eb);
  border-radius:999px;
  background:#fff;
  color:var(--slate,#4a5662);
  font-size:.9rem;
  font-weight:600;
  line-height:1.2;
  cursor:pointer;
  user-select:none;
  -webkit-tap-highlight-color:transparent;
  transition:background-color .12s, border-color .12s, color .12s;
}
.wci-toggle:hover{ border-color:var(--navy,#163B5C); color:var(--navy,#163B5C); }

/* The box is visually replaced by the tick, but stays in the layout and in
   the accessibility tree — it is the control, not decoration. */
.wci-toggle > input[type=checkbox]{
  position:absolute;
  opacity:0;
  width:1px;
  height:1px;
  margin:0;
  pointer-events:none;
}
.wci-toggle .wci-toggle-mark{
  flex:0 0 auto;
  width:18px;
  height:18px;
  border-radius:50%;
  border:1.5px solid #c3cad3;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  transition:background-color .12s, border-color .12s;
}
.wci-toggle .wci-toggle-mark::after{
  content:"";
  width:9px;
  height:5px;
  border-left:2px solid #fff;
  border-bottom:2px solid #fff;
  transform:rotate(-45deg) translateY(-1px);
  opacity:0;
  transition:opacity .12s;
}
.wci-toggle > input:checked ~ .wci-toggle-mark{
  background:var(--navy,#163B5C);
  border-color:var(--navy,#163B5C);
}
.wci-toggle > input:checked ~ .wci-toggle-mark::after{ opacity:1; }
.wci-toggle:has(> input:checked){
  background:color-mix(in srgb, var(--navy,#163B5C) 9%, transparent);
  border-color:var(--navy,#163B5C);
  color:var(--navy,#163B5C);
}
/* Focus must be visible on the chip, since the real input is invisible. */
.wci-toggle:has(> input:focus-visible){
  outline:2px solid color-mix(in srgb, var(--navy,#163B5C) 45%, transparent);
  outline-offset:2px;
}
.wci-toggle > input:disabled ~ .wci-toggle-mark{ opacity:.4; }
.wci-toggle:has(> input:disabled){ opacity:.55; cursor:default; }

.wci-toggle .wci-toggle-note{
  font-weight:400;
  font-size:.8rem;
  color:var(--faint,#8a94a3);
}

/* ── Overlays: stop the page scrolling underneath ───────────────────────────
   Two halves, and both are needed. overscroll-behavior keeps a flick that
   reaches the end of the panel from chaining to the document; the body lock
   stops iOS scrolling the page when the touch starts outside the panel.
   Without the pair, a modal appears frozen while the page slides behind it. */
.wci-scroll-contain{ overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }

body.wci-locked{
  overflow:hidden !important;
  /* position:fixed would jump the page to the top; this holds the scroll
     position and simply stops it moving. */
  touch-action:none;
}

/* ── Unsaved-changes bar ────────────────────────────────────────────────────
   A Save button at the foot of a long form is easy to scroll past and
   forget. This appears only once something has actually changed, sits above
   any bottom navigation, and says which section it will save.

   ``--wci-bottom-gap`` is how anything fixed to the bottom clears the
   navigation bar. Shells that have one set it; everywhere else it is 0. */
:root{ --wci-bottom-gap:0px; }

.wci-unsaved{
  position:fixed;
  left:0; right:0;
  bottom:calc(var(--wci-bottom-gap) + env(safe-area-inset-bottom));
  z-index:1040;                  /* above bottom nav (1035), below modals */
  display:none;
  align-items:center;
  gap:12px;
  padding:11px calc(16px + env(safe-area-inset-left))
          11px calc(16px + env(safe-area-inset-right));
  background:var(--navy,#163B5C);
  color:#fff;
  box-shadow:0 -3px 16px rgba(0,0,0,.18);
}
.wci-unsaved.is-on{ display:flex; }
.wci-unsaved .wci-unsaved-text{
  flex:1;
  min-width:0;
  font-size:.9rem;
  line-height:1.3;
  overflow:hidden;
  text-overflow:ellipsis;
}
.wci-unsaved .wci-unsaved-text b{ display:block; font-weight:700; }
.wci-unsaved button{
  flex:0 0 auto;
  min-height:44px;
  padding:0 20px;
  border:0;
  border-radius:10px;
  background:#fff;
  color:var(--navy,#163B5C);
  font-family:inherit;
  font-size:.95rem;
  font-weight:700;
  cursor:pointer;
}
.wci-unsaved button.ghost{
  background:transparent;
  color:#fff;
  border:1px solid rgba(255,255,255,.5);
  padding:0 14px;
}

/* ── Concern reporting: the external-escalation block ───────────────────────
   Markup lives in ONE partial, _concern_escalation.html, included by the
   public form, both app forms and the confirmation page. The styles are here
   rather than in that partial because the partial renders inside three
   different shells, and a <style> tag shipped inside an include would either
   duplicate itself when two surfaces render it or fail audit_stray_css.py.
   This file is the only stylesheet all of those shells already load.

   Tokens used are the intersection of what public_base.html and app_base.html
   both declare: --navy, --ink, --slate, --well, --hairline. NOT --muted (the
   app shell has no such token) and NOT --faint (the public shell has none),
   either of which would silently render as an invalid colour on one surface.

   This block tells a reporter they may go outside the company. That is much
   of what makes an internal channel trustworthy, so it is styled to be read
   rather than tucked away as fine print. */
.wci-esc{
  border:1px solid var(--hairline);
  border-radius:14px;
  background:var(--well);
  padding:18px 20px;
  margin:24px 0;
}
.wci-esc > h2{
  font-size:1rem;
  color:var(--navy);
  margin:0 0 6px;
}
.wci-esc-intro{
  font-size:.9rem;
  color:var(--slate);
  margin:0 0 14px;
  line-height:1.5;
}
.wci-esc-group{
  border-top:1px solid var(--hairline);
  padding-top:12px;
  margin-top:12px;
}
.wci-esc-group:first-of-type{border-top:0;padding-top:0;margin-top:0}
.wci-esc-group > h3{
  font-size:.78rem;
  letter-spacing:.4px;
  text-transform:uppercase;
  color:var(--navy);
  margin:0 0 8px;
}
.wci-esc-note{
  font-size:.85rem;
  color:var(--slate);
  margin:0 0 8px;
  line-height:1.5;
}
/* Definition list rather than a table: on a 375px phone a two-column table of
   nine county hotlines either overflows or squeezes the numbers to two words
   per line. This wraps to one block per agency and stays tappable. */
.wci-esc-list{margin:0;padding:0}
.wci-esc-list > div{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:4px 10px;
  padding:5px 0;
  font-size:.9rem;
}
.wci-esc-list .wci-esc-where{color:var(--ink);min-width:9rem;flex:0 1 auto}
/* Phone numbers are tel: links. On a phone this is the difference between a
   number and one tap, and this block is read by people in a hurry. The
   minimum height is the WCAG touch target. */
.wci-esc-list a{
  color:var(--navy);
  font-weight:600;
  text-decoration:none;
  border-bottom:1px solid color-mix(in srgb, var(--navy,#163B5C) 30%, transparent);
  display:inline-flex;
  align-items:center;
  min-height:var(--wci-tap);
}
.wci-esc-list a:hover{border-bottom-color:var(--navy)}
/* The 911 line. Urgency by weight and a rule, not by red — a red panel at the
   top of a form people are already anxious about reads as alarm, and this is
   information, not an alert. */
.wci-esc-urgent{
  font-size:.95rem;
  color:var(--ink);
  font-weight:600;
  margin:0 0 4px;
}
@media (max-width:767.98px){
  .wci-esc{padding:16px}
  .wci-esc-list .wci-esc-where{min-width:100%}
}

/* ── Concern reporting: the in-app form ─────────────────────────────────────
   Used by _app_concern_form.html, which is mounted twice — once in the
   caregiver app and once in the family app — and must stay ONE
   implementation, for the same reason _sms_right_pane.html does: "anything a
   caregiver can report, a family can report" is only kept true without
   ongoing effort if there is nothing to keep in sync.

   Here rather than in app_base.html's inline <style> because the partial
   renders under two shells and this file is loaded by both. app_base.html
   already supplies .card, .btn, .note, .err, .ok, label.f and the text-input
   rules; these are only what it lacks — textarea, select, choice rows and the
   code display.

   Prefixed .wci-cn- so nothing collides with the public form's .cn-* classes,
   which are a separate implementation for a separate shell. */
.wci-cn-form textarea,
.wci-cn-form select{
  width:100%;
  font-size:16px;            /* below 16px mobile Safari zooms and never unzooms */
  font-family:inherit;
  color:var(--ink);
  padding:12px 14px;
  border:1px solid var(--hairline);
  border-radius:11px;
  background:#fff;
  min-height:var(--wci-tap);
}
.wci-cn-form textarea{min-height:9rem;resize:vertical;line-height:1.6}
.wci-cn-form textarea:focus,
.wci-cn-form select:focus{
  outline:2px solid color-mix(in srgb, var(--navy,#163B5C) 35%, transparent);
  outline-offset:1px;
  border-color:var(--navy);
}

/* Tappable rows rather than bare radios: this is used one-handed, sometimes
   at a front door, and a 13px radio dot is not a touch target. */
.wci-cn-choice{
  display:flex;
  align-items:flex-start;
  gap:11px;
  padding:13px 14px;
  border:1px solid var(--hairline);
  border-radius:11px;
  background:#fff;
  margin-bottom:9px;
  font-size:.95rem;
  line-height:1.45;
  min-height:var(--wci-tap);
}
.wci-cn-choice input{margin-top:.2rem;flex:0 0 auto;width:20px;height:20px}
.wci-cn-choice .sub{
  display:block;
  color:var(--slate);
  font-size:.84rem;
  margin-top:3px;
}

.wci-cn-hint{
  font-size:.84rem;
  color:var(--slate);
  margin:0 0 8px;
  line-height:1.5;
}
.wci-cn-req{color:var(--magenta);font-weight:700}
.wci-cn-contact[hidden]{display:none}

/* Off-screen rather than display:none — some bots skip hidden inputs but fill
   positioned ones. See concerns.HONEYPOT_FIELD. */
.wci-cn-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* The reference and follow-up code, shown exactly once. Monospace and widely
   tracked because it gets copied onto paper; the alphabet already excludes
   0/O and 1/I/L to survive that trip. */
.wci-cn-code{margin-bottom:13px}
.wci-cn-code:last-child{margin-bottom:0}
.wci-cn-code .lbl{
  display:block;
  font-size:.72rem;
  letter-spacing:.6px;
  text-transform:uppercase;
  font-weight:700;
  color:var(--navy);
  opacity:.75;
  margin-bottom:3px;
}
.wci-cn-code .val{
  font-family:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  font-size:1.2rem;
  font-weight:600;
  color:var(--navy);
  letter-spacing:.08em;
  word-break:break-all;
}

/* ── Policy documents ───────────────────────────────────────────────────────
   Styles the BODY of a policy — the templates under
   wci_app/templates/policies/, rendered by policies.render_body().

   Here rather than in either shell's inline <style> because the same body is
   rendered in two places: the caregiver app, where someone signs it, and the
   admin console, where someone reads what they signed. One stylesheet both
   already load means the document cannot look like two different documents.

   Body templates therefore use only these classes plus plain h2/p/ul/li. A
   policy that reaches for its own <style> would fail audit_stray_css.py and
   would not render in the console at all.

   Tokens are the intersection of what app_base.html and admin_base.html both
   declare: --navy, --ink, --slate, --hairline, --well, --magenta. */
.wci-pol h2{
  font-size:1rem;
  color:var(--navy);
  margin:22px 0 8px;
  padding-bottom:4px;
  border-bottom:1px solid var(--hairline);
}
.wci-pol h2:first-child{margin-top:0}
.wci-pol p{
  font-size:.94rem;
  line-height:1.65;
  color:var(--ink);
  margin:0 0 11px;
}
/* The opening statement carries the weight of the whole document, so it is
   sized above the body text rather than being just another paragraph. */
.wci-pol .pol-lede{
  font-size:1rem;
  line-height:1.6;
  color:var(--ink);
  border-left:3px solid var(--magenta);
  padding:2px 0 2px 14px;
  margin-bottom:18px;
}
.wci-pol ul,.wci-pol ol{
  font-size:.94rem;
  line-height:1.6;
  color:var(--ink);
  margin:0 0 12px;
  padding-left:22px;
}
/* Prohibited-conduct items are read as a checklist against your own conduct,
   so they get breathing room rather than being packed tight. */
.wci-pol .pol-list li{margin-bottom:7px}
.wci-pol .pol-note{
  font-size:.88rem;
  color:var(--slate);
  background:var(--well);
  border:1px solid var(--hairline);
  border-radius:10px;
  padding:11px 13px;
  margin:0 0 12px;
}
.wci-pol strong{color:var(--ink)}

/* ── Motion ─────────────────────────────────────────────────────────────────
   Respect the OS setting. Not decorative: motion sensitivity is a real
   accessibility need and this costs nothing. */
@media (prefers-reduced-motion:reduce){
  *,
  *::before,
  *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}
