/* [Organization Name] — Members Portal (rides on site.css tokens) */

/* ===== compact banner ===== */
.ptl-banner .banner__inner{padding-top:clamp(110px,13vw,150px);padding-bottom:clamp(36px,5vw,56px);}
.ptl-banner h1{font-size:clamp(2rem,1.4rem + 2.8vw,3.4rem);}
.ptl-banner p{margin-top:var(--space-sm);font-size:clamp(.98rem,.95rem + .3vw,1.1rem);}

/* ===== pill sub-nav ===== */
.ptlnav{background:var(--paper);border-bottom:1px solid var(--line);}
/* In the installed app the avatar (top-right) already links into the portal, so hide the
   pill sub-nav there for a cleaner, edge-to-edge look. It stays in the browser. */
html.app-mode .ptlnav{display:none;}
/* A portal page with no banner has the tab strip as its first element, and the
   site header floats over the top of the page rather than sitting above it. The
   banner used to be what carried that clearance. */
.ptlnav--top{padding-top:calc(env(safe-area-inset-top,0px) + 76px);}
.ptlnav__wrap{display:flex;align-items:center;gap:var(--space-md);padding-block:10px;flex-wrap:wrap;}
.ptlnav__tabs{display:flex;gap:4px;flex-wrap:wrap;background:var(--cream);border-radius:100px;padding:5px;}
.ptlnav__tabs a{font-family:var(--font-display);font-weight:600;font-size:.86rem;color:var(--muted);padding:.5em 1.05em;border-radius:100px;transition:color .25s,background .25s,transform .25s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.ptlnav__tabs a:hover{color:var(--ink);transform:translateY(-1px);}
.ptlnav__tabs a.on{background:var(--ink);color:var(--paper);box-shadow:var(--shadow-sm);}
.ptlnav__me{margin-left:auto;display:flex;align-items:center;gap:10px;}
.ptlnav__out{font-family:var(--font-display);font-weight:600;font-size:.84rem;color:var(--muted);transition:color .2s;}
.ptlnav__out:hover{color:var(--cyan-deep);}
.ptlnav__tabs .outtab{display:none;}
/* mobile: one app-style scrollable rail — no wrapping, no orphaned sign-out band */
@media(max-width:700px){
  .ptlnav__wrap{flex-wrap:nowrap;padding-block:12px;}
  .ptlnav__me{display:none;}
  .ptlnav__tabs{flex:1;min-width:0;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;touch-action:pan-x;}
  .ptlnav__tabs::-webkit-scrollbar{display:none;}
  .ptlnav__tabs a{flex-shrink:0;white-space:nowrap;padding:.68em 1.15em;}
  .ptlnav__tabs .outtab{display:inline-block;color:var(--muted);}
  /* tuck the first content section closer to the rail */
  .ptlnav+.section,.ptlnav+section{padding-top:clamp(28px,7vw,44px);}
  .pdirbar{margin-bottom:var(--space-lg);}
  .pdoccat:first-of-type{margin-top:0;}
  .ptl-banner .eyebrow{font-size:.72rem;letter-spacing:.15em;}
}

/* ===== avatars ===== */
.pavatar{width:36px;height:36px;border-radius:50%;background:linear-gradient(140deg,var(--cyan),var(--cyan-deep));color:#fff;font-family:var(--font-display);font-size:.74rem;font-weight:800;display:inline-grid;place-items:center;overflow:hidden;flex-shrink:0;box-shadow:var(--shadow-sm);transition:transform .35s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pavatar img{width:100%;height:100%;object-fit:cover;}
.pavatar--lg{width:82px;height:82px;font-size:1.35rem;border:3px solid var(--paper);box-shadow:var(--shadow-md);}
.pavatar--md{width:44px;height:44px;font-size:.85rem;}

/* ===== light form fields (site .field is tuned for dark frosted cards) ===== */
.pfield{display:grid;gap:6px;margin-bottom:var(--space-md);}
.pfield label{font-family:var(--font-display);font-weight:700;font-size:.82rem;color:var(--ink);}
.pfield .help{font-weight:500;color:var(--muted);font-size:.78rem;}
.pfield input[type=text],.pfield input[type=email],.pfield input[type=tel],.pfield input[type=password],.pfield textarea,.pfield select{font:inherit;font-size:.95rem;width:100%;background:var(--paper);border:1.5px solid var(--line);border-radius:14px;padding:.75em .95em;color:var(--ink);transition:border-color .25s,box-shadow .25s;}
.pfield textarea{min-height:104px;resize:vertical;line-height:1.55;}
.pfield input:focus,.pfield textarea:focus,.pfield select:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 4px color-mix(in srgb,var(--cyan) 16%,transparent);}
.pcheck{display:flex;align-items:center;gap:9px;font-family:var(--font-display);font-weight:600;font-size:.9rem;color:var(--ink);margin-bottom:10px;cursor:pointer;}
.pcheck input{width:17px;height:17px;accent-color:var(--cyan);}
.pnote{border-radius:var(--radius-card);padding:13px 17px;font-family:var(--font-display);font-weight:600;font-size:.92rem;margin-bottom:var(--space-lg);animation:pnoteIn .45s var(--ease-out,cubic-bezier(.22,1,.36,1)) both;}
@keyframes pnoteIn{from{opacity:0;transform:translateY(-8px);}}
.pnote.ok{background:color-mix(in srgb,var(--cyan) 12%,var(--snow));color:var(--cyan-deep);border:1px solid color-mix(in srgb,var(--cyan) 30%,var(--snow));}
.pnote.err{background:#fae7e3;color:#9a3412;border:1px solid #f3cfc6;}

/* ===== panels on cream sections ===== */
.ppanel{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm);overflow:hidden;transition:box-shadow .4s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.ppanel:hover{box-shadow:var(--shadow-md);}
.ppanel__h{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md);padding:18px 22px;border-bottom:1px solid var(--line);flex-wrap:wrap;}
.ppanel__h h2{font-size:1.15rem;}
.ppanel__b{padding:20px 22px;}

/* ===== news / announcements ===== */
.pnews{display:grid;gap:var(--space-md);}
.pnews__it{position:relative;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:20px 24px 20px 28px;overflow:hidden;transition:transform .45s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .45s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pnews__it::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(var(--cyan),var(--cyan-deep));transition:width .35s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pnews__it:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);}
.pnews__it:hover::before{width:7px;}
.pnews__it time{font-family:var(--font-serif);font-style:italic;font-size:1rem;color:var(--cyan-deep);}
.pnews__it h3{font-size:1.15rem;margin-top:2px;}
.pnews__it p{margin-top:8px;color:var(--ink-soft);font-size:.95rem;white-space:pre-line;}

/* ===== directory ===== */
.pdirbar{display:flex;justify-content:center;margin-bottom:var(--space-xl);}
.pdirbar input{max-width:420px;width:100%;font:inherit;font-size:1rem;background:var(--paper);border:1.5px solid var(--line);border-radius:100px;padding:.85em 1.4em;box-shadow:var(--shadow-sm);transition:border-color .25s,box-shadow .25s;}
.pdirbar input:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 4px color-mix(in srgb,var(--cyan) 15%,transparent);}
.pdirgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(235px,1fr));gap:var(--space-lg);}
.pmcard{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:26px 20px 22px;text-align:center;transition:transform .5s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .5s var(--ease-out,cubic-bezier(.22,1,.36,1)),border-color .3s;}
.pmcard:hover{transform:translateY(-6px);box-shadow:var(--shadow-md);border-color:color-mix(in srgb,var(--cyan) 35%,var(--line));}
.pmcard:hover .pavatar{transform:scale(1.08) rotate(2deg);}
.pmcard .pavatar{margin:0 auto 12px;}
.pmcard h3{font-size:1.05rem;}
.pmcard .fam{font-family:var(--font-serif);font-style:italic;color:var(--cyan-deep);font-size:.95rem;margin-top:1px;}
.pmcard ul{list-style:none;padding:0;margin:12px 0 0;font-size:.85rem;display:grid;gap:4px;}
.pmcard a{color:var(--muted);overflow-wrap:anywhere;transition:color .2s;}
.pmcard a:hover{color:var(--cyan-deep);}

/* ===== prayer wall ===== */
.pwall{display:grid;gap:var(--space-lg);max-width:760px;margin-inline:auto;}
.pw{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:22px 24px;transition:transform .45s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .45s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pw:hover{transform:translateY(-2px);box-shadow:var(--shadow-md);}
.pw__meta{display:flex;align-items:center;gap:12px;margin-bottom:12px;}
.pw__who strong{display:block;font-family:var(--font-display);font-size:.95rem;line-height:1.2;color:var(--ink);}
.pw__who time{font-family:var(--font-serif);font-style:italic;font-size:.88rem;color:var(--muted);}
.pw__txt{white-space:pre-line;font-size:1rem;color:var(--ink-soft);}
.pw__upd{margin-top:12px;border-left:3px solid color-mix(in srgb,var(--cyan) 40%,var(--line));padding:8px 14px;font-size:.92rem;background:var(--cream);border-radius:0 12px 12px 0;color:var(--ink-soft);}
.pw__upd time{display:block;font-family:var(--font-display);font-size:.68rem;color:var(--cyan-deep);font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:2px;}
.pw__foot{display:flex;align-items:center;gap:10px;margin-top:16px;flex-wrap:wrap;}
.pw__btn{display:inline-flex;align-items:center;gap:.5em;border:1.5px solid var(--line);background:var(--paper);border-radius:100px;padding:.5em 1.1em;font-family:var(--font-display);font-weight:700;font-size:.84rem;color:var(--ink);cursor:pointer;transition:border-color .25s,background .25s,transform .25s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .25s;}
.pw__btn:hover{border-color:var(--cyan);transform:translateY(-2px);box-shadow:var(--shadow-sm);}
.pw__btn:active{transform:scale(.94);transition-duration:.08s;}
.pw__btn.did{background:color-mix(in srgb,var(--cyan) 12%,var(--snow));border-color:color-mix(in srgb,var(--cyan) 45%,var(--line));color:var(--cyan-deep);cursor:default;animation:prayPop .5s var(--ease-out,cubic-bezier(.22,1,.36,1));}
@keyframes prayPop{0%{transform:scale(.85);}55%{transform:scale(1.08);}100%{transform:scale(1);}}
.pw__own{margin-left:auto;display:flex;gap:10px;align-items:center;}
details.pw__more summary{cursor:pointer;font-family:var(--font-display);font-weight:700;font-size:.84rem;color:var(--cyan-deep);list-style:none;transition:color .2s;}
details.pw__more summary:hover{color:var(--ink);}
details.pw__more summary::-webkit-details-marker{display:none;}
details.pw__more[open]{margin-top:6px;}
.pw__del{border:0;background:none;font-family:var(--font-display);font-weight:700;font-size:.84rem;color:#a3302d;cursor:pointer;opacity:.75;transition:opacity .2s;}
.pw__del:hover{opacity:1;}
.pw--held{border-style:dashed;border-color:color-mix(in srgb,var(--cyan) 45%,var(--line));background:color-mix(in srgb,var(--cyan) 4%,var(--paper));}
.pw__heldtag{font-family:var(--font-display);font-weight:600;font-size:.78rem;color:var(--cyan-deep);background:color-mix(in srgb,var(--cyan) 10%,var(--snow));border-radius:10px;padding:8px 12px;margin-bottom:14px;}
.pw__report{border:0;background:none;font-family:var(--font-display);font-weight:600;font-size:.78rem;color:var(--muted);cursor:pointer;opacity:.7;transition:opacity .2s,color .2s;}
.pw__report:hover{opacity:1;color:#a3302d;}
.pw__report.is-done{cursor:default;color:var(--cyan-deep);opacity:.9;}
/* composer */
.pcomposer{max-width:760px;margin-inline:auto;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(20px,3vw,30px);box-shadow:var(--shadow-sm);}

/* ===== documents ===== */
.pdoccat{font-family:var(--font-serif);font-style:italic;font-size:1.3rem;color:var(--cyan-deep);margin:var(--space-xl) 0 var(--space-md);}
.pdocs{display:grid;gap:var(--space-sm);}
.pdoc{display:flex;align-items:center;gap:16px;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius-sm);padding:15px 18px;color:var(--ink);transition:transform .4s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .4s var(--ease-out,cubic-bezier(.22,1,.36,1)),border-color .3s;}
.pdoc:hover{transform:translateX(6px);box-shadow:var(--shadow-md);border-color:color-mix(in srgb,var(--cyan) 35%,var(--line));}
.pdoc__ic{width:42px;height:42px;flex-shrink:0;display:grid;place-items:center;border-radius:12px;background:color-mix(in srgb,var(--cyan) 11%,var(--snow));color:var(--cyan-deep);transition:transform .35s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pdoc:hover .pdoc__ic{transform:scale(1.1) rotate(-3deg);}
.pdoc__ic svg{width:21px;height:21px;}
.pdoc strong{display:block;font-family:var(--font-display);font-size:.95rem;line-height:1.3;}
.pdoc small{color:var(--muted);font-size:.78rem;}
.pdoc__dl{margin-left:auto;font-family:var(--font-display);font-weight:700;font-size:.84rem;color:var(--cyan-deep);white-space:nowrap;transition:transform .3s var(--ease-out,cubic-bezier(.22,1,.36,1));}
.pdoc:hover .pdoc__dl{transform:translateY(2px);}

/* ===== sign-in gate (inside a dark frosted banner card) ===== */
.gate-banner .banner__inner{padding-top:clamp(120px,15vw,180px);padding-bottom:clamp(56px,8vw,96px);max-width:none;display:flex;justify-content:center;}
.gate-card{width:100%;max-width:480px;}
.gate__tabs{display:flex;gap:6px;background:rgba(255,255,255,.1);border-radius:100px;padding:5px;margin:var(--space-lg) 0;}
.gate__tab{flex:1;border:0;background:transparent;font-family:var(--font-display);font-weight:700;font-size:.88rem;color:rgba(244,238,225,.75);padding:.55em 1em;border-radius:100px;cursor:pointer;white-space:nowrap;transition:background .25s,color .25s;}
@media(max-width:480px){.gate__tab{font-size:.82rem;padding:.62em .5em;}}
.gate__tab:hover{color:#fff;}
.gate__tab.on{background:var(--cyan);color:#fff;box-shadow:0 2px 12px rgba(160,138,111,.4);}
.gate__pane{animation:gateIn .4s var(--ease-out,cubic-bezier(.22,1,.36,1)) both;}
@keyframes gateIn{from{opacity:0;transform:translateY(10px);}}
.gate__hint{font-size:.8rem;color:rgba(244,238,225,.65);margin-top:14px;line-height:1.55;}
.gate__hint a{color:var(--cyan-bright,#d9c4a8);}
.gate-card .pnote.ok{background:rgba(160,138,111,.22);color:#eae3da;border-color:rgba(217,196,168,.4);}
.gate-card .pnote.err{background:rgba(163,48,45,.24);color:#ffd9d2;border-color:rgba(255,150,140,.35);}
.gate-card .btn{width:100%;justify-content:center;}

/* ===== reduced motion ===== */
@media(prefers-reduced-motion:reduce){
  .pmcard,.pw,.pdoc,.pnews__it,.pw__btn,.pavatar,.pdoc__ic,.pdoc__dl{transition:none !important;animation:none !important;}
}

/* ------------------------------------------------------------ dark palettes
   The members' area rides on site.css tokens, which already follow whichever
   theme is picked, so this only has to catch the handful of literals that
   cannot follow a variable — a hard-coded pink error note stays pink however
   dark everything around it gets.

   Two selectors on every rule, on purpose. html.dark is the old dark MODE,
   which nothing sets today but which is left working in case it comes back.
   .ath-compline is dark arriving as a theme somebody chose. Writing both here
   rather than in two blocks means a fix to one can never miss the other. */
html.dark .pnote.err,
html.app-mode body.ath-compline .pnote.err{background:color-mix(in srgb,#c0392b 22%,var(--cream));color:#ffb4aa;border-color:rgba(255,150,140,.3);}
html.dark .pnote.ok,
html.app-mode body.ath-compline .pnote.ok{background:color-mix(in srgb,#1d9e75 20%,var(--cream));color:#8ee3c4;border-color:rgba(140,227,196,.28);}
html.dark .ppanel,html.dark .pcard,
html.app-mode body.ath-compline .ppanel,html.app-mode body.ath-compline .pcard{background:var(--cream);border-color:var(--line);}
html.dark input,html.dark textarea,html.dark select,
html.app-mode body.ath-compline input,html.app-mode body.ath-compline textarea,html.app-mode body.ath-compline select{background:var(--cream-2);color:var(--ink);border-color:var(--line);}
html.dark input::placeholder,html.dark textarea::placeholder,
html.app-mode body.ath-compline input::placeholder,html.app-mode body.ath-compline textarea::placeholder{color:var(--muted);}
html.dark input[type=date],html.dark input[type=time],
html.app-mode body.ath-compline input[type=date],html.app-mode body.ath-compline input[type=time]{color-scheme:dark;}

/* The group rota screen. Its cards were the last panels in here still painting themselves
   #fff, which in a dark theme produced the worst of both: a white card carrying inputs that
   had already followed the palette down, so the fields read as dark holes punched in paper.
   Same two selectors and the same surfaces the rest of the members' area uses. */
html.dark .rotr__w,html.dark .rote__e,html.dark .rotp,html.dark .rotm__p,html.dark .rotq,
html.app-mode body.ath-compline .rotr__w,html.app-mode body.ath-compline .rote__e,html.app-mode body.ath-compline .rotp,html.app-mode body.ath-compline .rotm__p,html.app-mode body.ath-compline .rotq{background:var(--cream);border-color:var(--line);}
html.dark .rotr__w.is-rare,html.dark .rote__e.is-new,
html.app-mode body.ath-compline .rotr__w.is-rare,html.app-mode body.ath-compline .rote__e.is-new{background:var(--cream-2);}
html.dark .rotr__n,
html.app-mode body.ath-compline .rotr__n{background:var(--cyan);color:#17120c;}
html.dark .rotr__w.is-rare .rotr__n,
html.app-mode body.ath-compline .rotr__w.is-rare .rotr__n{background:color-mix(in srgb,var(--ink) 16%,transparent);color:var(--muted);}
html.dark .rotp__r + .rotp__r,
html.app-mode body.ath-compline .rotp__r + .rotp__r{border-top-color:var(--line);}
html.dark .rotp__r.is-off,html.dark .rotp__r.is-extra,
html.app-mode body.ath-compline .rotp__r.is-off,html.app-mode body.ath-compline .rotp__r.is-extra{background:var(--cream-2);}
html.dark .rotp__d,
html.app-mode body.ath-compline .rotp__d{color:var(--ink);}
html.dark .rotp__w,
html.app-mode body.ath-compline .rotp__w{background:var(--cream-2);color:var(--muted);}
html.dark .rotp__clear button:hover,
html.app-mode body.ath-compline .rotp__clear button:hover{color:var(--ink);border-color:var(--ink);}
html.dark .rota__other summary:hover,
html.app-mode body.ath-compline .rota__other summary:hover{color:var(--ink);}
/* The prayer wall's remove/report links are a fixed red that only reads on a
   light panel. */
html.dark .pw__del,html.dark .pw__report:hover,
html.app-mode body.ath-compline .pw__del,html.app-mode body.ath-compline .pw__report:hover{color:#ff9b95;}
/* ================================================================ messages
   Built to the references Hunter sent: pill rows rather than a hairline list,
   avatar clusters standing in for "who is in this", pinned people as faces
   across the top, and a corner + instead of a form left open on the screen.

   Everything keys off the theme tokens, so it follows all eight palettes with
   no per-theme rules. Two exceptions, both deliberate:
     --msgme / --msgmeink   set on .msgwrap when somebody has chosen their own
                            bubble color, so one person's choice is scoped to
                            their own screen rather than to the stylesheet
     --avink                the accent pulled 30% toward the ink, because the
                            accent's own deep shade is not dark enough on the
                            pale tint the avatars sit on — it measured 3.88:1
                            in Kashmir, short of AA for text that small

   Motion: a small spring, about 3% past the mark and back, which is roughly
   what iOS uses. Enough to feel placed rather than pasted, and far enough
   short of a bounce that it will not feel like a toy in six months. All of it
   is off under prefers-reduced-motion, at the bottom of this file. */
body{
  --avink:color-mix(in srgb,var(--aacd,var(--cyan-deep)) 70%,var(--ai,var(--ink)));
  /* Leaving a conversation is the one destructive thing on these screens, and
     it wants to look it. The site's red measured 2.89:1 on Compline's charcoal
     card — legible on paper, not on near-black — so the dark theme takes a
     lighter one. 7.76:1 there, 5.29:1 on the light themes. */
  --msgdanger:#c0392b;
  --msgspring:linear(0,.11 3.6%,.4 8.9%,.83 15.6%,1.01 19.6%,1.05 22.6%,1.03 27.8%,1 32.8%,.999 40%,1);
}
.msgwrap{max-width:720px;margin-inline:auto;position:relative;}

/* The [hidden] attribute is a UA rule (display:none) and ANY author rule that
   sets display beats it. This has now bitten three separate elements on this
   site — .applive, .appcontinue, .msghits — each time as "the thing that will
   not stay hidden", each time needing its own one-line fix. So it is fixed
   once, for everything inside a messaging screen, rather than a fourth time. */
.msgwrap [hidden]{display:none !important;}

/* The four conversation backgrounds.

   These used to paint a rounded panel behind the bubbles, which read as a box
   sitting on the screen rather than as the screen. They now take the whole
   surface — html, so it covers the safe areas and anything that overscrolls
   past the edge, not just the element the feed happens to occupy. */
/* background-color as well as the gradient, deliberately. A gradient is a
   background-IMAGE: if it never paints there is nothing underneath, and any
   check that walks the DOM looking for the color behind some text finds
   nothing and has to guess. Naming the color fixes both. */
/* The background-color is the gradient's FIRST stop, not its last.

   It is two things at once: the fallback if the gradient never paints, and the
   color the status-bar corrector reads at the top of the document. Naming the
   bottom stop meant the strip went navy while the top of the screen was teal —
   a hard line across the top of the app. The top stop is what is painted at
   y=0, so the top stop is what gets named. */
/* no-repeat is load-bearing. These gradients are background-attachment:fixed,
   which sizes them to the VIEWPORT rather than to the element — so on a
   conversation taller than one screen the browser tiled it, and the gradient
   visibly restarted every screenful. Measured on a real phone: a seam every
   958 device pixels, which is exactly 100vh at 3x. */
html.msgbg-soft, html.msgbg-soft body{
  background-color:var(--aicobg,var(--cream-2));
  background-image:linear-gradient(170deg,var(--aicobg,var(--cream-2)),var(--ab,var(--paper)) 58%);
  background-attachment:fixed;background-repeat:no-repeat}
html.msgbg-paper, html.msgbg-paper body{background-color:var(--asurf,var(--cream));}
html.msgbg-deep, html.msgbg-deep body{
  background-color:var(--ac1,var(--cyan-deep));
  background-image:linear-gradient(170deg,var(--ac1,var(--cyan-deep)),var(--ac2,var(--navy)));
  background-attachment:fixed;background-repeat:no-repeat}

/* the composer sits on the page, so it has to stop being opaque paper */
html.msgbg-soft .msgcomp,html.msgbg-paper .msgcomp,html.msgbg-deep .msgcomp{background:transparent;}
html.msgbg-soft .msghead,html.msgbg-paper .msghead,html.msgbg-deep .msghead{background:transparent;}

/* Deep is dark whatever the theme, so everything on it has to be light.

   These first said .msgb--them, which is a class from the mock-up and does not
   exist in the app — an incoming bubble is just .msgb. Every rule in this
   block silently matched nothing, and the sender's name sat pale blue on white
   paper at 1.24:1. Found by sweeping this background rather than by reading. */
html.msgbg-deep .msgb:not(.msgb--me){background:rgba(0,0,0,.42);border-color:rgba(255,255,255,.14);color:#fff;}
html.msgbg-deep .msgb:not(.msgb--me) .msgb__who{color:#dfd6cc;}
html.msgbg-deep .msgday,html.msgbg-deep .msgsys,html.msgbg-deep .msghead__t small,
html.msgbg-deep .msgearlier a{color:rgba(255,255,255,.84);}
html.msgbg-deep .msghead__t b,html.msgbg-deep .msgbar__t{color:#fff;}
html.msgbg-deep .msgback{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.22);color:#fff;}
html.msgbg-deep .msgcomp{border-top-color:rgba(255,255,255,.18);}
html.msgbg-deep .msgcomp textarea{background:rgba(255,255,255,.12);color:#fff;box-shadow:none;}
html.msgbg-deep .msgcomp textarea::placeholder{color:rgba(255,255,255,.66);}
html.msgbg-deep .msgclip,html.msgbg-deep .msgclock{background:rgba(255,255,255,.13);color:#fff;}
html.msgbg-deep .msgearlier a{background:rgba(255,255,255,.13);box-shadow:none;}
/* A 16% white chip is barely a tint over a warm gradient — white initials on
   it measured 3.84:1 in Sunset. Darkened to match the bubbles, which puts the
   initials on the same footing everywhere. */
html.msgbg-deep .msgline__av,html.msgbg-deep .msgav span{background:rgba(0,0,0,.42);color:#fff;
  box-shadow:0 0 0 2.5px transparent;}
/* the pill keeps its own surface on the deep background rather than borrowing
   the page's, so the count on it stays readable */
html.msgbg-deep .msgbr i{background:#251f19;color:#f5f3f1;
  box-shadow:0 0 0 2px rgba(0,0,0,.25),inset 0 0 0 1px rgba(255,255,255,.18);}
html.msgbg-deep .msgbr i.is-mine{box-shadow:0 0 0 2px rgba(0,0,0,.25),inset 0 0 0 1.5px var(--aac,var(--cyan));}
html.msgbg-deep .msgbr u{color:rgba(255,255,255,.72);}
html.msgbg-deep .msgfeed{scrollbar-color:rgba(255,255,255,.4) transparent;}

/* ------------------------------------------------------------------ avatars
   Overlap far enough to read as one group, not so far that the initials under
   it are covered — at 34px an 8px bite leaves every letter whole. */
.msgav{display:inline-flex;flex-direction:row-reverse;align-items:center;flex:none;}
.msgav span{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  font-family:var(--font-display);font-weight:700;font-size:.76rem;
  background:var(--aicobg,var(--cream-2));color:var(--avink);
  box-shadow:0 0 0 2.5px var(--arow,var(--paper));margin-right:-8px;overflow:hidden;}
.msgav span:first-child{margin-right:0;}
.msgav img{width:100%;height:100%;object-fit:cover;}
.msgav--lg span{width:46px;height:46px;font-size:.94rem;margin-right:-11px;}
.msgav--more{font-size:.68rem !important;letter-spacing:-.02em;}
.msgav--pic span{margin-right:0;}
.msgav__one{width:38px;height:38px;border-radius:50%;flex:none;display:grid;place-items:center;overflow:hidden;
  font-family:var(--font-display);font-weight:700;font-size:.82rem;
  background:var(--aicobg,var(--cream-2));color:var(--avink);}
.msgav__one img{width:100%;height:100%;object-fit:cover;}
.msgav__one--add{background:var(--asurf,var(--cream));color:var(--aacd,var(--cyan-deep));font-size:1.2rem;}

/* -------------------------------------------------------------- the inbox */
/* The + sits in the top right, where it was — the floating profile avatar that
   used to be over it is gone from these screens now, so the corner is free. */
.msgtop{display:flex;align-items:center;justify-content:space-between;gap:13px;margin-bottom:var(--space-md);}
.msgtop__h{font-family:var(--font-display);font-size:1.28rem;font-weight:700;letter-spacing:-.02em;
  color:var(--ai,var(--ink));margin:0;}
.msgnew{width:42px;height:42px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--aac,var(--cyan));color:var(--aacink,#fff);text-decoration:none;
  box-shadow:0 6px 18px var(--aglow,rgba(160,138,111,.35));
  transition:transform .24s var(--msgspring);}
.msgnew:active{transform:scale(.9);}
.msgnew svg{width:21px;height:21px;}

.msglab{display:flex;align-items:center;justify-content:space-between;gap:10px;
  font-size:.64rem;letter-spacing:.16em;text-transform:uppercase;font-weight:700;
  color:var(--am,var(--muted));margin:var(--space-lg) 0 10px 4px;}
.msglab--flat{margin-top:var(--space-md);}
.msgall{border:0;background:none;font:inherit;font-size:.68rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--aacd,var(--cyan-deep));cursor:pointer;padding:2px 4px;}

.msgpins{display:flex;gap:6px;overflow-x:auto;padding:2px 0 6px;scrollbar-width:none;}
.msgpins::-webkit-scrollbar{display:none;}
/* Three overlapped 46px faces are 116px wide; the tile was 86px, so the
   left-most face was being cut off by the edge of the strip. Size the faces to
   the tile rather than the other way round — the names underneath are what
   makes a pin identifiable anyway. */
.msgpin{flex:none;width:100px;display:flex;flex-direction:column;align-items:center;gap:7px;
  text-decoration:none;position:relative;}
.msgpin .msgav--lg span{width:38px;height:38px;font-size:.8rem;margin-right:-9px;}
.msgpin .msgav--lg span:first-child{margin-right:0;}
.msgpin b{font-size:.72rem;font-weight:600;color:var(--ai,var(--ink));text-align:center;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;}
.msgpin__n{position:absolute;top:-2px;right:20px;min-width:19px;height:19px;padding:0 5px;
  border-radius:100px;display:grid;place-items:center;font-style:normal;font-size:.66rem;font-weight:700;
  background:var(--aac,var(--cyan));color:var(--aacink,#fff);box-shadow:0 0 0 2.5px var(--ab,var(--paper));}

.msglist{display:flex;flex-direction:column;gap:8px;}
.msgrow{display:flex;align-items:center;gap:13px;padding:11px 16px 11px 12px;border-radius:100px;
  text-decoration:none;color:var(--ai,var(--ink));
  background:var(--arow,var(--paper));box-shadow:inset 0 0 0 1px var(--aline,var(--line));
  transition:transform .3s var(--msgspring);}
.msgrow:active{transform:scale(.975);}
.msgrow.is-new{background:var(--asurf,var(--cream));
  box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--aac,var(--cyan)) 34%,transparent);}
.msgrow__t{flex:1;min-width:0;}
.msgrow__t b{display:block;font-family:var(--font-display);font-weight:600;font-size:.96rem;line-height:1.2;}
.msgrow__t small{display:block;color:var(--am,var(--muted));font-size:.82rem;margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.msgrow__meta{flex:none;display:flex;align-items:center;gap:7px;}
.msgrow__w{color:var(--am,var(--muted));font-size:.73rem;}
.msgrow__mute{width:15px;height:15px;color:var(--am,var(--muted));display:block;}
.msgrow__mute svg{width:15px;height:15px;}
.msgrow__n{min-width:20px;height:20px;padding:0 6px;border-radius:100px;display:grid;place-items:center;
  background:var(--aac,var(--cyan));color:var(--aacink,#fff);font-size:.68rem;font-weight:700;}
/* muted still counts, it just stops shouting */
.msgrow__n--quiet{background:var(--aline,var(--line));color:var(--ai,var(--ink));}
.msgempty{color:var(--am,var(--muted));text-align:center;padding:var(--space-2xl) 0;}
.msgearlier{text-align:center;margin:0 0 var(--space-md);}
.msgearlier a{font-size:.78rem;font-weight:700;letter-spacing:.04em;color:var(--aacd,var(--cyan-deep));
  text-decoration:none;padding:7px 15px;border-radius:100px;background:var(--asurf,var(--cream));
  box-shadow:inset 0 0 0 1px var(--aline,var(--line));display:inline-block;}

/* ------------------------------------------------------- a new conversation */
.msgbar{display:flex;align-items:center;gap:12px;margin-bottom:var(--space-md);}
.msgbar__t{font-family:var(--font-display);font-size:1.06rem;color:var(--ai,var(--ink));}
.msgback{width:40px;height:40px;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--arow,var(--paper));border:1px solid var(--aline,var(--line));
  color:var(--ai,var(--ink));font-size:1.1rem;text-decoration:none;transition:background .18s;}
.msgback:hover{background:var(--aicobg,var(--cream-2));}
.msgback--r{margin-left:auto;}
.msgback svg{width:19px;height:19px;}

.msgnewform{display:flex;flex-direction:column;min-height:56vh;}
.msgto{display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding:12px 4px 13px;
  border-bottom:1px solid var(--aline,var(--line));}
.msgto__l{color:var(--am,var(--muted));font-size:.86rem;}
.msgto__picked{display:contents;}
.msgto__i{flex:1;min-width:130px;border:0;background:transparent;font:inherit;font-size:16px;
  color:var(--ai,var(--ink));outline:none;padding:4px 0;}
.msgto__i::placeholder{color:var(--am,var(--muted));}
.msgchip{display:inline-flex;align-items:center;gap:6px;padding:4px 7px 4px 4px;border-radius:100px;
  background:var(--aicobg,var(--cream-2));color:var(--ai,var(--ink));font-size:.84rem;font-weight:600;
  animation:msgPop .3s var(--msgspring) both;}
.msgchip__av{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;
  background:var(--arow,var(--paper));color:var(--avink);font-size:.62rem;font-weight:700;}
.msgchip button{width:19px;height:19px;border-radius:50%;border:0;cursor:pointer;line-height:1;
  background:color-mix(in srgb,var(--ai,var(--ink)) 12%,transparent);color:var(--ai,var(--ink));font-size:.78rem;}
@keyframes msgPop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}

.msghits{display:flex;flex-direction:column;gap:2px;margin-top:8px;}
.msghits[hidden]{display:none;}
.msghits--all{max-height:44vh;overflow-y:auto;}
.msghit{display:flex;align-items:center;gap:11px;width:100%;padding:8px 10px;border:0;border-radius:15px;
  background:none;font:inherit;text-align:left;cursor:pointer;color:var(--ai,var(--ink));
  transition:background .16s;}
.msghit:hover{background:var(--asurf,var(--cream));}
.msghit__n{flex:1;min-width:0;font-size:.92rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.msghit i{font-style:normal;font-size:.64rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--aacd,var(--cyan-deep));background:var(--aicobg,var(--cream-2));padding:3px 8px;border-radius:100px;}

.msgrule{font-size:.86rem;color:var(--am,var(--muted));line-height:1.5;margin:var(--space-md) 0;
  padding:12px 15px;border-radius:16px;background:var(--aicobg,var(--cream-2));}
.msgrule--stop{background:color-mix(in srgb,#c0392b 12%,var(--cream-2));color:var(--ai,var(--ink));font-weight:600;}

/* ------------------------------------------------------- one conversation */
.msghead{display:flex;align-items:center;gap:12px;padding:2px 0 var(--space-md);
  border-bottom:1px solid var(--aline,var(--line));margin-bottom:2px;}
.msghead__t{flex:1;min-width:0;}
.msghead__t b{display:block;font-family:var(--font-display);font-weight:600;font-size:1.06rem;
  color:var(--ai,var(--ink));overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.msghead__t small{color:var(--am,var(--muted));font-size:.8rem;
  display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* The header cluster was at the large size and, with the title beside it, left
   so little room that "4 people · group conversation" wrapped onto a second
   line and pushed the name up. It only has to say who; it does not have to be
   the biggest thing on the row. */
.msghead .msgav--lg span{width:34px;height:34px;font-size:.76rem;margin-right:-8px;}

.msgfeed{display:flex;flex-direction:column;gap:0;padding:var(--space-md) 0 var(--space-lg);
  max-height:min(56vh,540px);overflow-y:auto;overscroll-behavior:none;position:relative;}
.msgday{align-self:center;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--am,var(--muted));margin:var(--space-lg) 0 var(--space-sm);}
.msgsys{align-self:center;font-size:.76rem;color:var(--am,var(--muted));text-align:center;
  margin:var(--space-md) 0;max-width:80%;}

.msgline{display:flex;align-items:flex-end;gap:9px;}
.msgline--me{flex-direction:row-reverse;}
.msgline__av{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  font-size:.66rem;font-weight:700;font-family:var(--font-display);overflow:hidden;
  background:var(--aicobg,var(--cream-2));color:var(--avink);}
.msgline__av img{width:100%;height:100%;object-fit:cover;}
.msgline__av--gap{visibility:hidden;}

/* One big radius, and only the corner meeting the next bubble in a run is
   pulled in. Tails were tried and dropped — at this radius a tail reads as a
   decoration stuck onto the shape rather than part of it. */
/* Selection off, and the native long-press callout with it. A hold is the
   gesture that opens the message menu, and it cannot be both. Copy lives in
   that menu, so nothing is lost. */
.msgb{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;
  position:relative;max-width:min(76%,460px);padding:10px 15px;border-radius:22px;
  background:var(--arow,var(--paper));border:1px solid var(--aline,var(--line));color:var(--ai,var(--ink));
  cursor:default;}
/* The entrance belongs to a message ARRIVING, not to forty of them being
   drawn. Running it on the whole backlog meant every open animated the entire
   conversation at once, which is exactly the jank it was meant to avoid. Only
   bubbles the poll inserts get it. */
.msgline--in > .msgb{animation:msgIn .42s var(--msgspring) both;}
.msgb--me{background:var(--msgme,color-mix(in srgb,var(--aac,var(--cyan)) 15%,var(--paper)));
  border-color:var(--msgme,color-mix(in srgb,var(--aac,var(--cyan)) 28%,var(--aline,var(--line))));
  color:var(--msgmeink,var(--ai,var(--ink)));}
.msgline:not(.msgline--run) .msgb:not(.msgb--me){border-bottom-left-radius:9px;}
.msgline--me:not(.msgline--run) .msgb{border-bottom-right-radius:9px;}
@keyframes msgIn{from{opacity:0;transform:translateY(9px) scale(.965)}to{opacity:1;transform:none}}
.msgb__who{display:block;font-size:.76rem;font-weight:700;color:var(--aacd,var(--cyan-deep));margin-bottom:2px;}
.msgb--me .msgb__who{color:inherit;opacity:.82;}
.msgb__x{display:block;font-size:.95rem;line-height:1.45;white-space:pre-wrap;word-break:break-word;}
.msgb__t{display:block;font-size:.67rem;opacity:.62;margin-top:3px;}
.msgb.has-react{margin-bottom:14px;}

/* photos and videos, and the fact that they will not be here forever */
.msgb__media{display:block;width:min(240px,60vw);border-radius:15px;overflow:hidden;margin:2px 0 4px;}
.msgb__media--img img{display:block;width:100%;height:auto;border-radius:15px;}
video.msgb__media{background:#000;}
.msgb__exp{display:block;font-size:.64rem;opacity:.6;letter-spacing:.02em;}
.msgb__gone{display:block;font-size:.86rem;font-style:italic;opacity:.66;padding:6px 0;}

/* reactions ride the bubble's bottom edge */
.msgbr{position:absolute;right:9px;bottom:-12px;display:flex;gap:3px;}
.msgbr i{display:inline-flex;align-items:center;gap:3px;font-style:normal;font-size:.76rem;padding:2px 7px;
  color:var(--ai,var(--ink));
  border-radius:100px;background:var(--asurf,var(--cream));
  box-shadow:0 0 0 2px var(--ab,var(--paper)),inset 0 0 0 1px var(--aline,var(--line));
  animation:msgPop .34s var(--msgspring) both;}
.msgbr i.is-mine{box-shadow:0 0 0 2px var(--ab,var(--paper)),inset 0 0 0 1.5px var(--aac,var(--cyan));}
.msgbr u{text-decoration:none;font-size:.66rem;font-weight:700;color:var(--am,var(--muted));}

/* the reaction picker */
.msgpick{position:absolute;z-index:6;display:flex;gap:2px;padding:5px;border-radius:100px;
  background:var(--arow,var(--paper));box-shadow:0 10px 28px rgba(0,0,0,.16),inset 0 0 0 1px var(--aline,var(--line));
  animation:msgPop .3s var(--msgspring) both;}
.msgpick[hidden]{display:none;}
.msgpick button{font-size:1.05rem;width:34px;height:34px;display:grid;place-items:center;border:0;
  border-radius:50%;background:none;cursor:pointer;transition:transform .22s var(--msgspring);}
.msgpick button:hover{transform:scale(1.2);}
.msgpick__copy{width:34px;height:34px;color:var(--ai,var(--ink));
  border-left:1px solid var(--aline,var(--line)) !important;margin-left:3px;border-radius:0 100px 100px 0 !important;}
.msgpick__copy svg{width:17px;height:17px;}
.msgpick__copy.is-done{color:var(--aacd,var(--cyan-deep));}
.msgpick__copy.is-done svg{opacity:.35;}
.msgpick__copy.is-done::after{content:"Copied";position:absolute;right:6px;bottom:-19px;font-size:.62rem;
  font-weight:700;color:var(--am,var(--muted));}

/* typing: three dots, staggered, in an otherwise ordinary bubble */
.msgtyping[hidden]{display:none;}
.msgb--typing{display:flex;gap:4px;padding:14px 15px;animation:none;}
.msgb--typing i{width:6px;height:6px;border-radius:50%;background:var(--am,var(--muted));
  animation:msgTyp 1.15s ease-in-out infinite;}
.msgb--typing i:nth-child(2){animation-delay:.16s;}
.msgb--typing i:nth-child(3){animation-delay:.32s;}
@keyframes msgTyp{0%,60%,100%{opacity:.3;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}

/* ---------------------------------------------------------- the composer */
.msgcomp{display:flex;align-items:flex-end;gap:9px;padding-top:12px;
  border-top:1px solid var(--aline,var(--line));}
.msgcomp--new{margin-top:auto;}
.msgcomp textarea{flex:1;resize:none;border:0;border-radius:22px;padding:11px 16px;font:inherit;font-size:16px;
  line-height:1.4;background:var(--asurf,var(--cream));color:var(--ai,var(--ink));
  box-shadow:inset 0 0 0 1px var(--aline,var(--line));max-height:160px;}
.msgcomp textarea::placeholder{color:var(--am,var(--muted));}
.msgclip,.msgclock{width:40px;height:40px;flex:none;display:grid;place-items:center;border-radius:50%;border:0;
  background:var(--asurf,var(--cream));color:var(--aacd,var(--cyan-deep));cursor:pointer;
  transition:transform .24s var(--msgspring);}
.msgclip:active,.msgclock:active{transform:scale(.9);}
.msgclip svg,.msgclock svg{width:19px;height:19px;}
.msgsend{width:40px;height:40px;flex:none;display:grid;place-items:center;border-radius:50%;border:0;
  background:var(--aac,var(--cyan));color:var(--aacink,#fff);cursor:pointer;
  transition:transform .24s var(--msgspring);}
.msgsend:active{transform:scale(.88);}
.msgsend svg{width:19px;height:19px;}
.msgpicked{font-size:.76rem;color:var(--am,var(--muted));margin:8px 0 0 52px;}
.msgpicked[hidden]{display:none;}
.msgquiet{font-size:.78rem;color:var(--am,var(--muted));text-align:center;margin:0 0 8px;}

.msgsched{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;padding:13px 15px;
  border-radius:var(--radius-card);background:var(--asurf,var(--cream));
  box-shadow:inset 0 0 0 1px var(--aline,var(--line));animation:msgIn .34s var(--msgspring) both;}
.msgsched[hidden]{display:none;}
.msgsched label{font-size:.82rem;font-weight:600;color:var(--ai,var(--ink));}
.msgsched input{border:1px solid var(--aline,var(--line));border-radius:12px;padding:8px 11px;font:inherit;
  font-size:16px;background:var(--arow,var(--paper));color:var(--ai,var(--ink));}
.msgsched__x{border:0;background:none;font:inherit;font-size:.82rem;color:var(--am,var(--muted));cursor:pointer;}

.msgqueued{display:flex;flex-direction:column;gap:7px;margin:var(--space-md) 0 4px;}
.msgq{display:flex;align-items:center;gap:12px;padding:10px 14px;border-radius:var(--radius-card);
  background:var(--aicobg,var(--cream-2));}
.msgq span{flex:1;min-width:0;}
.msgq b{display:block;font-size:.8rem;color:var(--ai,var(--ink));}
.msgq em{display:block;font-style:normal;font-size:.8rem;color:var(--am,var(--muted));
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.msgq button{width:26px;height:26px;border-radius:50%;border:0;flex:none;cursor:pointer;line-height:1;
  background:var(--arow,var(--paper));color:var(--am,var(--muted));font-size:.9rem;}

/* --------------------------------------------------- conversation details */
.msginfo__h{display:flex;flex-direction:column;align-items:center;gap:9px;padding:var(--space-md) 0;text-align:center;}
.msgicon{position:relative;cursor:pointer;}
.msgicon i{position:absolute;right:-10px;bottom:-3px;width:28px;height:28px;border-radius:50%;
  display:grid;place-items:center;background:var(--aac,var(--cyan));color:var(--aacink,#fff);
  box-shadow:0 0 0 3px var(--ab,var(--paper));}
.msgicon i svg{width:15px;height:15px;}
.msginfo__name{font-family:var(--font-display);font-size:max(16px,1.22rem);font-weight:700;color:var(--ai,var(--ink));
  text-align:center;border:0;border-bottom:1.5px dashed var(--aline,var(--line));background:transparent;
  padding:3px 6px;max-width:100%;outline:none;}
.msginfo__name--fixed{border-bottom:0;}
.msginfo__h small{color:var(--am,var(--muted));font-size:.78rem;}

.msgcard{background:var(--arow,var(--paper));border-radius:var(--radius-card);padding:6px;
  box-shadow:inset 0 0 0 1px var(--aline,var(--line));}
.msgperson{display:flex;align-items:center;gap:12px;padding:9px 11px;}
.msgperson + .msgperson{border-top:1px solid var(--aline,var(--line));}
.msgperson__t{flex:1;min-width:0;}
.msgperson__t b{display:block;font-size:.93rem;font-weight:600;color:var(--ai,var(--ink));}
.msgperson__t b i{font-style:normal;font-weight:600;color:var(--am,var(--muted));font-size:.8rem;}
.msgperson__t small{display:block;color:var(--am,var(--muted));font-size:.75rem;}
.msgperson__x{width:28px;height:28px;border-radius:50%;border:0;flex:none;cursor:pointer;line-height:1;
  background:var(--asurf,var(--cream));color:var(--am,var(--muted));font-size:1rem;}
.msgperson--add{border-top:1px solid var(--aline,var(--line));}
.msgadd__i{flex:1;border:0;background:transparent;font:inherit;font-size:16px;color:var(--ai,var(--ink));outline:none;}
.msgadd__i::placeholder{color:var(--am,var(--muted));}
.msgadd .btn{margin:8px 11px 10px;}

.msgtog{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:13px 13px;
  font-size:.93rem;color:var(--ai,var(--ink));}
.msgtog + .msgtog{border-top:1px solid var(--aline,var(--line));}
.msgtog--col{flex-direction:column;align-items:flex-start;gap:9px;}
.msgtog small{color:var(--am,var(--muted));font-size:.78rem;font-weight:400;}
.msgtog--danger{color:var(--msgdanger);}
.msgleave{border:0;background:none;font:inherit;font-weight:700;font-size:.85rem;color:var(--msgdanger);cursor:pointer;}
html.app-mode body.ath-compline,body.emb.ath-compline,html.dark body{--msgdanger:#ff9b95;}
.msgsw{width:44px;height:26px;border-radius:100px;flex:none;position:relative;border:0;cursor:pointer;
  background:var(--aline,var(--line));transition:background .24s;}
.msgsw::after{content:"";position:absolute;top:2.5px;left:2.5px;width:21px;height:21px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .3s var(--msgspring);}
.msgsw.is-on{background:var(--aac,var(--cyan));}
.msgsw.is-on::after{transform:translateX(18px);}
.msgspans{display:flex;flex-wrap:wrap;gap:7px;}
.msgspan{border:1px solid var(--aline,var(--line));background:var(--asurf,var(--cream));
  color:var(--ai,var(--ink));border-radius:100px;padding:7px 13px;font:inherit;font-size:.8rem;
  font-weight:600;cursor:pointer;transition:transform .24s var(--msgspring);}
.msgspan:active{transform:scale(.95);}
.msgspan.is-on{background:var(--aac,var(--cyan));color:var(--aacink,#fff);border-color:transparent;}

.msgnote{font-size:.83rem;line-height:1.55;color:var(--am,var(--muted));padding:13px 16px;
  margin:10px 0 0;border-radius:var(--radius-card);background:var(--asurf,var(--cream));}
.msgnote a{color:var(--aacd,var(--cyan-deep));}

/* ------------------------------------------------------- messaging settings */
.msgsws{display:flex;gap:11px;flex-wrap:wrap;}
.msgsw2{width:40px;height:40px;border-radius:50%;border:0;cursor:pointer;background:var(--c);
  box-shadow:0 0 0 2px var(--paper,#fff);transition:transform .26s var(--msgspring);}
.msgsw2:hover{transform:scale(1.08);}
.msgsw2[aria-pressed="true"]{box-shadow:0 0 0 2px var(--paper,#fff),0 0 0 4px var(--ink);}
.msgbgs{display:grid;grid-template-columns:repeat(4,1fr);gap:11px;max-width:340px;}
.msgbg{border:0;background:none;padding:0;cursor:pointer;display:flex;flex-direction:column;gap:6px;align-items:center;}
.msgbg span{display:block;width:100%;aspect-ratio:9/13;border-radius:12px;
  box-shadow:inset 0 0 0 1px var(--line);}
.msgbg[aria-pressed="true"] span{box-shadow:inset 0 0 0 2px var(--ink);}
.msgbg b{font-size:.72rem;font-weight:600;color:var(--muted);}
.msgbgs--sm{display:flex;gap:9px;flex-wrap:wrap;}
.msgbgs--sm .msgbg{border:0;background:none;padding:0;cursor:pointer;width:56px;}
.msgbgs--sm .msgbg span{width:56px;aspect-ratio:9/12;border-radius:10px;}
.msgbgs--sm .msgbg b{color:var(--am,var(--muted));}
.msgbgs--sm .msgbg.is-on span{box-shadow:inset 0 0 0 2px var(--ai,var(--ink));}
.msgbg--none span{background:var(--arow,var(--paper));
  background-image:linear-gradient(135deg,transparent 46%,var(--aline,var(--line)) 46% 54%,transparent 54%);}
.msgbg--plain span{background:var(--paper);}
.msgbg--soft span{background:linear-gradient(165deg,color-mix(in srgb,var(--cyan) 18%,var(--paper)),var(--paper));}
.msgbg--paper span{background:var(--cream);}
.msgbg--deep span{background:linear-gradient(165deg,var(--cyan-deep),var(--navy));}

/* the unread count beside the Messages tab */
.ptlnav__n{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;margin-left:7px;
  border-radius:100px;background:var(--cyan);color:#fff;font-size:.68rem;font-weight:700;vertical-align:middle;}

/* The same count on a home tile. It sits beside the kicker rather than
   floating over the photograph: the kicker is already the line that says what
   sort of thing this card is, so the number belongs next to it. */
.ptlnew{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 6px;margin-left:8px;
  border-radius:100px;background:var(--cyan);color:#fff;font-size:.66rem;font-weight:700;
  letter-spacing:.01em;vertical-align:middle;text-transform:none;}

/* The floating profile avatar is fixed to the top right of every app screen.
   On a messaging screen it sits on top of the conversation header and is the
   one control nobody opens Messages to reach — your own profile is two taps
   away from the app home. Gone here, untouched everywhere else. */
html.msg-app .appuser{display:none !important;}

/* ------------------------------------------------------------ full screen
   Last in the file on purpose. These override the feed's own max-height and
   the section padding, and a first attempt placed them at the top where the
   later .msgfeed rule quietly won — the composer ended up floating in the
   middle of the screen instead of sitting on the bottom edge.

   The height is set from JavaScript rather than in CSS. 100svh is the whole
   screen, but a conversation does not get the whole screen: the app's floating
   tab bar sits over the bottom of it, and when the keyboard opens iOS shrinks
   the visual viewport without telling CSS. Both are measurable at runtime and
   neither is guessable, so --msgh is measured. The CSS value below is only
   what shows before the first measurement lands. */
.msgsection{padding:0 !important;}
.msgwrapper{padding-inline:14px;max-width:760px;}
html.app-mode .msgwrapper{padding-top:calc(env(safe-area-inset-top,0px) + 10px);}
html.msg-solo .msgwrapper{padding:0;max-width:none;}

/* Fixed to the viewport rather than sized from where it happens to sit.

   The previous version measured the wrap's distance from the top of the
   document once and subtracted it from the viewport height. If that measurement
   ran a moment before the web font landed — or the page had scrolled a pixel —
   the wrap came out taller than the screen and the composer fell off the
   bottom. Nothing here depends on layout any more: it is pinned to the
   viewport, and JavaScript only has to tell it how tall the viewport is when
   the keyboard changes that. */
.msgwrap--solo{position:fixed;left:0;right:0;top:0;
  height:var(--msgh,100dvh);
  display:flex;flex-direction:column;
  max-width:760px;margin-inline:auto;
  padding:calc(env(safe-area-inset-top,0px) + 8px) 14px calc(env(safe-area-inset-bottom,0px) + 8px);}
/* Only the feed may give up room. Without this the header shrinks along
   with everything else when the keyboard takes the bottom of the screen,
   so the name and the back arrow visibly squash on the way down and
   stretch on the way back - which is what made the keyboard read as a
   reflow rather than as the screen getting shorter. */
.msgwrap--solo .msghead{flex:none;}
/* flex:1 is flex-grow:1 with a basis of ZERO, and the composer below asked
   for the same free space with margin-top:auto. An engine is meant to flex
   first and hand the auto margin whatever is left - which is nothing, the
   feed having taken it. WebKit resolves the auto margin first, so on an
   iPhone the feed never grew past its own padding: forty pixels of nothing
   under the group card, the date divider sliced through at the bottom edge,
   and the composer pushed off the screen. Both halves are gone now. The
   basis is auto, so a feed that is handed no free space is still as tall as
   the messages in it, and the auto margin is dropped, because a feed that
   grows already puts the composer on the bottom edge. */
.msgwrap--solo .msgfeed{flex:1 1 auto;max-height:none;min-height:0;}
.msgwrap--solo .msgcomp{flex:none;}
/* iOS reports the shrunken viewport once, after the keyboard has finished
   coming up, so following it exactly moves the whole screen in one frame -
   the snap. Easing the two values that change turns that single report into
   the glide the keyboard is already doing. Switched on by a class rather
   than declared outright, because the first measurement happens on load and
   is not a change: the screen must not slide into place. */
.msgwrap--solo.is-settled{transition:height .28s cubic-bezier(.32,.72,0,1),top .28s cubic-bezier(.32,.72,0,1);}
/* Going away is the reverse of arriving and wants the reverse feel: the
   keyboard drops faster than it rises, so the screen should be waiting
   rather than trailing after it. */
.msgwrap--solo.is-settled.kb-out{transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);}
@media(prefers-reduced-motion:reduce){ .msgwrap--solo.is-settled{transition:none;} }
.msgnewform{flex:1;display:flex;flex-direction:column;min-height:0;}
.msgnewform .msgdrop,.msgnewform .msghits--all{min-height:0;}

/* A conversation owns the screen: the feed scrolls, the page does not, and the
   floating tab bar goes with the rest of the chrome. There is a back button in
   the corner; a second navigation floating over the composer is one too many,
   and it was covering the send button on shorter phones. */
/* The height matters as much as the overflow, and leaving it out cost a day.
   iOS clips a position:fixed element to its body box rather than to the
   viewport. While the page underneath was a full page that went unnoticed -
   the box was tall, so the conversation fitted inside it. Take the footer
   away and the body collapses to nothing, and a conversation clipped to
   nothing is a blank screen. Pinning both boxes to exactly one viewport
   gives the conversation the whole screen to be clipped to and still leaves
   nothing to scroll, which was the point of the overflow in the first place. */
html.msg-solo,html.msg-solo body{overflow:hidden;height:100%;min-height:100%;}
html.msg-solo body{overscroll-behavior:none;}
html.msg-solo .botbar{display:none !important;}
/* ...and the page underneath is still a whole page: the site's floating nav
   across the top, the site's footer at the bottom, and a conversation fixed
   over the middle of them. overflow:hidden on the root is meant to be the end
   of it, and is on every desktop browser. iOS scrolls it anyway, so what came
   up from underneath a conversation was the footer - VISIT, Who We Are,
   Ministries, Small Groups - drifting through the middle of somebody's
   messages, which is what "the overlay" turned out to be.

   Asking politely was the mistake. Nothing behind a conversation belongs to
   the conversation, so the nav and the footer come out of the flow entirely:
   with them gone the document is no taller than the screen and there is
   nothing left to scroll to, on any engine, however it feels about overflow. */
html.msg-solo .navshell,
html.msg-solo .footer{display:none !important;}

/* ---------------------------------------------------------------- motion
   These screens opt out of the site's entrance cascade.

   Everything with [data-reveal] starts at opacity:0 and waits for the observer
   to bring it in. On a page you scroll that is a nice touch; on a conversation
   it means the whole thing is invisible until JavaScript has run, on top of a
   page-load animation, on top of the browser's own navigation — three things
   stacked before you can read a message. That is what "laggy" was.

   Opacity only, short, and no waiting on script. */
html.msg-app main{animation:msgPageIn .16s linear both !important;}
/* Same reasoning as the page slide, and the same shape: long enough that it
   is still going whenever the next screen lands. A conversation cannot be
   moved - it is position:fixed inside main - so it dims instead. */
html.msg-app.page-exit main{animation:msgPageOut 2s linear both !important;}
@keyframes msgPageIn{from{opacity:.4}}
@keyframes msgPageOut{0%{opacity:1}12%{opacity:.84}30%{opacity:.76}100%{opacity:.52}}
html.msg-app [data-reveal]{opacity:1 !important;transform:none !important;}

@supports not (height:100dvh){ .msgwrap--solo{height:var(--msgh,100vh);} }

@media(prefers-reduced-motion:reduce){
  .msgrow,.msgback,.msgsend,.msgnew,.msgclip,.msgclock,.msgspan,.msgsw2,.msgsw::after,.msgpick button{
    transition:none !important;}
  .msgb,.msgbr i,.msgchip,.msgpick,.msgsched,.msgb--typing i{animation:none !important;}
}

/* ---------------------------------------------------- granted staff tools
   Deliberately not the big image cards the rest of the portal home uses:
   these are tools, not invitations, so they read as a compact shelf that
   does not compete with Prayer Wall and Documents above them. */
.grants{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px}
.grant{display:flex;align-items:center;gap:13px;padding:14px 16px;border-radius:14px;
  border:1px solid var(--line,#ece9e5);background:#fff;text-decoration:none;color:inherit;
  transition:border-color .18s,box-shadow .18s,transform .18s}
.grant:hover{border-color:var(--cyan,#a08a6f);box-shadow:0 8px 22px rgba(34,32,29,.09);transform:translateY(-1px)}
.grant:focus-visible{outline:2.5px solid var(--cyan,#a08a6f);outline-offset:3px}
.grant__ic{flex:0 0 auto;display:grid;place-items:center;width:40px;height:40px;border-radius:11px;
  background:color-mix(in srgb,var(--cyan,#a08a6f) 12%,#fff);color:var(--cyan-deep,#64523c)}
.grant__ic svg{width:21px;height:21px}
.grant__tx{display:grid;gap:2px;min-width:0}
.grant__tx b{font-weight:700;color:var(--navy,#22201d);font-size:.95rem;line-height:1.25}
.grant__tx span{font-size:.82rem;color:var(--muted,#94897e);line-height:1.35}
.grant__go{margin-left:auto;color:var(--cyan,#a08a6f);font-size:1.05rem;transition:transform .18s}
.grant:hover .grant__go{transform:translateX(3px)}


/* ===== sermon notes =====
   Rebuilt around the moment this screen is actually used: a phone, one hand,
   halfway down a pew, by someone whose eyes are on the front of the room and
   not on the glass. Everything below trades density for "I can hit that
   without looking twice."

   The delete control is hidden until hover on pointer devices and always
   visible on touch, because there is no hover there to reveal it with. */

/* --- service date ---
   The written-out date used to be shoved right with margin-left:auto on the
   same flex line as the picker. On a phone that line wrapped and the date
   ended up alone, right-aligned against nothing. A two-column grid keeps the
   control and the date on one line and lets them stack honestly when narrow. */
.ntdate{display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:var(--space-2xs) var(--space-sm);align-items:center;margin-bottom:var(--space-lg);}
.ntdate__l{grid-column:1 / -1;font-size:.72rem;letter-spacing:.09em;
  text-transform:uppercase;font-weight:700;color:var(--muted);}
.ntdate__i{min-height:44px;padding:.45em .7em;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--paper);color:var(--ink);
  font:inherit;font-size:1rem;}
.ntdate__w{font-family:var(--font-serif);font-style:italic;font-size:1.08rem;
  line-height:1.2;color:var(--cyan-deep);min-width:0;}
@media (max-width:430px){
  /* Stacked, but the field keeps its own width — a date input stretched the
     full width of a phone looks like a text box you are meant to write an
     essay in. */
  .ntdate{grid-template-columns:minmax(0,1fr);}
  .ntdate__i{justify-self:start;}
  .ntdate__w{font-size:1rem;}
}

.ntlinked{margin:0 0 var(--space-md);font-size:.88rem;color:var(--ink-soft);}
.ntlinked a{color:var(--cyan-deep);font-weight:600;}
.ntlinked--wait{opacity:.75;}

/* --- the writing area ---
   This is the whole point of the page, so it gets the room. Sized against the
   viewport rather than a fixed 220px, which on a phone showed about six lines
   and clipped the seventh mid-word. The plain min-height is the fallback for
   anything that does not understand dvh — declared first so it is overwritten,
   not competed with. */
.ntbody{width:100%;min-height:300px;min-height:clamp(300px,46dvh,560px);
  padding:var(--space-md);border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--paper);color:var(--ink);
  /* 1.0625rem, never below 16px: iOS zooms the whole page in on focus for
     anything smaller, which on one hand mid-service is genuinely disorienting. */
  font:inherit;font-size:1.0625rem;line-height:1.75;
  resize:none;
  transition:border-color .25s var(--ease-out),box-shadow .25s var(--ease-out);}
/* A drag handle is useless without a pointer, and on touch it only gets in the
   way of scrolling. Give it back to people who have a mouse. */
@media (pointer:fine){ .ntbody{resize:vertical;} }
.ntbody:focus{outline:none;border-color:var(--cyan-deep);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--cyan) 22%,transparent);}
/* A ring drawn with box-shadow disappears in forced-colors mode. */
@media (forced-colors:active){ .ntbody:focus{outline:2px solid;outline-offset:1px;} }
@media (prefers-reduced-motion:reduce){ .ntbody{transition:none;} }

/* --- save row ---
   The button stretches on narrow screens: a target the full width of the thumb's
   arc is easier to hit than a neat pill floating left, and there is nothing else
   competing for that line. */
.ntbar{display:flex;align-items:center;flex-wrap:wrap;
  gap:var(--space-sm) var(--space-md);margin-top:var(--space-md);}
.ntbar .btn{min-height:48px;flex:1 1 auto;justify-content:center;}
@media (min-width:560px){ .ntbar .btn{flex:0 0 auto;} }
.ntbar__hint{margin:var(--space-sm) 0 0;font-size:.8rem;color:var(--muted);}

/* --- the note list --- */
.ntempty{max-width:620px;margin:var(--space-2xl) auto 0;text-align:center;color:var(--ink-soft);}
.ntempty h2{font-family:var(--font-serif);font-style:italic;font-weight:400;
  margin:0 0 var(--space-xs);color:var(--ink);}
.ntempty p{margin:0;}

/* --- open the composer mid-week ---
   Sunday leads with the writing box. The rest of the week the page leads with
   what you have already written, and this is the way back in. */
.ntopen{max-width:820px;margin:0 auto;display:flex;}
.ntopen .btn{min-height:48px;}

.ntlist{max-width:820px;margin:var(--space-2xl) auto 0;display:grid;gap:var(--space-2xl);}

/* --- a series, collapsible ---
   <details>/<summary>, so it folds with no JavaScript at all and announces
   itself correctly to a screen reader. The remembered state is a nicety layered
   on top; if the script never runs, every series is simply open. */
/* Left at the default block display, with spacing from the cards rather than a
   gap. Overriding display on a <details> has historically stopped the closed
   state hiding anything in some browsers; block, grid and flex all collapse
   correctly in current Chromium, but this page is read mostly on iPhones and
   Safari is the engine that matters here, so the cautious option is free. */
.ntgrp{display:block;}
.ntgrp > .ntcard{margin-top:var(--space-sm);}
.ntgrp__h{display:flex;align-items:center;gap:var(--space-md);margin-bottom:var(--space-2xs);
  cursor:pointer;list-style:none;border-radius:var(--radius-sm);
  padding:var(--space-2xs) var(--space-2xs) var(--space-2xs) 0;
  transition:background-color .2s var(--ease-out);}
.ntgrp__h::-webkit-details-marker{display:none;}
.ntgrp__h:hover{background:color-mix(in srgb,var(--navy) 4%,transparent);}
.ntgrp__h:focus-visible{outline:2px solid var(--cyan-deep);outline-offset:2px;}
.ntgrp__chev{margin-left:auto;flex:none;display:grid;place-items:center;
  width:32px;height:32px;border-radius:50%;color:var(--muted);
  transition:transform .25s var(--ease-out),color .2s var(--ease-out);}
.ntgrp[open] .ntgrp__chev{transform:rotate(180deg);}
.ntgrp__h:hover .ntgrp__chev{color:var(--cyan-deep);}
@media (prefers-reduced-motion:reduce){
  .ntgrp__h,.ntgrp__chev{transition:none;}
}
.ntgrp__img{width:56px;height:56px;border-radius:var(--radius-inset);overflow:hidden;flex:none;
  background:color-mix(in srgb,var(--navy) 8%,transparent);}
.ntgrp__img img{width:100%;height:100%;object-fit:cover;display:block;}
/* An empty gray square is not a placeholder, it is a hole. Series without
   artwork simply do not get one. */
.ntgrp__img--none{display:none;}
.ntgrp__t{display:grid;gap:2px;min-width:0;}
.ntgrp__t strong{font-size:1.05rem;letter-spacing:-.01em;color:var(--ink);}
.ntgrp__t em{font-family:var(--font-serif);font-style:italic;font-size:.95rem;color:var(--ink-soft);}
.ntgrp__t small{font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);}

.ntcard{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-md) var(--space-lg);display:grid;gap:var(--space-sm);}
.ntcard__h{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2xs) var(--space-sm);}
.ntcard__d{font-weight:700;font-size:.98rem;color:var(--ink);text-decoration:none;}
.ntcard__d:hover{color:var(--cyan-deep);}
.ntcard__s{font-family:var(--font-serif);font-style:italic;color:var(--ink-soft);min-width:0;}
.ntcard__e{margin-left:auto;flex:none;display:inline-flex;align-items:center;
  min-height:38px;padding:0 var(--space-sm);border-radius:100px;
  font-size:.82rem;font-weight:600;color:var(--cyan-deep);text-decoration:none;
  box-shadow:inset 0 0 0 1px var(--line);
  transition:background-color .2s var(--ease-out);}
.ntcard__e:hover{background:color-mix(in srgb,var(--cyan) 12%,transparent);}
@media (prefers-reduced-motion:reduce){ .ntcard__e{transition:none;} }

/* --- the sermon, as a thumbnail ---
   Borrows .vidcard from the messages page rather than reimplementing it, so the
   two stay in step. Small: this is a note you are reading, and the video is the
   thing you might go and watch afterwards, not the subject of the card. */
.ntcard__v{width:min(190px,52%);border-radius:12px;text-decoration:none;}
.ntcard__v .vidcard__thumb{border-radius:var(--radius-inset);}
/* The shared play button is 54px, built for a full-width hero card. At this
   size it would cover most of the frame. */
.ntcard__v .vidcard__play{width:38px;height:38px;}
.ntcard__v .vidcard__play svg{width:16px;height:16px;}
.ntcard__v:hover{transform:none;box-shadow:none;}

.ntcard__b{margin:0;white-space:pre-wrap;line-height:1.7;color:var(--ink-soft);max-width:68ch;}

.ntcard__x{justify-self:end;opacity:0;transition:opacity .25s var(--ease-out);}
.ntcard__x button{min-height:38px;padding:0 var(--space-sm);border:0;background:none;
  border-radius:100px;font:inherit;font-size:.8rem;color:var(--muted);cursor:pointer;}
.ntcard__x button:hover{color:#b3261e;background:color-mix(in srgb,#b3261e 8%,transparent);}
@media (hover:hover){ .ntcard:hover .ntcard__x{opacity:1;} }
.ntcard:focus-within .ntcard__x{opacity:1;}
@media (hover:none){ .ntcard__x{opacity:1;} }
@media (prefers-reduced-motion:reduce){ .ntcard__x{transition:none;} }


/* The conversation screens had their own page animation, declared !important
   and — because this file loads after site.css — winning on source order over
   the rule that stands the CSS versions down. site.js owns the movement now,
   for the reason set out there: a CSS animation on a fresh document has
   often finished before an installed app is allowed to show the page. */
html.msg-app main,
html.msg-app.page-exit main{animation:none !important;}


/* ---- No pull-to-refresh inside a conversation ---------------------------
   Dragging past the top of a chat still handed the gesture to iOS, which ran
   its own refresh behind a thread that was still settling - that tug of war
   is what reads as the scrolling being glitchy on a long conversation. A
   recording of it shows the spinner plainly, sitting above the messages.

   The first attempt at this used "contain", which was the wrong value and is
   worth writing down so nobody reaches for it again here: contain stops the
   gesture escaping to whatever is underneath, but explicitly still allows an
   element its OWN default overscroll effect - and on iOS that effect IS the
   pull-to-refresh. Only "none" turns the effect itself off.

   It also has to be set on the html element. The gesture belongs to the
   viewport, and overscroll-behavior on body is not dependably propagated up
   to it, which is why the rule already sitting on "html.msg-solo body" was
   never going to be enough on its own.

   Nothing here is waiting on a pull anyway: messages arrive by themselves,
   so there was never anything to pull down FOR. */
html.msg-app, html.msg-app body,
html.msg-solo, html.msg-solo body{
  overscroll-behavior-y: none;
  overscroll-behavior-x: none;
}
.msgfeed, .msgwrap--solo .msgfeed, .msghits--all{
  overscroll-behavior: none;
}


/* ═════ ministry needs + marketplace ═════
   Same card as the prayer wall on purpose. What is new here is Reach Out,
   which opens in place rather than in a modal so the message you are writing
   stays attached to the thing you are answering. */
.bd__reach{flex:0 0 auto}
.bd__reach[open]{flex:1 1 100%}
.bd__reach>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:.5em;
  border:1.5px solid var(--line);background:var(--paper);border-radius:100px;padding:.5em 1.1em;
  font-family:var(--font-display);font-weight:700;font-size:.84rem;color:var(--ink);
  transition:border-color .25s,background .25s,color .25s,transform .25s var(--ease-out,cubic-bezier(.22,1,.36,1)),box-shadow .25s}
.bd__reach>summary::-webkit-details-marker{display:none}
.bd__reach>summary::marker{content:""}
.bd__reach>summary:hover{border-color:var(--cyan);transform:translateY(-2px);box-shadow:var(--shadow-sm)}
.bd__reach>summary:active{transform:scale(.94);transition-duration:.08s}
.bd__reach[open]>summary{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.bd__reachform{margin-top:12px;display:grid;gap:10px;animation:bdReach .3s cubic-bezier(.22,1,.36,1) both}
@keyframes bdReach{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.bd__reachform textarea{font:inherit;width:100%;border:1.5px solid var(--line);border-radius:14px;
  padding:.7em .85em;background:var(--paper);color:var(--ink);line-height:1.55;resize:vertical}
.bd__reachform textarea:focus{outline:none;border-color:var(--cyan);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--cyan) 14%,transparent)}
.bd__reachrow{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.bd__privacy{flex:1 1 250px;font-size:.78rem;line-height:1.45;color:var(--muted)}
.bd__nomail{font-family:var(--font-serif);font-style:italic;font-size:.86rem;color:var(--muted)}
.bd__count{font-family:var(--font-display);font-weight:600;font-size:.78rem;color:var(--cyan-deep)}

/* Done: still readable, visibly finished. Left up for a week so people stop
   asking, then swept. */
.bd--done{background:var(--cream);border-style:dashed}
.bd--done .mk__pics,.bd--done .pw__txt,.bd--done .mk__title{opacity:.6}
.bd__donetag{display:flex;gap:.55em;flex-wrap:wrap;align-items:baseline;margin-bottom:12px;
  font-family:var(--font-display);font-weight:700;font-size:.82rem;color:var(--cyan-deep)}
.bd__donetag span{font-family:var(--font-serif);font-style:italic;font-weight:400;color:var(--muted)}

/* ── marketplace ──────────────────────────────────────────────────────────
   A noticeboard, not a shop. The photographs do the talking; everything else
   keeps out of their way. */

/* The post form is shut to begin with. Most visits are somebody seeing what is
   on the board, and an open form at the top of a board is a form standing in
   front of the thing you came for. Dashed while closed — the visual language
   of a free pin, not of a primary button. */
.mkpost{max-width:760px;margin-inline:auto}
.mkpost>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.75em;
  background:var(--paper);border:1.5px dashed color-mix(in srgb,var(--cyan) 34%,var(--line));
  border-radius:var(--radius);padding:15px 20px;
  font-family:var(--font-display);font-weight:700;font-size:.97rem;color:var(--ink);
  transition:border-color .25s,background .25s,transform .25s var(--ease-out,cubic-bezier(.22,1,.36,1))}
.mkpost>summary::-webkit-details-marker{display:none}
.mkpost>summary::marker{content:""}
.mkpost>summary:hover{border-color:var(--cyan);background:color-mix(in srgb,var(--cyan) 5%,var(--paper));transform:translateY(-1px)}
.mkpost>summary:focus-visible{outline:none;box-shadow:0 0 0 4px color-mix(in srgb,var(--cyan) 20%,transparent)}
.mkpost[open]>summary{border-style:solid;border-color:var(--cyan);background:var(--paper);
  border-bottom-left-radius:0;border-bottom-right-radius:0;transform:none}

/* The plus turns into a close. One transform, no second trick. */
.mkpost__plus{position:relative;flex:none;width:26px;height:26px;border-radius:50%;
  background:color-mix(in srgb,var(--cyan) 14%,var(--snow));
  transition:transform .3s cubic-bezier(.22,1,.36,1),background .25s}
.mkpost__plus::before,.mkpost__plus::after{content:"";position:absolute;top:50%;left:50%;
  background:var(--cyan-deep);border-radius:2px}
.mkpost__plus::before{width:11px;height:2px;transform:translate(-50%,-50%)}
.mkpost__plus::after{width:2px;height:11px;transform:translate(-50%,-50%)}
.mkpost[open] .mkpost__plus{transform:rotate(45deg);background:color-mix(in srgb,var(--cyan) 22%,var(--snow))}
.mkpost__form{background:var(--paper);border:1.5px solid var(--cyan);border-top:0;
  border-radius:0 0 var(--radius) var(--radius);padding:clamp(18px,3vw,26px);
  animation:mkOpen .34s cubic-bezier(.22,1,.36,1) both}
@keyframes mkOpen{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}

.mk__kinds{display:grid;grid-template-columns:repeat(auto-fit,minmax(206px,1fr));gap:10px;margin-bottom:var(--space-md)}
.mk__kind{position:relative;display:block;border:1.5px solid var(--line);border-radius:16px;padding:13px 15px;
  cursor:pointer;background:var(--paper);transition:border-color .2s,background .2s}
.mk__kind:hover{border-color:var(--cyan)}
.mk__kind input{position:absolute;opacity:0;width:0;height:0}
.mk__kind b{display:block;font-family:var(--font-display);font-size:.95rem;color:var(--ink)}
.mk__kind span{display:block;margin-top:3px;font-size:.8rem;line-height:1.4;color:var(--muted)}
.mk__kind:has(input:checked){border-color:var(--cyan);background:color-mix(in srgb,var(--cyan) 7%,var(--paper))}
.mk__kind:has(input:focus-visible){box-shadow:0 0 0 4px color-mix(in srgb,var(--cyan) 18%,transparent)}
.mk__file{font:inherit;font-size:.86rem;color:var(--ink-soft)}

/* A segmented control, not a row of pills. Three labels of unequal length in a
   flex row wrapped onto two lines on a phone and turned the tray into a blob;
   equal columns cannot wrap, so it holds its shape at any width. The type and
   padding shrink with the viewport rather than the labels breaking. */
.mkbar{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:3px;
  width:100%;max-width:460px;margin:0 auto var(--space-lg);
  background:var(--cream);border-radius:100px;padding:4px}
.mkbar a{display:flex;align-items:center;justify-content:center;gap:.4em;
  white-space:nowrap;overflow:hidden;min-height:38px;padding:0 .45em;border-radius:100px;
  font-family:var(--font-display);font-weight:600;
  font-size:.85rem;letter-spacing:-.01em;color:var(--muted);
  transition:color .25s,background .25s}
.mkbar a:hover{color:var(--ink)}
.mkbar a.on{background:var(--ink);color:var(--paper);box-shadow:var(--shadow-sm)}
.mkbar a:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--cyan) 45%,transparent)}
.mkbar a span{font-size:.86em;opacity:.5;font-variant-numeric:tabular-nums}
.mkbar a.on span{opacity:.7}

/* "Giving away" is the widest of the three, so it sets the floor. Measured
   against Montserrat 600 at each step: the type drops before the labels can
   collide, and the counts — a nicety, not the function — go last on the
   narrowest phones still in use. Slack at every step is 8px or better. */
@media(max-width:430px){ .mkbar a{font-size:.78rem;gap:.3em;padding:0 .3em} }
@media(max-width:380px){ .mkbar a{font-size:.73rem;gap:.28em;padding:0 .28em} }
@media(max-width:359px){ .mkbar a span{display:none} }

/* Two columns where there is room. A board is for scanning many, not reading
   one — which is the whole difference between this and the prayer wall. */
.pwall--mk{max-width:1060px;grid-template-columns:repeat(auto-fit,minmax(304px,1fr));
  align-items:start;gap:var(--space-md)}
.pwall--mk>[hidden]{display:none}
.mk{display:flex;flex-direction:column;padding:18px 20px 20px}
.mk .pw__foot{margin-top:auto;padding-top:14px}

.mk__pics{display:grid;gap:6px;margin:0 0 14px}
.mk__lead{display:block;border-radius:14px;overflow:hidden}
.mk__lead img{display:block;width:100%;aspect-ratio:16/10;object-fit:cover;
  transition:transform .5s var(--ease-out,cubic-bezier(.22,1,.36,1))}
.mk__lead:hover img{transform:scale(1.03)}
.mk__more{display:flex;gap:6px}
.mk__more a{flex:0 0 auto;display:block;width:78px;border-radius:10px;overflow:hidden}
.mk__more img{display:block;width:100%;aspect-ratio:1;object-fit:cover;
  transition:transform .5s var(--ease-out,cubic-bezier(.22,1,.36,1))}
.mk__more a:hover img{transform:scale(1.06)}

.mk__head{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.mk__tag{display:inline-block;font-family:var(--font-display);font-weight:700;font-size:.7rem;
  text-transform:uppercase;letter-spacing:.09em;border-radius:100px;padding:.4em .85em}
.mk__tag--offer{background:color-mix(in srgb,var(--cyan) 14%,var(--snow));color:var(--cyan-deep)}
.mk__tag--request{background:var(--cream);color:var(--ink);border:1px solid var(--line)}
.mk__title{font-family:var(--font-display);font-size:1.26rem;line-height:1.2;margin:0;
  color:var(--ink);text-wrap:balance}
.mk__txt{margin-top:10px;font-size:.95rem;max-width:62ch}
.mk__meta{margin:16px 0 0}
.mk .pw__who strong{font-size:.88rem}
.mk .pw__who time{font-size:.82rem}

.mkempty{text-align:center;max-width:52ch;margin-inline:auto;color:var(--muted);
  font-family:var(--font-serif);font-style:italic}

/* Filtering is a change of view, so the set that remains settles together. */
.pwall--mk.is-swap>.mk:not([hidden]){animation:mkIn .34s cubic-bezier(.22,1,.36,1) both}
@keyframes mkIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

@media(prefers-reduced-motion:reduce){
  .bd__reachform,.mkpost__form{animation:none}
  .pwall--mk.is-swap>.mk:not([hidden]){animation:none}
  .mk__lead:hover img,.mk__more a:hover img{transform:none}
  .mkpost>summary:hover{transform:none}
}


/* .........................................................
   MARKETPLACE CARD ON A PHONE
   The events list runs its artwork at 24px, and these cards sit in the same
   app, so they take the same curve. The photo comes out to an 8px inset and
   16px - 24 less the card around it - so the two curves run parallel instead
   of the picture floating in the middle of a 20px margin.
   ......................................................... */
@media(max-width:640px){
  .mk{border-radius:var(--radius-card)}
  .mk__pics{margin:-10px -12px 14px}
  .mk__lead{border-radius:15px}
  .mk__more a{border-radius:12px}
}


/* ---- edit a small group's schedule -----------------------------------------
   Two jobs on one page, and the page has to make plain which one you are doing:
   the rotation is set once and repeats, the one-off list is where the unusual
   dates go. Tabs rather than two forms stacked, so neither can be scrolled past
   and mistaken for the other.

   Most weeks a leader will open this and change nothing, so the resting state
   is quiet: a blank field means "as usual" and the placeholder says so, rather
   than a paragraph of instructions above the form.

   Field text is 16px and not a fraction less. Below that iOS zooms the page the
   moment you tap in, which on a form of this length is genuinely disorienting. */
.rota{max-width:840px;margin-inline:auto}

/* ---- who and where ------------------------------------------------------- */
.rota__head{display:flex;justify-content:space-between;align-items:flex-end;
  gap:var(--space-sm);flex-wrap:wrap;margin-bottom:var(--space-sm)}
.rota__eyebrow{font-size:.64rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--cyan-deep);margin:0}
.rota__head h2{margin:var(--space-2xs) 0 0;font-size:1.5rem;letter-spacing:-.01em}
.rota__see{font-size:.84rem;font-weight:600;color:var(--cyan-deep);white-space:nowrap}

.rota__pick{display:flex;flex-wrap:wrap;gap:var(--space-2xs);margin-bottom:var(--space-sm)}
.rota__pill{font-size:.84rem;font-weight:600;padding:.42em .9em;border-radius:999px;
  background:var(--cream);color:var(--ink);border:1px solid var(--line);
  transition:background .14s var(--ease-out),color .14s var(--ease-out)}
.rota__pill:hover{background:var(--cream-2)}
.rota__pill.on{background:var(--navy);color:#fff;border-color:var(--ink)}

.rota__borrowed{margin:0 0 var(--space-sm);font-size:.8rem;color:var(--muted);
  background:var(--cream);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:.6em .85em}

/* ---- the two jobs -------------------------------------------------------- */
.rota__tabs{display:flex;gap:var(--space-md);margin:0 0 var(--space-lg);
  border-bottom:1px solid var(--line)}
.rota__tab{position:relative;padding:.7em 0 .85em;font-size:.94rem;font-weight:600;
  color:var(--muted);text-decoration:none;
  transition:color .14s var(--ease-out)}
.rota__tab:hover{color:var(--ink)}
.rota__tab.on{color:var(--ink)}
.rota__tab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:var(--cyan);border-radius:2px}
.rota__count{display:inline-block;min-width:1.35em;padding:0 .3em;margin-left:.4em;
  font-size:.7rem;font-weight:700;line-height:1.5em;text-align:center;
  border-radius:999px;background:var(--cream-2);color:var(--muted)}
.rota__tab.on .rota__count{background:var(--cyan);color:#fff}

/* ---- the leader hub's second row ----------------------------------------
   The three pills are the job. The rotation's own two tabs sit under them,
   quieter, because they are a choice inside one of those jobs rather than a
   fourth job. */
.rota__tabs--sub{margin-top:calc(var(--space-xs) - var(--space-lg));border-bottom:0;gap:var(--space-md)}
.rota__tabs--sub .rota__tab{font-size:.84rem;padding:.45em 0 .6em}
.rota__tabs--sub .rota__tab.on::after{background:var(--muted)}

/* ---- which meeting is being marked --------------------------------------
   A strip of dates rather than a date field: a leader is picking one of eight
   real evenings, not naming an arbitrary day. The next meeting is dashed, so
   marking it in advance looks like the odd thing it is. */
/* A grid rather than a wrapping row. There are usually nine dates here -
   eight meetings behind and the next one - and left to wrap they broke 4, 4,
   then a single chip stranded on a line of its own. Three up on a phone
   divides nine exactly, and gives a thumb something big to hit; from 520px
   the columns are sized instead of counted, which lands on 5+4, 6+3 and
   eventually one clean row. */
.rotd{display:grid;grid-template-columns:repeat(3,1fr);
  gap:var(--space-2xs);margin:0 0 var(--space-md)}
@media(min-width:520px){
  .rotd{grid-template-columns:repeat(auto-fill,minmax(84px,1fr))}}
.rotd__d{display:flex;flex-direction:column;align-items:center;gap:1px;
  min-width:62px;padding:.45em .6em;border-radius:var(--radius-sm);
  background:var(--cream);border:1px solid var(--line);color:inherit;
  text-decoration:none;line-height:1.15;
  transition:background .14s var(--ease-out),border-color .14s var(--ease-out)}
.rotd__d span{font-size:.62rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.rotd__d b{font-size:.86rem;font-weight:700}
.rotd__d:hover{background:var(--cream-2)}
.rotd__d.is-next{border-style:dashed}
.rotd__d.on{background:var(--navy);border-color:var(--ink);color:#fff}
.rotd__d.on span{color:rgba(255,255,255,.72)}

/* A chip filled with --navy is invisible on a dark page - the brand color and
   the background are the same darkness. After dark the selected chip inverts
   instead, which is the same idea said the other way round. */
html.dark .rota__pill.on,html.dark .rotd__d.on,
html.app-mode body.ath-compline .rota__pill.on,html.app-mode body.ath-compline .rotd__d.on{
  background:var(--ink);border-color:var(--ink);color:var(--paper)}
html.dark .rotd__d.on span,
html.app-mode body.ath-compline .rotd__d.on span{color:var(--paper);opacity:.72}

/* ---- the register -------------------------------------------------------
   One row per person, and the whole row is the label, so a thumb anywhere on
   it ticks the box. 44px minimum because this gets filled in on a phone in
   somebody's front room. */
.rotm{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.rotm__p{display:flex;align-items:center;gap:var(--space-sm);
  background:#fff;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:0 .85em}
.rotm__tick{flex:1;display:flex;align-items:center;gap:.7em;min-height:46px;cursor:pointer}
.rotm__tick input{width:20px;height:20px;flex:none;accent-color:var(--cyan);cursor:pointer}
.rotm__name{font-size:.95rem;font-weight:600;color:inherit}
.rotm__name em{font-style:normal;font-size:.62rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin-left:.4em}
.rotm__been{flex:none;font-size:.74rem;color:var(--muted);font-variant-numeric:tabular-nums}

.rotm__edit{margin-top:0}
.rotm__add{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--space-sm)}
.rotm__add .rotr__f{flex:1;min-width:210px}
.rotm__off{list-style:none;margin:var(--space-xs) 0 0;padding:0}
.rotm__off li{display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-sm);padding:.55em .2em;border-bottom:1px solid var(--line);font-size:.9rem}
.rotm__off li:last-child{border-bottom:0}
.rotm__off button{border:1px solid var(--line);background:var(--cream);color:var(--muted);
  border-radius:999px;padding:.4em .85em;font:inherit;font-size:.78rem;font-weight:600;cursor:pointer}
.rotm__off button:hover{color:inherit}

/* ---- this week's questions, to read ------------------------------------- */
.rotq{background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-md) var(--space-md) var(--space-lg)}
.rotq__wk{margin:0;font-size:.66rem;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.rotq__t{margin:.2em 0 0;font-size:1.25rem}
.rotq__o{margin:var(--space-sm) 0 0;font-size:.98rem}
.rotq__ref{margin:var(--space-sm) 0 0;padding:var(--space-sm) var(--space-md);
  background:var(--cream);border-radius:var(--radius-sm);
  font-size:.94rem;line-height:1.6;white-space:pre-line}
.rotq__q{margin:var(--space-md) 0 0;padding-left:1.3em;display:flex;flex-direction:column;gap:.55em}
.rotq__q li{font-size:.98rem;line-height:1.5}
.rotq__pray{margin:var(--space-md) 0 0;font-size:.95rem}
.rotq__pray span{display:block;font-size:.66rem;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);margin-bottom:.2em}
.rotq__ann{margin:var(--space-sm) 0 0;font-size:.88rem;color:var(--muted)}

/* ---- the meal ------------------------------------------------------------
   A property of the month rather than of a week number, so it gets its own box
   under the five rather than borrowing one of them. */
.rotmeal{margin:0;background:var(--cream);border:1px solid var(--line);
  border-radius:var(--radius);padding:var(--space-sm) var(--space-md) var(--space-md)}
.rotmeal__on{display:flex;gap:11px;align-items:flex-start;cursor:pointer;padding:.35em 0}
.rotmeal__on input{width:20px;height:20px;flex:none;margin-top:2px;accent-color:var(--cyan);cursor:pointer}
.rotmeal__on b{display:block;font-size:.95rem}
.rotmeal__on em{display:block;font-style:normal;font-size:.8rem;color:var(--muted);margin-top:3px;line-height:1.45}
.rotmeal__fields{display:grid;gap:var(--space-sm);margin-top:var(--space-sm)}
@media(min-width:640px){.rotmeal__fields{grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}}

/* ---- weeks 1 to 5 -------------------------------------------------------- */
.rotr{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-sm)}
.rotr__w{display:flex;gap:var(--space-sm);align-items:flex-start;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-sm) var(--space-md) var(--space-md)}
/* The fifth week happens three or four times a year, so it sits back until it
   is wanted rather than taking an equal share of the eye. */
.rotr__w.is-rare{background:var(--cream);border-style:dashed}
.rotr__n{flex:none;width:34px;height:34px;margin-top:.15em;border-radius:50%;
  display:grid;place-items:center;
  font-size:.92rem;font-weight:700;font-variant-numeric:tabular-nums;
  background:var(--navy);color:#fff}
.rotr__w.is-rare .rotr__n{background:var(--cream-2);color:var(--muted)}
.rotr__body{flex:1;min-width:0}
.rotr__when{margin:.35em 0 var(--space-sm);font-size:.8rem;color:var(--muted);line-height:1.4}
.rotr__fields{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-sm)}

/* Pinning a week to the end of the month. One radio per card plus an off switch, because
   only one week can be the last one and a checkbox would let a leader claim two. */
.rotr__last,.rotr__undo{display:inline-flex;align-items:flex-start;gap:.5em;cursor:pointer;
  margin:0 0 var(--space-sm);font-size:.78rem;color:var(--muted);line-height:1.4}
.rotr__last input,.rotr__undo input{flex:none;width:17px;height:17px;margin:.05em 0 0;accent-color:var(--cyan);cursor:pointer}
.rotr__last em{font-style:normal;font-weight:700;color:var(--cyan-deep)}
.rotr__w:has(.rotr__last input:checked){border-color:var(--cyan)}
.rotr__w:has(.rotr__last input:checked) .rotr__n{background:var(--cyan)}
.rotr__how{margin:0 0 var(--space-md);max-width:64ch}
.rotr__how p{margin:0;font-size:.8rem;color:var(--muted);line-height:1.55}
.rotr__how p + p{margin-top:.6em}
.rotr__how em{font-style:normal;font-weight:700;color:var(--cyan-deep)}
/* The pinned week spells out what it resolves to, with real dates, because
   "the last one of the month" is otherwise a rule a leader has to take on
   trust. The off switch lives in the same box: the place you turn a thing
   off should be the place it is on. */
.rotr__pin{margin:0 0 var(--space-sm);padding:var(--space-sm) var(--space-md);
  border-radius:calc(var(--radius) - 5px);background:rgba(160,138,111,.09)}
.rotr__pinnote{margin:0 0 .5em;font-size:.78rem;color:var(--muted);line-height:1.5}
.rotr__pinnote b{font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
.rotr__pin .rotr__last{margin:0}
.rotr__undo{margin:.45em 0 0}
.rotr__undo:hover span{color:var(--ink)}
html.dark .rotr__pin,html.app-mode body.ath-compline .rotr__pin{background:rgba(160,138,111,.18);}
html.dark .rotr__how em,html.app-mode body.ath-compline .rotr__how em{color:var(--cyan);}
.rotr__when strong{font-weight:800;color:var(--cyan-deep)}
html.dark .rotr__when strong,html.dark .rotr__last em,
html.app-mode body.ath-compline .rotr__when strong,html.app-mode body.ath-compline .rotr__last em{color:var(--cyan);}
html.dark .rotr__w:has(.rotr__last input:checked) .rotr__n,
html.app-mode body.ath-compline .rotr__w:has(.rotr__last input:checked) .rotr__n{background:var(--cyan);color:#17120c;}

/* ---- one-off dates ------------------------------------------------------- */
.rote{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-sm)}
.rote__e{background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-md)}
.rote__e.is-new{background:var(--cream);border-style:dashed}
.rote__add{margin:0 0 var(--space-sm);font-size:.7rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--cyan-deep)}
.rote__fields{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-sm)}
.rote__f{display:block;min-width:0;grid-column:span 2}
.rote__f--sm{grid-column:span 1}
.rote__f--wide{grid-column:1/-1}
.rote__rm{display:inline-flex;align-items:center;gap:var(--space-2xs);
  margin-top:var(--space-sm);font-size:.8rem;color:var(--muted);cursor:pointer}
.rote__rm input{width:18px;height:18px;accent-color:var(--cyan)}

/* ---- fields, shared ------------------------------------------------------ */
/* 16px and not a fraction less. Below that iOS zooms the page the moment you
   tap in, which on a form of this length is genuinely disorienting. */
.rotr__f,.rote__f{display:block;min-width:0}
.rotr__f span,.rote__f span{display:block;font-size:.7rem;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);margin-bottom:var(--space-2xs)}
.rotr__f span em,.rote__f span em{font-style:normal;font-weight:600;text-transform:none;
  letter-spacing:0;color:var(--cyan-deep)}
.rotr__f input,.rote__f input,.rote__f select,.rote__f textarea{
  font:inherit;font-size:16px;width:100%;background:var(--surface,#fff);
  border:1.5px solid var(--line);border-radius:var(--radius-sm);
  padding:.5em .65em;color:var(--ink);
  transition:border-color .14s var(--ease-out),box-shadow .14s var(--ease-out)}
.rote__f textarea{resize:vertical;min-height:3.2em;line-height:1.45}
.rotr__f input:focus,.rote__f input:focus,.rote__f select:focus,.rote__f textarea:focus{
  outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(160,138,111,.15)}

.rota__save{margin-top:var(--space-xl);display:flex;flex-direction:column;
  align-items:flex-start;gap:var(--space-xs)}
.rota__save .btn{min-width:200px;justify-content:center}
.rota__fine{margin:0;font-size:.76rem;color:var(--muted);line-height:1.6;max-width:62ch}

/* ---- what it actually comes out as --------------------------------------- */
.rota__sub{margin:var(--space-2xl) 0 var(--space-sm);font-size:.7rem;font-weight:700;
  letter-spacing:.11em;text-transform:uppercase;color:var(--muted)}
.rotp{list-style:none;margin:0;padding:0;
  border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:#fff}
.rotp__r{display:flex;align-items:center;gap:var(--space-sm);
  padding:.7em var(--space-md);font-size:.88rem}
.rotp__r + .rotp__r{border-top:1px solid var(--line)}
.rotp__r.is-off{background:var(--cream);color:var(--muted)}
.rotp__r.is-extra{background:var(--cream)}
.rotp__d{flex:none;width:6.5em;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.rotp__r.is-off .rotp__d{color:var(--muted)}
.rotp__w{flex:none;font-size:.68rem;font-weight:700;letter-spacing:.04em;
  color:var(--muted);background:var(--cream-2);border-radius:999px;padding:.2em .55em}
.rotp__t{flex:1;min-width:0;color:var(--ink)}
.rotp__t em{font-style:normal;color:var(--muted)}
.rotp__clear{flex:none;margin:0}
.rotp__clear button{font:inherit;font-size:.68rem;font-weight:700;letter-spacing:.03em;
  color:var(--muted);background:none;border:1px solid var(--line);border-radius:999px;
  padding:.2em .6em;cursor:pointer;
  transition:color .14s var(--ease-out),border-color .14s var(--ease-out)}
.rotp__clear button:hover{color:var(--ink);border-color:var(--ink)}

/* ---- the back door ------------------------------------------------------- */
.rota__other{margin-top:var(--space-2xl);font-size:.84rem}
.rota__other summary{cursor:pointer;color:var(--muted);font-weight:600;
  padding:.5em 0;list-style:none}
.rota__other summary::-webkit-details-marker{display:none}
.rota__other summary::before{content:"+ ";font-weight:700}
.rota__other[open] summary::before{content:"\2212 "}
.rota__other summary:hover{color:var(--ink)}
.rota__other ul{list-style:none;margin:var(--space-2xs) 0 0;padding:0;
  display:flex;flex-direction:column;gap:.35em}
.rota__other li a{font-weight:600;color:var(--cyan-deep)}
.rota__other li span{color:var(--muted);font-size:.8rem}

@media(max-width:680px){
  .rote__fields{grid-template-columns:1fr 1fr}
  .rote__f{grid-column:1/-1}
  .rote__f--sm{grid-column:span 1}
}
@media(max-width:620px){
  .rotr__fields{grid-template-columns:1fr}
  .rotr__w,.rote__e{padding:var(--space-sm)}
  .rota__save .btn{width:100%}
  .rotp__r{flex-wrap:wrap;gap:var(--space-2xs) var(--space-xs)}
  .rotp__d{width:auto}
  .rotp__t{flex:1 0 100%}
}
@media(prefers-reduced-motion:reduce){
  .rota__pill,.rota__tab,.rotp__clear button,
  .rotr__f input,.rote__f input,.rote__f select,.rote__f textarea{transition:none}
}

/* --- the prayer mark ------------------------------------------------------
   Two hands, palms together, drawn in the same 24-box and round-capped stroke
   as the rest of the app. It replaces an emoji, which is a different typeface
   on every phone, is colored whether the button is or not, and shifts weight
   the moment the button is pressed. Praying hands is a hard shape at 17px —
   this one keeps the center seam and the fingers on both sides, which are the
   two things that make it read as hands rather than a leaf. */
.pw__ic{width:18px;height:18px;flex:none}
.pw__report.is-done{display:inline-flex;align-items:center;gap:.4em}
.pw__report.is-done .pw__ic{width:14px;height:14px}

/* The inbox on the website (not the installed app). The section's padding is
   taken away above so a conversation can run edge to edge, which left the
   list hard against the Client Area bar and a short page ending in a strip of
   blank page under the footer. The list gets its breathing room back, and the
   page is at least a screen tall so the footer sits at the bottom. */
html.msg-app:not(.msg-solo):not(.app-mode) .msgwrapper{padding-top:clamp(32px,5vw,56px);padding-bottom:clamp(56px,7vw,96px);}
html.msg-app:not(.msg-solo):not(.app-mode) main{min-height:calc(100vh - 140px);}
html.msg-app:not(.msg-solo):not(.app-mode) .msgtop{padding-bottom:14px;border-bottom:1px solid var(--line);}
html.msg-app:not(.msg-solo):not(.app-mode) .msgnew{box-shadow:none;}
