/* =================================================================
   YEC. — the portal system, both sides of the login
   =================================================================
   The spec is docs/design/canvas/build.py (the CSS block at the top) and
   System.dc.html, approved by Drew 2026-09-02. Every value here is that
   block, translated onto the class names the pages already use where a
   site class exists (.kicker not .kick, .form-input not .in, .btn-outline
   not .btn.o) and the canvas's own names where nothing existed (.chip,
   .ver, .tab, .tile, .face, .ev, .date, .cue).

   SCOPED TO body.pshell. site.js adds that class only on /members/ pages
   that got a sidebar (never /members/login, never /vote), so a page with
   no shell keeps the marketing chrome it had, and this file can be loaded
   by every page under /members/ without a second gate.

   The marketing site's .h1/.card/.btn are display-sized for a visitor
   arriving cold. Under the shell the same names take the working sizes:
   the bar already says where you are, so nothing inside needs to shout.

   TYPE FLOOR (R3, audit P1-023, S2-13): every size here is rem, so a
   member's own text size setting scales it, and nothing is under 12px
   (0.75rem). Tracked capital labels are 12px, buttons and filter tabs
   13px. The canvas CSS in build.py mirrors these values.
   ================================================================= */

/* ---- rhythm: the page is cream, the cards are white ---- */
body.pshell .section { background: transparent; padding-block: 0 clamp(14px, 2vw, 22px); }
body.pshell .section + .section { border-top: 0; }
body.pshell .section.bg-white, body.pshell .section.bg-cream { background: transparent; }
/* left-aligned, like the canvas: the hero and the cards share one left edge
   instead of a centred 880px hero over a full-width grid */
body.pshell .container { padding-inline: clamp(14px, 2.4vw, 26px); margin-inline: 0; max-width: 1400px; }
body.pshell .container.narrow { max-width: 880px; }
body.pshell { font-size: 0.9375rem; }
body.pshell .page-hero { padding-top: clamp(16px, 2.2vw, 24px); }
body.pshell .page-hero.portal-hero { padding-bottom: clamp(10px, 1.4vw, 16px); }
body.pshell .page-hero + .section { padding-top: 0; }

/* ---- type ---- */
/* THE ONE H1 RULE: 23px on a phone, 28px above 900px (the system's t-h1).
   It names .page-hero .h1 too, so chrome.css's hero clamp (20.8 to 27.2px)
   stops winning; Stream A deletes that rule in S3-01. The max-width is
   chrome's, kept here so the delete changes nothing. */
body.pshell .page-hero .h1, body.pshell .h1 { font-family: var(--font-body); font-weight: 600; font-size: 1.75rem; letter-spacing: -0.01em; line-height: 1.2; max-width: 34ch; }
body.pshell .h2 { font-family: var(--font-body); font-weight: 600; font-size: 1.25rem; line-height: 1.25; letter-spacing: 0; }
/* Section headings on member pages are h2.h2, the boards' 20px y-h2 open
   sections (QA4 D-5, Drew 09-26). THE CARD LABEL below is the staff pages'
   h2.h3: a small Montserrat label, left as it was. */
body.pshell .h3 { font-family: var(--font-kicker); font-weight: 600; font-size: 0.75rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--kicker, var(--teal-deep)); /* QA4 B-5: one kicker colour per theme (orange in dark, as y-kicker) */ line-height: 1.4; }
/* Card sub-heading ("Your answer", "Share preview"): the system's t-h3. With no
   rule .h4 fell to the browser's h2/h3 size, up to 22.5px (audit P1-023). */
body.pshell .h4 { font-family: var(--font-body); font-weight: 600; font-size: 1rem; line-height: 1.375; letter-spacing: 0; }
body.pshell .lead { font-size: 1rem; color: var(--gray); line-height: 1.55; max-width: 52ch; }
body.pshell .small { font-size: 0.875rem; color: var(--gray); }
/* A link inside a sentence shows as a link: the link token and an underline,
   not colour alone (WCAG 1.4.1, audit P1-031, S1-07). Unclassed links only, so
   buttons, tabs and arrow links keep their own look. */
body.pshell a.u, body.pshell main :is(p, li, dd, label) a:not([class]) { color: var(--link, #005E7A); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
body.pshell .meta { font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.75rem; color: var(--slate); }
body.pshell .mono { font-variant-numeric: tabular-nums; }
body.pshell .nm { font-size: 0.96875rem; font-weight: 600; line-height: 1.25; }
body.pshell .co { font-size: 0.78125rem; color: var(--gray); }
@media (max-width: 900px) { body.pshell .page-hero .h1, body.pshell .h1 { font-size: 1.4375rem; } }
/* An H1 that only repeats the phone top bar's name (People, Library, Press...)
   is sr-only at 900px and below: still the page's one H1, the lead stays in
   view (QA4 D-1, Drew 09-26; People.html:2). Desktop keeps it. */
@media (max-width: 900px) { body.pshell .bar-named { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } }

/* ---- buttons: square, like the brand's ---- */
body.pshell .btn { justify-content: center; font-size: 0.8125rem; padding: 13px 20px; min-height: 44px; white-space: nowrap; }
body.pshell .btn:hover { transform: none; }
body.pshell .btn-outline { color: var(--navy); border-color: currentColor; }
/* the two endings, and nowhere else */
body.pshell .btn-maybe { background: var(--white); border-color: var(--teal); color: var(--teal-deep); }
body.pshell .btn-maybe:hover { background: var(--teal); color: var(--white); }
body.pshell .btn-decline { background: var(--white); border-color: var(--bad, #a63d2f); color: var(--bad, #a63d2f); }
body.pshell .btn-decline:hover { background: var(--bad, #a63d2f); color: var(--white); }
body.pshell .btn-quiet { background: var(--white); border-color: #D2D2CA; color: var(--gray); }
body.pshell .btn-quiet:hover { border-color: var(--teal); color: var(--teal-deep); }
body.pshell .btn:disabled, body.pshell .btn[aria-disabled="true"] { opacity: 0.45; cursor: default; }
body.pshell .btn-sm { padding: 10px 14px; min-height: 36px; font-size: 0.75rem; }
/* 44px under a thumb: RSVP, Answer this and Withdraw were the smallest
   buttons on the page (audit P1-024, S1-07). */
@media (pointer: coarse), (max-width: 900px) { body.pshell .btn-sm { min-height: 44px; } }
/* A full-width phone button wraps its label rather than run past the screen:
   at 13px "Draft one from my profile" needed 296px at 320 (S2-13). 1.3 line
   height so two lines do not touch; one line still sits in the 44px box. */
@media (max-width: 900px) { body.pshell .btn:not(.btn-sm) { width: 100%; white-space: normal; text-align: center; line-height: 1.3; } }

/* ---- cards ---- */
body.pshell .card { padding: 18px 20px; display: flex; flex-direction: column; gap: 12px; height: auto; }
body.pshell .card.tight { padding: 14px 16px; gap: 10px; }
/* the gap is the rhythm inside a card; the pages' mt- spacers would stack on it */
body.pshell .card > .mt-1, body.pshell .card > .mt-2, body.pshell .card > .mt-3 { margin-top: 0; }
body.pshell .card > p:last-child { margin-bottom: 0; }
body.pshell .tile { background: var(--white); border: 1px solid rgba(23, 32, 41, 0.10); padding: 16px 18px; display: flex; flex-direction: column; gap: 6px; text-decoration: none; color: inherit; }
body.pshell .tile .n { font-family: var(--font-body); font-weight: 300; font-size: 2.375rem; line-height: 1; letter-spacing: -0.02em; color: var(--navy); }
body.pshell .tile.hot { border-top: 3px solid var(--orange); }
a.tile:hover { border-color: var(--teal); }

/* ---- layout ---- */
body.pshell .grid { gap: 16px; }
body.pshell .cols { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 18px; align-items: start; }
/* --stack: 0 turns off styles.css's .stack margin, which added 19px on top of the gap (31px, audit P1-012). */
body.pshell .stack { display: flex; flex-direction: column; gap: 12px; --stack: 0; }
body.pshell .row { display: flex; align-items: center; gap: 12px; }
body.pshell .between { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* A card-header link is a touch target too (Lighthouse target-size, hub "Directory" link, 2026-09-03). */
body.pshell .between > a.small { display: inline-flex; align-items: center; min-height: 24px; padding: 2px 0; }
body.pshell .rule { height: 1px; background: var(--line, #DCDCD4); }
/* Tables on a phone (Drew, 2026-09-03: "staff is not mobile responsive at
   all"). Every portal table carries .stack-phone: under 700px the rows
   become cards and each cell leads with its column name (data-label, set by
   site.js initStackTables from the header). The page never scrolls sideways;
   a page-scoped min-width on the table is overridden here on purpose. */
@media (max-width: 700px) {
  body.pshell table.stack-phone { display: block; width: 100% !important; min-width: 0 !important; border-collapse: collapse; }
  body.pshell table.stack-phone thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  body.pshell table.stack-phone tbody, body.pshell table.stack-phone tr, body.pshell table.stack-phone td { display: block; width: 100%; box-sizing: border-box; }
  body.pshell table.stack-phone tr { border: 1px solid var(--cool-light); border-radius: 4px; padding: 10px 12px; margin: 0 0 10px; background: var(--white); }
  body.pshell table.stack-phone td { padding: 6px 0 !important; border: 0 !important; font-size: 0.92rem; }
  body.pshell table.stack-phone td:empty { display: none; }
  body.pshell table.stack-phone td[data-label]:not([data-label=""])::before { content: attr(data-label); display: block; font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.75rem; color: var(--slate); margin-bottom: 2px; }
  body.pshell table.stack-phone .am-nowrap, body.pshell table.stack-phone .ae-num { white-space: normal; }
}
/* phone first: one column, always. Grids start at 900px. */
@media (max-width: 900px) {
  body.pshell .grid-2, body.pshell .grid-3, body.pshell .grid-4, body.pshell .cols { grid-template-columns: 1fr; }
}
@media (min-width: 901px) and (max-width: 1200px) {
  body.pshell .grid-3, body.pshell .grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* ---- chips and states ---- */
body.pshell .chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
body.pshell .chip { font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.75rem; padding: 4px 8px; border-radius: 3px; border: 1px solid var(--cool-light); color: var(--slate); background: var(--white); display: inline-block; line-height: 1.3; }
/* A chip that is a button is a filter, so it gets a thumb-sized box; a
   span.chip is a badge and keeps its size (audit P1-025, S1-07). */
@media (pointer: coarse), (max-width: 900px) { body.pshell button.chip { min-height: 44px; display: inline-flex; align-items: center; } }
body.pshell .chip.yes { background: var(--good, #1f6f54); border-color: var(--good, #1f6f54); color: var(--white); }
body.pshell .chip.no { background: var(--bad, #a63d2f); border-color: var(--bad, #a63d2f); color: var(--white); }
body.pshell .chip.conflict { background: var(--slate); border-color: var(--slate); color: var(--white); }
body.pshell .chip.quiet { background: #F2F2EE; border-color: #F2F2EE; color: var(--gray); } /* #8A8F94 was 2.9:1; --gray is 6.5:1 (axe, M1) */
body.pshell .ver { display: inline-block; font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.75rem; padding: 5px 8px; border-radius: 3px; background: var(--cool-light); color: var(--navy); line-height: 1.3; }
body.pshell .ver.advance { background: var(--good, #1f6f54); color: var(--white); }
body.pshell .ver.hold { background: var(--bad, #a63d2f); color: var(--white); }
body.pshell .ver.yours { background: var(--teal); color: var(--white); }
/* "All three have voted. Choose the ending." The next step, not an alarm. */
body.pshell .cue { font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.07em; font-size: 0.75rem; color: var(--navy); background: #FBF3E8; padding: 8px 10px; display: flex; align-items: center; gap: 8px; margin: 0; }
body.pshell .cue::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--orange); flex: 0 0 auto; }
body.pshell .notice { background: #FBF3E8; padding: 14px 16px; display: flex; gap: 12px; align-items: flex-start; }
body.pshell .empty { padding: 22px; border: 1px dashed #C9CBC3; color: var(--gray); font-size: 0.875rem; text-align: center; }

/* ---- filters: a group of toggles, not a tablist ---- */
body.pshell .tabs { display: flex; gap: 8px; flex-wrap: wrap; }
body.pshell .tab { font-family: var(--font-kicker); font-weight: 600; text-transform: uppercase; letter-spacing: 0.09em; font-size: 0.8125rem; padding: 12px 14px; border-radius: 3px; border: 1px solid var(--cool-light); background: var(--white); color: var(--slate); min-height: 44px; display: inline-flex; align-items: center; gap: 6px; cursor: pointer; line-height: 1; }
/* One filter count: the number after a tab's label. Events used the sidebar's
   orange .ps-cnt pill, which reads as "new" (audit P1-025, S1-07). */
body.pshell .tab b, body.pshell .tab .ps-cnt { color: var(--teal-deep); font-weight: 700; font-variant-numeric: tabular-nums; }
body.pshell .tab .ps-cnt { font: inherit; font-weight: 700; background: none; border-radius: 0; padding: 0; margin: 0; min-width: 0; }
body.pshell .tab:hover:not(:disabled) { border-color: var(--teal); }
body.pshell .tab:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
body.pshell .tab.on { background: var(--navy); border-color: var(--navy); color: var(--white); }
body.pshell .tab.on b, body.pshell .tab.on .ps-cnt { color: var(--orange); }
body.pshell .tab:disabled, body.pshell .tab.off { opacity: 0.5; cursor: default; }
/* The Press tab bar (_includes/press-tabs.njk) is the shell's .ps-tabs row
   (chrome.css); a count that has not loaded stays out of sight. */
body.pshell .press-tabs .ps-cnt:empty { display: none; }
/* a segmented answer: the same toggle in body type */
body.pshell .seg { display: flex; gap: 6px; flex-wrap: wrap; }
body.pshell .seg .tab { flex: 1 1 auto; justify-content: center; text-transform: none; letter-spacing: 0; font-family: var(--font-body); font-weight: 400; font-size: 0.875rem; }
body.pshell .seg .tab.on { font-weight: 600; }

/* ---- a person ---- */
body.pshell .face { width: 38px; height: 38px; border-radius: 50%; background: var(--cool-light); color: var(--slate); display: grid; place-items: center; font-family: var(--font-kicker); font-weight: 700; font-size: 0.75rem; flex: 0 0 auto; position: relative; overflow: hidden; }
body.pshell .face.lg { width: 56px; height: 56px; font-size: 0.9375rem; }
body.pshell .face.sm { width: 28px; height: 28px; font-size: 0.75rem; }
/* a headshot layers over the initials, so a 404 reveals them with no reflow */
body.pshell .face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* ---- a row: a date block or an icon, two lines, an action ---- */
body.pshell .ev { display: flex; gap: 14px; align-items: flex-start; padding: 12px 0; border-top: 1px solid #EFEFE9; margin: 0; }
body.pshell .ev:first-child, body.pshell .h3 + .ev, body.pshell .h2 + .ev, body.pshell .between + .ev { border-top: 0; padding-top: 0; }
body.pshell .ev > .grow { flex: 1 1 auto; min-width: 0; }
body.pshell .evt { font-size: 0.90625rem; font-weight: 600; line-height: 1.3; }
body.pshell .evs { font-size: 0.78125rem; color: var(--gray); margin-top: 2px; }
body.pshell .date { font-family: var(--font-kicker); font-weight: 700; font-size: 0.9375rem; color: var(--navy); text-align: center; line-height: 1.1; width: 44px; flex: 0 0 44px; padding: 6px 0; background: var(--cool-light); }
body.pshell .date span { display: block; font-weight: 600; font-size: 0.75rem; letter-spacing: 0.12em; color: var(--gray); margin-top: 2px; }

/* ---- forms: the label above, the hint above the box ---- */
body.pshell .form-row { gap: 6px; margin-bottom: 14px; }
/* A grid child defaults to min-width:auto, so one wide select stretches the whole row past a phone screen (events admin, 2026-09-03). */
body.pshell .form-row > * { min-width: 0; max-width: 100%; }
body.pshell .form-label { font-size: 0.75rem; }
/* 16px, not less: iPhone Safari zooms the page into any field under 16px and leaves it zoomed (S1-06). */
/* Role tokens (S1-08, audit P1-008): #C9CBC3 borders were 1.64:1 and #8A8F94
   hints 3.26:1 on white. field-line is 3.8:1, ink-2 6.8:1. Staff pages do not
   load css/tokens.css, so every var() carries the light value as fallback. */
body.pshell .form-input, body.pshell .form-textarea { border: 1px solid var(--field-line, #7D8388); padding: 12px; font-size: 1rem; min-height: 44px; }
body.pshell .form-textarea { min-height: 96px; }
body.pshell .hint { font-size: 0.78125rem; color: var(--ink-2, #555C63); }
body.pshell .srch { display: flex; align-items: center; gap: 10px; border: 1px solid var(--field-line, #7D8388); background: var(--white); padding: 0 12px; min-height: 44px; flex: 1 1 auto; }
body.pshell .srch input { border: 0; outline: 0; background: transparent; font: inherit; font-size: 1rem; flex: 1 1 auto; min-width: 0; color: var(--navy); }
/* The post-event rating (js/members/events.js). State by shape, not colour
   alone: a chosen star is filled, an open one is an outline. Both marks clear
   3:1 (the old #C9CBC3 and orange were 1.64:1 and 2.69:1). Outranks the
   page's own .ev-star colours in members/events.njk. */
body.pshell .ev-star { color: transparent; -webkit-text-stroke: 1.5px var(--field-line, #7D8388); }
body.pshell .ev-star.on { color: var(--mark, #B86800); -webkit-text-stroke-color: var(--mark, #B86800); }
body.pshell .ev-star:hover { -webkit-text-stroke-color: var(--mark, #B86800); }

/* ---- tables ---- */
body.pshell table { width: 100%; border-collapse: collapse; font-size: 0.84375rem; }
body.pshell th { font-family: var(--font-kicker); font-weight: 600; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--slate); text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line, #DCDCD4); }
body.pshell td { padding: 11px 10px; border-bottom: 1px solid #EFEFE9; vertical-align: middle; }
body.pshell tr:last-child td { border-bottom: 0; }
body.pshell .table-wrap { overflow-x: auto; }
body.pshell .prog { height: 6px; background: var(--cool-light); width: 120px; position: relative; display: inline-block; }
body.pshell .prog i { position: absolute; left: 0; top: 0; bottom: 0; background: var(--teal); }

/* ---- the question list (application, interview sheet) ---- */
body.pshell .q { display: flex; gap: 12px; align-items: flex-start; padding: 12px 0; border-top: 1px solid #EFEFE9; }
body.pshell .q .num { font-family: var(--font-kicker); font-weight: 700; font-size: 0.75rem; color: var(--teal-deep); width: 22px; flex: 0 0 22px; padding-top: 3px; }
body.pshell .q .qt { font-size: 0.90625rem; font-weight: 600; line-height: 1.35; }
body.pshell .q .qn { font-size: 0.8125rem; color: var(--gray); margin-top: 2px; white-space: pre-line; overflow-wrap: anywhere; }

/* ---- the sidebar count ---- */
.ps-cnt { margin-left: auto; font-family: var(--font-kicker); font-weight: 700; font-size: 0.75rem; background: var(--orange); color: var(--on-accent, #172029); /* navy on orange: 6:1; white on orange was 2.7:1 (Lighthouse, 2026-09-03) */ border-radius: 9px; padding: 1px 6px; min-width: 20px; text-align: center; line-height: 1.5; }

/* ---- the back link, in the system's quiet voice ---- */
body.pshell .pf-linkbtn { border-radius: 0; }

/* ---- the filter box on the admin pages: a card, not a marketing form ---- */
body.pshell .form-mock { padding: 18px 20px; border-color: rgba(23, 32, 41, 0.10); }
/* Staff perks "New category" row: at the 12px floor its label, 200px field and
   Add button need 357px, past a 390 phone, so the row wraps (S2-13).
   ponytail: page rule kept here because members/admin/perks.njk is Stream A's
   file until Thu Sep 24; move it into that page's style then. */
body.pshell .ap-cat-add { flex-wrap: wrap; }

/* The hidden attribute must beat every display rule below it. Without this a
   .chip or .btn (display: inline-flex) with hidden="" still renders, which is
   how "You are in" showed before an RSVP on the home hub (2026-09-03). */
body.pshell [hidden] { display: none !important; }

/* ---- member home hub (M1, 2026-09-03) ---- */
body.pshell .evmain { flex: 1; min-width: 0; }
body.pshell .nm.done { text-decoration: line-through; color: var(--gray); }
body.pshell .mp-prog { display: block; width: 100%; margin: 4px 0 2px; }
body.pshell a.nm { color: inherit; text-decoration: none; }
body.pshell a.nm:hover { text-decoration: underline; }
body.pshell .chip[href] { text-decoration: none; }

/* ---- the list pager (Press Profiles, Placements, Inbox) ----
   One row on a desktop: the range left, the controls right, all centred on
   one line. On a phone the range takes its own line and the controls share
   the next, with Previous and Next splitting the spare width so both are an
   easy thumb target. The select stays as narrow as its longest option.
   The controls wrap, so at 320 Next drops to its own full-width line
   instead of running off the screen (P1-029, S1-06). */
body.pshell .pp-pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; margin-top: 12px; }
body.pshell .pp-pager .pp-range { margin: 0; }
body.pshell .pp-pager-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }
body.pshell .pp-pager-controls label { margin: 0; white-space: nowrap; }
body.pshell .pp-pager .pp-per { width: auto; flex: 0 0 auto; min-height: 36px; padding: 6px 8px; }
@media (pointer: coarse), (max-width: 900px) { body.pshell .pp-pager .pp-per { min-height: 44px; } }
@media (max-width: 700px) {
  body.pshell .pp-pager .pp-range { flex: 1 0 100%; }
  body.pshell .pp-pager-controls { flex: 1 1 100%; margin-left: 0; }
  body.pshell .pp-pager-controls .btn { flex: 1 1 0; min-height: 44px; }
}

/* ---- status and error lines (audit P1-026, S1-07) ----
   Every page styles its own .xx-msg line as tiny Montserrat capitals, so an
   error on first sign-in read like a label. One rule for all of them: 15px
   body type in the sentence case the scripts write, and one error colour.
   A class token ending in -msg, wherever it sits: scripts append .show and
   .err, so [class$="-msg"] alone lets go the moment a line appears.
   :root rather than body.pshell: sign-in has no shell and its line is the
   first a member reads (portal.css loads on member pages only). It also
   lifts the rule over body.pshell .small, which kept Pitch's lines at 13px and
   its errors grey. A page's #id rule still wins (billing's portal note). */
:root :is([class$="-msg"], [class*="-msg "]):is([role="status"], [role="alert"]) { font-family: var(--font-body); font-weight: 400; font-size: 0.9375rem; line-height: 1.45; letter-spacing: normal; text-transform: none; }
:root :is([class$="-msg"], [class*="-msg "]):is([role="status"], [role="alert"]):is(.err, .bad, [data-bad="1"]) { color: var(--bad, #A63D2F); }

/* ---- dark mode (S3-02, CP0 B10: every member page) ----
   Only under html[data-theme="dark"], which theme.js sets on a page that
   carries data-dark-ready. Light values are untouched.
   1. The legacy colour names. styles.css, pages.css, this file and every
      page's own <style> paint with the marketing names (--white cards,
      --navy text, --cream bands, --teal links). In the page content and the
      footer each name points at its dark role token, so a fill and the text
      on it flip together (navy button with white text becomes the cream
      strong fill with dark text). The shell (sidebar, top bar) is chrome.css,
      Stream A's, on tokens of its own, so it is left out of the remap.
      --teal-deep and --accent-ink go to the link blue, not the orange kicker:
      orange is for the main action and unread items only. --orange stays. */
[data-theme="dark"] :is(main, .ps-footer) {
  --white: var(--surface);
  --cream: var(--bg);
  --navy: var(--ink);
  --navy-soft: var(--raised);
  --slate: var(--ink-2);
  --gray: var(--ink-2);
  --charcoal: var(--ink-2);
  --cool-light: var(--raised);
  --teal: var(--link);
  --teal-deep: var(--link);
  --accent-ink: var(--link);
}
/* 2. Light-only literals with no token of the same value: borders drawn in
      navy at 10 to 22% and the pale fills. Accent tints mix the token. */
[data-theme="dark"] :is(main, .ps-footer) :is(.card, .tile, .form-mock, .res-card, .faq-list, .faq-item, .event-row, .embed-note, .empty),
[data-theme="dark"] body.pshell :is(td, .ev, .q, .btn-quiet) { border-color: var(--line); }
[data-theme="dark"] body.pshell .chip.quiet { background: var(--raised); border-color: var(--raised); }
/* The token first: a value with var() in it is never dropped at parse time, so
   a browser without color-mix would paint it transparent, not fall back. */
[data-theme="dark"] body.pshell :is(.cue, .notice) { background: var(--tint-warn); }
@supports (background: color-mix(in srgb, red 50%, blue)) { [data-theme="dark"] body.pshell :is(.cue, .notice) { background: color-mix(in srgb, var(--accent) 14%, var(--surface)); } }
/* 3. Orange text on the cream selected tab was 2.2:1; decorative orange
      (list markers, quote rules) takes the link blue. */
[data-theme="dark"] body.pshell .tab.on :is(b, .ps-cnt) { color: var(--on-strong); }
[data-theme="dark"] main .prose li::marker { color: var(--link); }
[data-theme="dark"] main .prose blockquote { border-left-color: var(--link); }

/* QA-4 C-7: a block that fills from the API (Home's hub, Events, Pitch) is
   laid out but unseen until its page script's first render, so rows landing
   in any order move nothing a member can see (layout shift counts only what
   is painted). Revealing it is not a shift. If the script never runs, it
   shows by itself after 4 seconds. */
body.pshell .ps-wait { visibility: hidden; animation: ps-wait 0s 4s forwards; }
@keyframes ps-wait { to { visibility: visible; } }

/* QA-4 A-4: the booking sheet's Book button names a whole date and time. On
   a phone the two footer buttons take their own widths and wrap to two rows
   when the time is long, rather than squeezing it into half the footer. */
@media (max-width: 900px) {
  #book-sheet .y-sheet__foot { flex-wrap: wrap; }
  #book-sheet .y-sheet__foot > .y-btn { flex: 1 1 auto; }
}

/* The staff preview bar (Drew 2026-09-28): site.js draws it at the top of
   main while a staff member previews the portal as a member group. Fixed
   colours in both themes: it must never read as part of the member's page. */
.y-preview-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px;
  padding: 10px 16px; background: #005E7A; color: #FFFFFF; font-size: .92rem; font-weight: 600; }
.y-preview-bar__exit { min-height: 44px; padding: 0 16px; border: 1.5px solid #FFFFFF; border-radius: 6px;
  background: transparent; color: #FFFFFF; font: inherit; cursor: pointer; }
.y-preview-bar__exit:hover { background: rgba(255, 255, 255, .14); }
.y-preview-bar__exit:focus-visible { outline: 2px solid #FFFFFF; outline-offset: 2px; }


/* ---- One list page pattern: tabs, a filter row, a filter sheet ----
   Press (Drew 10-01, after the Mobbin review) and the Library use the same
   pieces, so they look and behave alike. The tabs stick under the 53px
   portal header; each section carries data-tab and shows only on its tab
   (main[data-tab]); the filter row is Filters (n), quick toggles and a
   removable chip; the sheet is a yecSheet dialog. */
.p-tabs { position: sticky; top: 53px; z-index: 5; display: flex; width: 100%; margin: 12px 0; background: var(--surface, #fff); }
.p-tabs button { flex: 1 1 0; min-height: 44px; padding: 0 6px; }
.p-tabs .n { font-weight: 400; margin-left: 2px; }
.p-tabs button[aria-pressed="true"] { background: var(--slate); color: var(--white); }
main[data-tab="you"] [data-tab]:not([data-tab="you"]):not(button),
main[data-tab="all"] [data-tab]:not([data-tab="all"]):not(button),
main[data-tab="mine"] [data-tab]:not([data-tab="mine"]):not(button),
main[data-tab="done"] [data-tab]:not([data-tab="done"]):not(button) { display: none; }
.p-tools { display: flex; gap: 6px; margin: 8px 0 0; }
.p-tools .btn { min-height: 44px; flex: 0 1 auto; min-width: 0; padding-left: 10px; padding-right: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-tools .n:not(:empty)::before { content: " ("; } .p-tools .n:not(:empty)::after { content: ")"; }
/* body.pshell: the portal's own .btn-outline colour (above) outranked a
   plain .p-tools rule and left a pressed label unreadable (1.35:1, 390px
   check 10-01). Hover keeps it too. */
body.pshell .p-tools [aria-pressed="true"], body.pshell .p-tools [data-chip],
body.pshell .p-tools [aria-pressed="true"]:hover, body.pshell .p-tools [data-chip]:hover { background: var(--slate); border-color: var(--slate); color: var(--white); }
.p-results { display: flex; align-items: center; gap: 8px; min-height: 36px; }
.p-results > p { margin: 0; }
.p-fsheet fieldset { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.p-fsheet .y-check { min-height: 44px; align-items: center; }

/* Arrow links are 44px tap targets everywhere in the portal (10-07), not page by page. */
body.pshell .link-arrow { min-height: 44px; align-items: flex-end; }
