/* The Ralph Prize: component styles. Copied from prototypes/take-1/design.css (everything after the :root block,
   which lives in tokens.css) minus prototype-only rules (packet strip, PROTOTYPE bar, toast, back link).
   Deviations from the prototype are marked "RP-4:" and listed in docs/shell.md. */
* { box-sizing: border-box; }
html { color-scheme: light; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--sans); font-size: 15px; line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--teal); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { color: var(--navy); margin: 0; font-weight: 700; letter-spacing: -0.01em; }
/* Headings carry admin-entered contest names (up to 60 characters, RP-V0-78): an unbroken one wraps, never widens the page. */
h1, h2, h3, h4 { overflow-wrap: break-word; }
h1 { font-size: 34px; line-height: 1.15; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }
p { margin: 0 0 10px; }
strong { color: var(--ink); font-weight: 700; }
button { font: inherit; cursor: pointer; }
input, select, textarea { font: inherit; }

/* Header + sub-bar (shell.js injects these) */
.rp-header {
  background: var(--navy); color: #fff; height: 72px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--gutter);
}
.rp-logo { font-weight: 700; font-size: 22px; letter-spacing: 0.02em; color: #fff; text-decoration: none; }
.rp-logo:hover { text-decoration: none; }
.rp-logo em { font-style: normal; color: var(--teal-light); }
/* RP-V0-86: the test phase pill (RP_PHASE_LABEL) sits right of the brand mark. The mark never shrinks, so it keeps its
   size whether the pill is there or not, and the header wraps rather than squeezes: when brand and nav do not fit on one
   row the nav drops to a second row (as on the phone header), and a brand wider than the page wraps its pill under the
   mark. On the desktop header the prototype's fixed 72px height becomes a minimum; one row renders as before. */
@media (min-width: 901px) {
  .rp-header { flex-wrap: wrap; height: auto; min-height: 72px; padding-block: 8px; gap: 10px 12px; }
}
/* The sticky desktop header (Atin ruling 2026-09-27, client round 6): above 900 px the header stays in view while the page
   scrolls, so Report an issue and the account menu (Sign out is in it) stay in view on a long page. Only the header sticks; the
   sub-bar scrolls away. At 900 px and below it stays in flow: the phone header is two rows and would cover too much of a
   story. Its z-index sits above page content and popovers (the conflict panel is 40) and below the reader's overlays (50)
   and the skip link (100); the Report an issue panel lives inside it, so it still opens above the page. Its height is one
   72 px row or two when it wraps, so src/shell/client/header.ts publishes it as --rp-header-h (72 px without script), and
   scroll-padding-top keeps anchors, the skip link's target and focused elements clear of it, never under it. The header
   itself and everything in it sit inside that padded strip, so Chrome would scroll the page to "reveal" any of them when it
   takes focus or is scrolled into view (Tab, the focus the issue panel hands back to its button, the phase pill); a scroll
   margin that shifts their box down by the padding tells it they are already in view. The issue panel and the account menu's
   panel are left out: each is its own scroll region, and a shifted box would hide its first items from its own scrolling. */
@media (min-width: 901px) {
  html { scroll-padding-top: calc(var(--rp-header-h, 72px) + 8px); }
  .rp-header { position: sticky; top: 0; z-index: 45; }
  .rp-header, .rp-header :not(.rp-issue-panel):not(.rp-issue-panel *):not(.rp-account-panel):not(.rp-account-panel *) {
    scroll-margin-top: calc(-1 * (var(--rp-header-h, 72px) + 8px)); scroll-margin-bottom: calc(var(--rp-header-h, 72px) + 8px);
  }
}
.rp-brand { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; min-width: 0; }
.rp-brand .rp-logo { flex: none; white-space: nowrap; }
.rp-phase { flex: none; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.rp-nav { display: flex; align-items: center; gap: 18px; font-size: 15px; }
.rp-nav a { color: #fff; }
.rp-subbar {
  background: var(--bar); border-bottom: 1px solid var(--border); height: 42px;
  display: flex; align-items: center; gap: 32px; padding: 0 var(--gutter); font-size: 14px;
}
.rp-subbar b { color: var(--navy); font-weight: 700; }
.rp-subbar span { color: var(--muted); }

/* Page frame */
.rp-page { max-width: var(--maxw); margin: 0 auto; padding: 36px var(--gutter) 96px; }
.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--teal); margin-bottom: 10px;
}
.eyebrow.navy { color: var(--navy); }
.lede { font-size: 18px; color: var(--text); margin: 14px 0 22px; }
.title-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 22px; }

/* Grid helpers */
.grid { display: grid; gap: 24px; }
.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-5 { grid-template-columns: repeat(5, 1fr); }
.grid-64 { grid-template-columns: 1.45fr 1fr; }
.grid-46 { grid-template-columns: 1fr 1.45fr; }
@media (max-width: 900px) {
  /* the prototype's responsive override of the gutter token; the token block itself stays in tokens.css */
  :root { --gutter: 16px; }
  .grid-2, .grid-3, .grid-4, .grid-5, .grid-64, .grid-46 { grid-template-columns: 1fr; }
  .rp-header { height: auto; padding: 12px var(--gutter); flex-wrap: wrap; gap: 10px; }
  .choice { grid-template-columns: 1fr; }
  h1 { font-size: 26px; }
}

/* Cards */
.card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 28px 28px 26px;
}
.card.dark { background: var(--navy); color: #fff; border-color: var(--navy); }
.card.dark h2, .card.dark h3, .card.dark strong { color: #fff; }
.card.dark .eyebrow { color: var(--teal-light); }
.card.dark .kv { border-color: rgba(255,255,255,0.35); }
.card.dark .kv span { color: rgba(255,255,255,0.85); }
.card.dark .kv b { color: #fff; }
.stat .label { font-size: 13px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 10px; }
.stat .value { font-size: 30px; font-weight: 700; color: var(--navy); line-height: 1.1; margin-bottom: 8px; font-variant-numeric: tabular-nums; }
.stat .sub { font-size: 13px; color: var(--muted); }
/* A tile whose value is words, not a number (the assignment mode): one line at a size that fits a quarter-width card, never broken mid-word. */
.stat .value.value-text { font-size: 22px; line-height: 34px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Key/value rows */
.kv { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.kv:last-child { border-bottom: 0; }
.kv span { color: var(--text); }
/* The label wraps only between words, even inside a card that lets long values break anywhere (the value keeps that). */
.kv > span:first-child { overflow-wrap: normal; word-break: normal; }
.kv b { color: var(--ink); font-variant-numeric: tabular-nums; text-align: right; min-width: 0; overflow-wrap: anywhere; }
.kv a { font-weight: 700; }
/* A value that swaps text keeps reserved space (34ch fits both), never more than the row: on a narrow card it takes its own line. */
.kv.rp-live-row { flex-wrap: wrap; }
.kv.rp-live-row b { min-width: min(34ch, 100%); margin-left: auto; }

/* Callouts */
.callout { background: var(--info-bg); border-left: 4px solid var(--teal); padding: 14px 20px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; color: var(--navy-2); }
.callout.plain { border-left: 0; border-radius: var(--radius-sm); }
.callout.warn { background: var(--warn-bg); border: 1px solid var(--warn-border); border-left-width: 1px; border-radius: var(--radius-sm); }
.callout b { display: block; color: var(--ink); }
.note { font-size: 13px; color: var(--muted); }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-width: 128px; height: 46px; padding: 0 22px; border-radius: var(--radius-sm);
  font-weight: 700; font-size: 15px; border: 1px solid transparent; white-space: nowrap;
}
.btn.primary { background: var(--teal); color: #fff; }
.btn.primary:hover { background: var(--teal-dark); }
.btn.outline { background: #fff; color: var(--navy); border-color: var(--border); }
.btn.outline:hover { border-color: var(--navy); }
.btn.navy { background: var(--navy); color: #fff; }
.btn.block { width: 100%; }
.btn.sm { height: 38px; min-width: 96px; padding: 0 16px; font-size: 14px; }
.btn.upper { text-transform: uppercase; letter-spacing: 0.04em; }
.btn:disabled, .btn.disabled { background: var(--disabled); color: var(--muted); border-color: var(--disabled); cursor: not-allowed; }
/* A disabled primary must not turn teal under the pointer: the hover rule above has the same specificity and comes first. */
.btn:disabled:hover, .btn.disabled:hover { background: var(--disabled); border-color: var(--disabled); }
.btn-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.btn-row.end { justify-content: flex-end; }
.link-btn { background: none; border: 0; color: var(--teal); font-weight: 700; padding: 0; }

/* Segmented / choice tiles (fixed width so labels never shift layout) */
/* RP-4: minmax(0, 1fr) so a longer label can never widen a track (SPEC-100); the prototype used 1fr 1fr. */
.choice { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.choice button {
  text-align: left; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 18px 20px; color: var(--navy); min-height: 100px;
}
.choice button b { display: block; font-size: 16px; margin-bottom: 6px; color: var(--navy); }
.choice button span { color: var(--text); font-size: 14px; }
.choice button[aria-pressed="true"] { border: 2px solid var(--teal); background: var(--info-bg); padding: 17px 19px; }

/* Forms */
.field { margin-bottom: 18px; }
.field label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin-bottom: 6px; }
.field .field-hint { margin: -2px 0 6px; font-size: 13px; color: var(--muted); } /* admin-field's `hint`: one plain line between the label and its box */
.field input[type=text], .field input[type=email], .field input[type=tel], .field input[type=search], .field select, .field textarea {
  width: 100%; height: 44px; padding: 0 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: #fff; color: var(--ink);
}
.field textarea { height: auto; min-height: 120px; padding: 10px 12px; line-height: 1.5; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--teal); outline-offset: 1px; border-color: var(--teal); }
.hint { font-size: 13px; color: var(--muted); margin-top: 6px; }
.check { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; color: var(--ink); cursor: pointer; }
.check input { width: 18px; height: 18px; margin: 2px 0 0; accent-color: var(--teal); flex: none; }

/* Scale pickers (1–5, 1–10) — fixed-width cells, never shift */
.scale { display: flex; gap: 6px; flex-wrap: wrap; }
.scale button {
  width: 40px; height: 36px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff;
  color: var(--teal); font-weight: 700; font-variant-numeric: tabular-nums;
}
.scale button[aria-pressed="true"] { background: var(--teal); color: #fff; border-color: var(--teal); }
/* RP-4: fixed width (the prototype's auto width let a label resize its button); wide enough for "Definitely not". */
.scale.wide button { width: var(--scale-w, 128px); padding: 0 8px; }
.anchors { display: flex; justify-content: space-between; font-size: 12px; color: var(--muted); margin-top: 6px; }

/* Badges / pills */
.pill {
  display: inline-block; padding: 4px 10px; border-radius: 999px; font-size: 11px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
}
.pill.teal { background: var(--info-bg); color: var(--ink); }
.pill.amber { background: var(--amber-bg); color: var(--amber); }
.pill.green { background: var(--green-bg); color: var(--green); }
.pill.red { background: var(--red-bg); color: var(--red); }
.pill.grey { background: var(--disabled); color: var(--muted); }
.pill.navy { background: var(--navy); color: #fff; }
.dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; background: var(--teal); margin-right: 12px; vertical-align: -1px; }
.dot.grey { background: var(--faint); }
.dot.amber { background: var(--amber); }
.dot.red { background: var(--red); }

/* Tables */
table.tbl { width: 100%; border-collapse: collapse; font-size: 15px; }
table.tbl th { text-align: left; font-size: 12px; color: var(--muted); font-weight: 700; padding: 8px 8px 10px; border-bottom: 1px solid var(--border); }
table.tbl td { padding: 14px 8px; border-bottom: 1px solid var(--border); color: var(--ink); vertical-align: middle; font-variant-numeric: tabular-nums; }
table.tbl tr:last-child td { border-bottom: 0; }
table.tbl .num { text-align: right; }
table.tbl .muted { color: var(--muted); }
table.tbl tr.selected td { background: var(--info-bg); }
table.tbl tr.clickable { cursor: pointer; }
table.tbl tr.clickable:hover td { background: #f7fafb; }

/* Steps */
.steps { list-style: none; margin: 0; padding: 0; }
.steps li { display: flex; gap: 16px; padding: 12px 0; }
.steps .n { flex: none; width: 32px; height: 32px; border-radius: 50%; background: var(--teal); color: #fff; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; }
.steps b { display: block; color: var(--navy); }
.steps span { font-size: 13px; color: var(--muted); }

/* Progress bar */
.bar { height: 8px; border-radius: 4px; background: var(--disabled); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--teal); }
.bar i.amber { background: var(--amber); }
.bar i.red { background: var(--red); }

/* Story typography (reader, preview) */
.story { font-family: var(--serif); color: var(--ink); font-size: 17px; line-height: 1.65; }
.story h2 { font-family: var(--serif); font-size: 26px; color: var(--navy); margin-bottom: 14px; }
.story p { margin: 0 0 14px; }
.story p.dim { color: var(--muted); }
.story mark { background: var(--highlight); color: inherit; padding: 2px 0; }
.story .marker {
  position: absolute; right: -32px; top: -6px; width: 28px; height: 28px; border-radius: 50%;
  background: var(--teal); color: #fff; font-family: var(--sans); font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.story .anch { position: relative; }

/* Tabs */
.tabs { display: flex; gap: 22px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.tabs button { background: none; border: 0; padding: 0 0 10px; color: var(--muted); font-weight: 700; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.tabs button[aria-selected="true"] { color: var(--teal); border-bottom-color: var(--teal); }



/* ---- RP-4 additions: shell chrome and shared components ---------------------------------- */
:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.rp-header :focus-visible { outline-color: var(--teal-light); }
.skip-link { position: absolute; left: 8px; top: -60px; z-index: 100; background: #fff; color: var(--navy); padding: 10px 14px; border-radius: var(--radius-sm); font-weight: 700; }
.skip-link:focus { top: 8px; }
.rp-nav a { padding: 4px 0; border-bottom: 2px solid transparent; }
.rp-nav a[aria-current="page"] { border-bottom-color: var(--teal-light); }
.rp-nav a.rp-cta { padding: 0 16px; height: 38px; min-width: 132px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid #fff; border-radius: var(--radius-sm); font-weight: 700; }
.rp-signout { margin: 0; display: inline-flex; }
.rp-signout button { background: none; border: 0; color: #fff; padding: 4px 0; border-bottom: 2px solid transparent; font: inherit; }
.rp-subbar .rp-status { margin-left: auto; min-width: 16ch; text-align: right; font-variant-numeric: tabular-nums; }
/* The contest in play (RP-V0-78): context in ink, never the accent; one line that shrinks to an ellipsis, so the sub-bar stays
   42px at any name length and never pushes the status slot. On phones it keeps its natural width and wraps below the screen name. */
.rp-subbar .rp-contest { flex: 0 1 auto; min-width: 0; max-width: 32ch; min-height: 0; color: var(--ink); text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The signed-in address (Scott, 2026-09-26): muted, one line; it gives way (shrink 4) before the contest (shrink 1) does; the full address is its title. On phones it wraps below the screen name. */
.rp-subbar .rp-who { flex: 0 4 auto; min-width: 0; max-width: 36ch; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The role never shrinks; the screen name keeps one line and gives way to an ellipsis only when it is itself a long name. On phones the screen name gets its own untruncated line. */
.rp-subbar > span:not(.rp-contest):not(.rp-status):not(.rp-who) { flex: none; white-space: nowrap; }
.rp-subbar > b { flex: 0 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-main { min-height: 60vh; }
.rp-admin { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 32px; align-items: start; }
.rp-sidenav, .rp-sections-nav { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rp-sidenav .group, .rp-sections-nav .group { font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin: 18px 0 6px; }
.rp-sidenav .group:first-child { margin-top: 0; }
.rp-sidenav a, .rp-sections-nav a { display: block; padding: 8px 12px; border-left: 3px solid transparent; color: var(--navy); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; overflow-wrap: anywhere; }
.rp-sidenav a[aria-current="page"], .rp-sections-nav a[aria-current="page"] { border-left-color: var(--teal); background: var(--info-bg); }
/* RP-V0-111: the phone and tablet form of the side navigation (at most 900 px), a Sections control at the top of the
   content, so every admin page opens on its content. Closed it is one fixed 44 px row naming the section in view (one line,
   an ellipsis for a long name); opening it lists every section below it, a user action, so it may push the page down. It is
   a <details>: it opens with no script. Above 900 px it does not render and the side column is unchanged. */
.rp-sections { display: none; min-width: 0; }
.rp-sections-summary, .rp-filters-summary {
  list-style: none; display: flex; align-items: center; gap: 12px; box-sizing: border-box; height: 44px; padding: 0 14px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer;
}
.rp-sections-summary::-webkit-details-marker, .rp-filters-summary::-webkit-details-marker { display: none; }
.rp-sections-label, .rp-filters-label { flex: none; font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--teal); }
.rp-sections-current, .rp-filters-current { flex: 1 1 auto; min-width: 0; color: var(--navy); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-sections-summary::after, .rp-filters-summary::after {
  content: ""; flex: none; width: 8px; height: 8px; margin: -4px 4px 0 0;
  border-right: 2px solid var(--teal); border-bottom: 2px solid var(--teal); transform: rotate(45deg);
}
.rp-sections[open] > .rp-sections-summary { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.rp-sections[open] > .rp-sections-summary::after, .rp-filters[open] > .rp-filters-summary::after { margin-top: 4px; transform: rotate(-135deg); }
.rp-sections-nav { padding: 10px 0 12px; background: var(--card); border: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
.rp-sections-nav .group { margin: 14px 15px 4px; }
.rp-sections-nav .group:first-child { margin-top: 4px; }
.rp-sections-nav a { padding: 11px 12px; border-radius: 0; }
.rp-footer { border-top: 1px solid var(--border); padding: 18px var(--gutter) 28px; font-size: 13px; color: var(--muted); display: flex; gap: 24px; flex-wrap: wrap; }
@media (max-width: 900px) {
  .rp-subbar { gap: 16px; }
  /* minmax(0, 1fr), never 1fr: a bare 1fr track is as wide as the widest content's minimum, so one unbreakable row in a
     page once widened the whole column past the phone (RP-V0-111). Content that cannot shrink overflows its own box. */
  .rp-admin { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .rp-admin > .rp-sidenav { display: none; }
  .rp-sections { display: block; }
  .rp-nav { flex-wrap: wrap; gap: 8px 16px; }
}
/* The phone nav stays one row where it can (client round 6: Dashboard joined it "if that is not an issue on mobile"). At
   420 px and below the links step down to 14 px with 10 px between them, and at 374 px and below to 13 px. The entrant's
   Dashboard, My story, My reviews and the account menu (client round 11: Account, with Sign out inside) keep one row down
   to 320 px; so does the admin's, down to 360 px. Narrower than that the nav wraps to a second row inside the gutters. */
@media (max-width: 420px) {
  .rp-nav { column-gap: 10px; font-size: 14px; }
}
@media (max-width: 374px) {
  .rp-nav { font-size: 13px; }
}
@media (max-width: 560px) {
  .rp-subbar {
    height: auto; min-height: 42px; flex-wrap: wrap; column-gap: 12px; row-gap: 2px; padding-top: 8px; padding-bottom: 8px;
  }
  .rp-subbar > b { flex: 1 0 100%; white-space: normal; overflow: visible; }
  .rp-subbar .rp-who, .rp-subbar .rp-contest { flex: 0 0 auto; max-width: 100%; }
  .rp-subbar > span:not(.rp-contest):not(.rp-status):not(.rp-who) { white-space: normal; max-width: 100%; }
}

/* Segmented control: every option has one fixed width (--seg-w), so a label swap never moves the row. */
.seg { display: inline-flex; }
.seg button { width: var(--seg-w, 120px); height: 40px; padding: 0 8px; border: 1px solid var(--border); border-left-width: 0; background: #fff; color: var(--navy); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.seg button:first-child { border-left-width: 1px; border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.seg button:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.seg button[aria-pressed="true"] { background: var(--teal); color: #fff; border-color: var(--teal); }

/* Reserved space and tabular numerals. */
.swap { display: inline-block; min-width: var(--swap-w, 12ch); }
.num { font-variant-numeric: tabular-nums; }
.rp-time { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Reserve the widest stamp a zone name can make ("2026-10-14 10:00 GMT-2:30"), so the rewrite to the reader's zone never moves the line. */
.rp-time:not([data-style]) { display: inline-block; min-width: 24ch; }
/* A day inside a sentence ("Locked 30 Sep 2026") is as wide as "30 May 2026" at most; the rewrite from the UTC day never moves the words after it. */
.rp-time[data-style="day"] { display: inline-block; min-width: 11ch; }
.gate { display: flex; align-items: center; gap: 16px; }
.gate .gate-reason { flex: 1; min-height: 1.45em; font-size: 13px; color: var(--muted); }
.not-configured { font-size: 13px; color: var(--muted); }
.test-badge { background: var(--amber-bg); color: var(--amber); font-variant-numeric: tabular-nums; }

/* Error pages. */
.rp-error { max-width: 640px; margin: 48px auto 0; }
.rp-error .status { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* The signed-in 403 (not permitted): whose account this is, and one way on. Values break anywhere so a long address or
   path never widens the card; on a phone each row stacks and the two actions fill the width, their labels allowed to wrap. */
.rp-forbidden-facts { margin: 0 0 22px; }
.rp-forbidden .kv b { min-width: 0; overflow-wrap: anywhere; }
.rp-forbidden .rp-forbidden-path { font-weight: 400; }
.rp-forbidden form .note { margin: 12px 0 0; }
.rp-forbidden .rp-forbidden-request { margin: 22px 0 0; font-size: 12px; }
/* Client round 11: the other accounts on the device, one full-width button each (an address can be long; it wraps). */
.rp-forbidden-switching .note { margin: 12px 0 0; }
.rp-forbidden-label { margin: 0 0 8px; font-weight: 700; color: var(--navy); }
.rp-forbidden-accounts { display: flex; flex-direction: column; gap: 8px; margin: 0 0 4px; }
.rp-forbidden-accounts form { margin: 0; }
.rp-forbidden-accounts .btn { width: 100%; height: auto; min-height: 44px; padding: 10px 16px; white-space: normal; overflow-wrap: anywhere; text-align: left; justify-content: flex-start; }
.rp-forbidden-switching .btn-row { margin-top: 18px; }
@media (max-width: 520px) {
  .rp-forbidden .kv { flex-direction: column; align-items: flex-start; gap: 2px; }
  .rp-forbidden .kv b { text-align: left; }
  .rp-forbidden .btn-row .btn { flex: 1 1 100%; white-space: normal; height: auto; min-height: 46px; padding: 10px 16px; text-align: center; }
}

/* The audit log (Scott, 2026-09-26): the title and filters stay put while the events scroll beneath them. The frame is at
   most one viewport tall (on the desktop, the viewport beneath the sticky header, so it fits on load and at any scroll); the
   log card is its own scroll region in both axes, its column header sticks to the region's top, and scrolling the log never
   drags the page. A short log keeps its natural height. The frame never shrinks below 32rem on a phone (20rem on the
   desktop), so a very short window still shows rows. */
.audit-frame { display: flex; flex-direction: column; gap: 24px; max-height: max(32rem, 100dvh); }
.audit-frame .audit-top { flex: none; }
.audit-frame .audit-log { flex: 0 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; padding-top: 0; }
/* The log's width comes from the page, never from the table: without this a wide table widens the one-column phone grid. */
.audit-frame .audit-log { contain: inline-size; }
.audit-frame .audit-log table.tbl { border-collapse: separate; border-spacing: 0; }
.audit-frame .audit-log thead th { position: sticky; top: 0; z-index: 1; background: var(--card); padding-top: 20px; }
/* Cells wrap at word boundaries only (the card's overflow-wrap:anywhere split "ad|min" and timestamps). At, Role and
   Action never wrap; Actor, Target, Reason and Detail wrap between words, and a token too long for its column still breaks.
   Columns are found by position: rows that carry data-source have a Source column second (At, Source, Actor, Role, Action),
   rows without it do not (At, Actor, Role, Action). */
.audit-frame .audit-log th, .audit-frame .audit-log td { overflow-wrap: break-word; }
.audit-frame .audit-log th { white-space: nowrap; }
/* A dense log: tighter rows, and the Detail JSON (always the last column) one step smaller, so more events fit. */
.audit-frame .audit-log td { padding-block: 10px; }
.audit-frame .audit-log td:last-child { font-size: 13px; }
.audit-frame .audit-log td:first-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
.audit-frame .audit-log tr:not([data-source]) td:nth-child(3), .audit-frame .audit-log tr:not([data-source]) td:nth-child(4) { white-space: nowrap; }
.audit-frame .audit-log tr[data-source] td:nth-child(2), .audit-frame .audit-log tr[data-source] td:nth-child(4), .audit-frame .audit-log tr[data-source] td:nth-child(5) { white-space: nowrap; }
/* The person slot (RP-V0-106): one fixed box for its four states (button, reason with its submit, email select), so
   choosing a person never moves the filters. */
.audit-frame .audit-top form .field.audit-person-slot { width: 280px; max-width: 100%; }
.audit-person-slot > .btn, .audit-person-slot select { width: 100%; height: 44px; min-width: 0; }
.audit-person-slot .audit-person-search { min-width: 0; margin-bottom: 8px; appearance: none; }
/* The button and reason states sit where the select sits in the list state (the 44 px search box and its 8 px gap
   above), so opening the list moves neither the other filters nor the log. */
.audit-person-slot > .btn, .audit-person-slot > .audit-person-reason { margin-top: 52px; }
.audit-person-reason { display: flex; gap: 8px; }
.audit-person-reason input[type=text] { flex: 1 1 auto; min-width: 0; }
.audit-person-reason .btn { flex: none; width: 116px; min-width: 0; height: 44px; padding: 0 12px; }
@media (min-width: 901px) {
  /* Beneath the sticky header (client round 6). The frame is the viewport less the header (--rp-header-h), the footer (66 px,
     one line on the desktop), the page's bottom padding (24 px on these pages) and 12 px of clearance: 102 px. The page
     then scrolls at most 66 px, less than the sub-bar and top padding above the frame (78 px), so the frame's title and
     filters stop 12 px below the header at the bottom of the page and never slide under it. The floor is 20rem, not the
     phone's 32rem, so a short laptop window (1280 x 620) still fits; only a window under about 500 px tall reaches it. */
  .rp-page:has(.audit-frame) { padding-bottom: 24px; }
  .audit-frame { max-height: max(20rem, calc(100dvh - var(--rp-header-h, 72px) - 102px)); }
}
/* M39: in a window up to 1100 px tall the filter card (500 to 550 px once the owner filter wraps) left the fitted log a box of
   28 to 51 px, under its 48 px sticky heading, so no row could be clicked at 1366 x 657 or 1280 x 800. There the frame is not
   fitted: the page scrolls past the title and filters, and the log is its own scroll box of at least 20rem and at most the
   viewport beneath the header, so its rows always show. Taller windows keep the fitted frame. */
@media (min-width: 901px) and (max-height: 1100px) {
  .audit-frame { max-height: none; }
  .audit-frame .audit-log { max-height: max(20rem, calc(100dvh - var(--rp-header-h, 72px) - 102px)); }
}
/* RP-V0-111: the filters of the audit log and the issues list are a <details>, so on a phone they fold behind one fixed
   44 px row naming the active filters and the log opens near the top of the screen. The page opens them itself while the
   person picker has a step in play (its reason, its list or an error), so that step is never hidden. Above 900 px the row is
   hidden and the content forced visible, so the desktop page is unchanged; a browser without ::details-content keeps the
   row there too and still reaches every filter. */
.rp-filters { min-width: 0; }
.rp-filters[open] > .rp-filters-summary { margin-bottom: 16px; }
/* Client round 6: a filter that is one choice among fixed-width buttons (the issues list's Status and Filed by) has a small
   label above its row, the row's accessible name; a label after another row starts 24 px lower, so each row reads as its
   own choice. */
.rp-filter-label { margin: 0 0 6px; font-size: 13px; font-weight: 700; color: var(--muted); }
.btn-row + .rp-filter-label { margin-top: 24px; }
/* Each choice is at least 120 px and grows to fit its own label, never past the row; a label too long for the row (an
   owner's name or email) wraps inside its button. Choosing changes colour only, so a choice never moves its row, and a
   label never runs over its neighbour (ISS-67FAN: owner names in 120 px boxes spilled across the next button). `.btn` is
   in the selector so the 120 px floor outranks `.btn.sm`. At 449 px and below each button is at least a third of the row
   (a hair under, so three always share one line), so three short choices keep one line on a phone and a longer row wraps
   onto a second line, its buttons the same size as the rest. */
.btn.rp-filter-btn { width: auto; min-width: 120px; max-width: 100%; height: auto; min-height: 38px; padding: 6px 16px; white-space: normal; overflow-wrap: anywhere; text-align: center; line-height: 1.3; }
@media (max-width: 449px) {
  .rp-filter-row { gap: 8px; }
  .rp-filter-row .rp-filter-btn { flex: 0 1 auto; min-width: calc((100% - 16px) / 3 - 1px); padding: 6px; }
}
@media (min-width: 901px) {
  @supports selector(::details-content) {
    .rp-filters > .rp-filters-summary { display: none; }
    .rp-filters::details-content { content-visibility: visible; }
  }
}
/* T1-69: the V2 Feedback list has eight columns. On a desktop they share the card's width (fixed layout, set widths, long
   emails and paths break anywhere), so every column, Response included, is visible at 1920. Below 760 px of card the table
   scrolls sideways inside the card; a phone keeps the 1120 px scroll of the rule below. */
@media (min-width: 901px) {
  .issues-frame .audit-log table.issues-tbl { table-layout: fixed; width: 100%; min-width: 760px; }
  .issues-frame .audit-log table.issues-tbl th, .issues-frame .audit-log table.issues-tbl tr:not([data-source]) td { white-space: normal; overflow-wrap: anywhere; }
  .issues-frame .audit-log table.issues-tbl .pill { white-space: normal; overflow-wrap: normal; }
  /* The Filed stamp breaks only at its spaces (date, then time and zone), never inside a number. */
  .issues-frame .audit-log table.issues-tbl tr:not([data-source]) td:nth-child(2) { overflow-wrap: normal; }
  .issues-frame col.ic-ref { width: 12%; }
  .issues-frame col.ic-filed { width: 14%; }
  .issues-frame col.ic-status { width: 12%; }
  .issues-frame col.ic-who { width: 10%; }
  .issues-frame col.ic-owner { width: 12%; }
  .issues-frame col.ic-page { width: 14%; }
  .issues-frame col.ic-what { width: 15%; }
  .issues-frame col.ic-response { width: 11%; }
}
@media (max-width: 900px) {
  /* A phone keeps every column readable: the table scrolls sideways inside the log card, never the page. */
  .audit-frame .audit-log table.tbl { min-width: 1120px; }
  .audit-frame .card { padding: 20px 16px; }
  .audit-frame .audit-log { padding-top: 0; }
  /* Filters pair up two to a row, so the fixed top leaves the log most of the screen. */
  .audit-frame .audit-top form .field { flex: 1 1 40%; min-width: 0; margin-bottom: 0; }
  .audit-frame .audit-top form .field.audit-person-slot { flex: 1 1 100%; width: auto; }
  /* RP-V0-111: a tighter frame, and one line per event: Actor and Target (an id each) no longer wrap into three lines,
     the row scrolls sideways inside the log instead, so about six events fit under the fold at 390 x 844. */
  .audit-frame { gap: 12px; }
  .audit-frame .audit-top { padding-block: 16px; }
  .audit-frame .audit-log thead th { padding-top: 14px; }
  .audit-frame .audit-log tr[data-source] td:nth-child(3), .audit-frame .audit-log table.tbl:not(.with-what) tr[data-source] td:nth-child(6), .audit-frame .audit-log table.with-what tr[data-source] td:nth-child(7) { white-space: nowrap; }
  .audit-frame .audit-log table.tbl.with-what { min-width: 1360px; }
}
/* Client round 11 (ISS-YXY8W): person mode's "What happened" sits just before the raw code (fifth; Action moves to sixth,
   Target to seventh), so it is in view without scrolling past a long route pattern. It wraps between words and never
   narrows below a readable sentence; Action keeps its one line. Person mode's block (the note and one line per contest:
   name, roles, the status headline and its Activity, participant and reviewer links) sits inside the filters, so a phone
   folds it with them and the log opens near the top; on the desktop it shows. */
.audit-frame .audit-log table.with-what tr[data-source] td:nth-child(5) { white-space: normal; min-width: 220px; }
.audit-frame .audit-log table.with-what tr[data-source] td:nth-child(6) { white-space: nowrap; }
.audit-frame .audit-top #audit-person p { margin: 0 0 6px; }
.audit-frame .audit-top #audit-person p:last-child { margin-bottom: 0; }
/* A blind ID or issue reference never breaks at its hyphen. */
.rp-nowrap { white-space: nowrap; }
/* Staff mode's pointer sits inside the filters: shown above them on the desktop, folded with them on a phone, where it would
   push the log's first row below the fold. */
.audit-frame .audit-top .audit-pointer { margin: 0 0 12px; }
/* The person at a glance (participant and Activity pages): eight fixed rows, a missing value is "—", so the card keeps its
   height whatever the person has done. On a phone each row stacks, label over value. The activity list's time column
   never wraps and keeps tabular numerals, so the sentences line up. */
.glance .kv b { flex: 1 1 auto; }
.activity-tbl .activity-when { width: 150px; white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 520px) {
  .glance .kv { flex-direction: column; align-items: flex-start; gap: 2px; }
  .glance .kv b { text-align: left; }
  .activity-tbl .activity-when { width: 108px; white-space: normal; }
}

/* Report an issue (RP-V0-109): the header's last item, at its right edge on every shell page and every width. The nav and
   the button share one right-aligned group (.rp-header-end), so when the header wraps the group moves to the next row still
   flush right, and inside the group the button may drop under the nav, flush right too; it never lands alone at the left.
   The button has one fixed width at each breakpoint and a label that never changes, so opening, sending and closing never
   move the header. The panel floats below it (absolute), right-anchored to the button and never wider than the page less
   both gutters, so it always opens inside the viewport. On the phone header (at most 900 px) the group dissolves
   (display: contents): the button sits on the brand's row at its right, labelled "Report" (an icon alone at 420 px and
   below, beside a phase pill too), its accessible name always "Report an issue", and the nav takes the row below. */
.rp-header-end { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 10px 18px; margin-left: auto; min-width: 0; }
.rp-issue { position: relative; flex: none; }
.rp-issue > summary { list-style: none; }
.rp-issue > summary::-webkit-details-marker { display: none; }
.rp-issue-btn {
  display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; width: 152px; height: 38px;
  padding: 0 12px; border: 1px solid var(--teal-light); border-radius: var(--radius-sm); color: #fff; font-size: 14px;
  font-weight: 700; white-space: nowrap; overflow: hidden; cursor: pointer;
}
.rp-issue-btn:hover { background: var(--teal-dark); }
.rp-issue[open] > .rp-issue-btn { background: var(--teal-dark); }
.rp-issue-short, .rp-issue-icon { display: none; }
.rp-issue-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 70; width: min(440px, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100dvh - 120px); overflow: hidden; box-sizing: border-box; display: flex; flex-direction: column;
  background: var(--card); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(36, 59, 75, 0.18); font-size: 15px; text-align: left;
  --rp-issue-pad-y: 18px; --rp-issue-pad-x: 20px;
}
/* The panel is a column (client round 6 follow-up): the form fills it; its fields scroll in their own box and the foot (the
   error line, Send and Cancel) sits beneath, outside the scrolling, over a hairline. However short the window, Send and
   Cancel stay in view, and a field that takes focus is scrolled into view inside the box, never under the foot. The done
   view keeps the panel's padding and never scrolls (it is three lines). */
.rp-issue-form { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.rp-issue-form[hidden], .rp-issue-done[hidden] { display: none; }
.rp-issue-body { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 8px var(--rp-issue-pad-x) 4px; }
/* RP-V2-105 (ISS-7Q6ZK): the title's head bar never scrolls. With script it holds two fixed-width tools, Move left/right
   (above 900 px) and Collapse/Expand, whose labels swap inside their widths; above 900 px the head is also the drag handle.
   Placed (moved by drag or Move left) the panel is fixed to the window at the spot the script clamps it to, its size
   unchanged; collapsed only the head shows (the form and the done view are display: none, out of the tab order). The
   head (40 px with its 30 px tools) and the body's 8 px top stand where the body's 18 px top and the title stood,
   so the RP-I6 geometry below holds. */
.rp-issue-head { flex: none; display: flex; align-items: center; gap: 8px; height: 40px; box-sizing: border-box; padding: 4px 10px 4px var(--rp-issue-pad-x); border-bottom: 1px solid var(--border); }
.rp-issue-head .rp-issue-title { flex: 1 1 auto; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.btn.sm.rp-issue-tool { flex: none; height: 30px; min-width: 0; padding: 0 8px; font-size: 13px; }
.rp-issue-side { width: 98px; }
.rp-issue-fold { width: 86px; }
.rp-issue-panel.is-placed { position: fixed; top: var(--rp-issue-y, 0px); left: var(--rp-issue-x, 0px); right: auto; }
.rp-issue-panel.is-collapsed > .rp-issue-form, .rp-issue-panel.is-collapsed > .rp-issue-done { display: none; }
@media (min-width: 901px) {
  .rp-issue-head.is-draggable { cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
  .rp-issue-panel.is-dragging .rp-issue-head { cursor: grabbing; }
}
@media (max-width: 900px) {
  .rp-issue-side { display: none; } /* moving is for a desktop window; a phone keeps Collapse */
}
.rp-issue-done { padding: var(--rp-issue-pad-y) var(--rp-issue-pad-x); }
.rp-issue-title { font-size: 17px; margin: 0 0 6px; color: var(--navy); }
.rp-issue-intro, .rp-issue-note { font-size: 14px; margin: 0 0 12px; color: var(--ink); }
.rp-issue-note { color: var(--muted); font-size: 13px; }
.rp-issue-label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin: 0 0 6px; }
.rp-issue-panel textarea, .rp-issue-panel input[type=email] {
  display: block; width: 100%; box-sizing: border-box; margin: 0 0 12px; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: #fff; color: var(--ink); font: inherit; line-height: 1.5; resize: vertical;
}
.rp-issue-panel input[type=email] { height: 42px; }
.rp-issue-panel textarea:focus, .rp-issue-panel input:focus { outline: 2px solid var(--teal); outline-offset: 1px; border-color: var(--teal); }
.rp-issue-panel :focus-visible { outline-color: var(--teal); }
.rp-issue-hint { display: block; margin: -8px 0 12px; font-size: 12px; color: var(--muted); }
.rp-issue-error { min-height: 1.45em; margin: 0 0 8px; color: var(--red); font-size: 14px; line-height: 1.45; }
/* RP-V1-62: each box's reserved message slot sits 4px under the box (or its hint) and always holds its 20px. */
.rp-issue-panel .rp-field-msg { min-height: 40px; margin: -8px 0 8px; } /* two lines reserved, like every field of a data-fields form */
.rp-issue-actions { display: flex; flex-wrap: wrap; gap: 10px; }
/* The foot never scrolls and never changes size: the error line keeps its one line whether or not it holds a refusal. */
.rp-issue-foot { flex: none; padding: 10px var(--rp-issue-pad-x) var(--rp-issue-pad-y); border-top: 1px solid var(--border); }
.rp-issue-action { width: 140px; min-width: 0; }
/* RP-V2-105: Discard draft, a quiet text button after Close. Its space is always kept: invisible (and out of the tab order)
   while there is no draft to discard, so the foot keeps one shape. */
.rp-issue-discard { width: 88px; height: 38px; margin-left: auto; padding: 0; border: 0; background: none; color: var(--navy); font: inherit; font-size: 13px; text-decoration: underline; white-space: nowrap; cursor: pointer; }
.rp-issue-discard.is-idle { visibility: hidden; }
/* The foot stays one row: 140 + 140 + 88 and two 10 px gaps fit the panel's 398 px. A phone's panel is narrower, so its
   Send and Close narrow too (fixed widths still: a label never moves its neighbour). */
@media (max-width: 480px) {
  .btn.sm.rp-issue-action { width: 112px; padding: 0 8px; }
  .btn.sm.rp-issue-action[data-issue-cancel] { width: 76px; }
}
/* A draft carried from another page names it on the body's last line: two lines kept, so nothing below it can move. */
.rp-issue-started { min-height: 2.9em; overflow-wrap: anywhere; }
.rp-issue-done .rp-issue-title:focus { outline: none; }
/* Client round 6: the signed-in reply line and the page screenshot. The frame keeps one height whatever it shows (taking,
   the image, could not), and the box and the "attached" line keep their room, so nothing in the panel moves. The box comes
   first and the frame under it, so the box is in view when the panel opens (ISS-6T3N8). The block
   arrives as a <template> the panel script puts in place (nothing is captured without script). */
.rp-issue-reply { font-size: 13px; margin: 0 0 12px; color: var(--muted); overflow-wrap: anywhere; }
.rp-issue-shot { margin: 0 0 12px; }
.rp-issue-shot-img[hidden] { display: none; }
.rp-issue-shot-frame {
  position: relative; box-sizing: border-box; height: 72px; margin: 6px 0 0; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg);
}
.rp-issue-shot-img { display: block; width: 100%; height: 100%; object-fit: contain; }
.rp-issue-shot-off .rp-issue-shot-img { opacity: 0.35; }
.rp-issue-shot-status {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 0 12px;
  font-size: 13px; color: var(--muted); text-align: center; pointer-events: none;
}
.rp-issue-shot-attach { display: flex; align-items: center; gap: 8px; min-height: 24px; font-size: 14px; color: var(--ink); cursor: pointer; }
.rp-issue-shot-attach input { flex: none; width: 18px; height: 18px; margin: 0; accent-color: var(--teal); }
.rp-issue-note { line-height: 1.45; }
.rp-issue-note-shot { min-height: 2.9em; margin-top: -8px; }
/* RP-I6 / ISS-6T3N8: on a short window the screenshot box sat under the footer. The order stays (the box under
   "What did you expect"). A shorter panel, tighter gaps and shorter boxes bring the box above the footer. */
@media (max-height: 760px) {
  .rp-issue-panel { max-height: calc(100dvh - 77px); } /* phones: 12 px below the panel */
  .rp-issue-body { padding-top: 4px; }
  .rp-issue-title { margin-bottom: 4px; }
  .rp-issue-intro { margin-bottom: 8px; }
  .rp-issue-label { margin-bottom: 4px; }
  .rp-issue-panel textarea { height: 86px; } /* 3 lines: 3 x 22.5 + 16 + 2 */
}
@media (max-height: 760px) and (min-width: 901px) {
  .rp-issue-panel { max-height: calc(100dvh - var(--rp-header-h, 72px) - 14px); } /* follows a wrapped header */
}
@media (max-height: 660px) {
  .rp-issue-panel textarea { height: 63px; } /* 2 lines, the floor */
}
@media (max-width: 900px) {
  .rp-header-end { display: contents; }
  /* A zero basis lets the brand give way (its pill wraps under the mark) before the button would leave the brand's row. */
  .rp-brand { order: 0; flex: 1 1 0%; }
  .rp-issue { order: 1; margin-left: auto; }
  .rp-nav { order: 2; flex: 1 1 100%; }
  .rp-issue-btn { width: 132px; }
  .rp-issue-long { display: none; }
  .rp-issue-short { display: inline; }
}
@media (max-width: 420px) {
  .rp-issue-btn { width: 44px; padding: 0; }
  .rp-issue-short { display: none; }
  .rp-issue-icon { display: block; }
}

/* The account menu (client round 11, ISS-GBV4E): the header's last navigation item for a signed-in session, where Account and
   Sign out were. "Account" (a <summary>, underlined like a current link on the account page) opens a panel naming the address,
   with Your account, Switch account (where switching is open) and Sign out, so Sign out is never beside Report an issue. The label
   and its chevron never change, and the panel floats (absolute) above the page, so opening it moves nothing. Above 900 px the
   panel hangs from the Account item, right-aligned to it; at 900 px and below from the nav row, gutter to gutter, so it never
   leaves the page whatever row Account lands on. */
.rp-account { position: relative; flex: none; }
.rp-account > summary { list-style: none; }
.rp-account > summary::-webkit-details-marker { display: none; }
.rp-account-btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 4px 0; border-bottom: 2px solid transparent; color: #fff;
  white-space: nowrap; cursor: pointer;
}
.rp-account-btn::after {
  content: ""; flex: none; width: 6px; height: 6px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
.rp-account[open] > .rp-account-btn::after { transform: translateY(2px) rotate(-135deg); }
.rp-account[data-current] > .rp-account-btn { border-bottom-color: var(--teal-light); }
.rp-account-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 70; box-sizing: border-box;
  width: min(340px, calc(100vw - 2 * var(--gutter))); max-height: calc(100dvh - 120px); overflow: auto; padding: 8px;
  background: var(--card); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(36, 59, 75, 0.18); font-size: 15px; line-height: 1.4; text-align: left; white-space: normal;
}
.rp-account-panel :focus-visible { outline-color: var(--teal); }
.rp-account-head { margin: 0; padding: 8px 10px 10px; }
.rp-account-eyebrow { display: block; margin: 0 0 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--teal); }
.rp-account-group > .rp-account-eyebrow { padding: 0 10px; margin-top: 4px; }
.rp-account-email { display: block; color: var(--ink); font-weight: 700; overflow-wrap: anywhere; }
.rp-account-group { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
.rp-account-panel form { margin: 0; }
/* Scoped under the panel: the nav's own link rules (.rp-nav a: white, underlined when current) must not reach inside it. */
.rp-account-panel .rp-account-item {
  display: flex; align-items: center; box-sizing: border-box; width: 100%; min-height: 40px; padding: 8px 10px; margin: 0;
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--navy); font: inherit; text-align: left;
  text-decoration: none; overflow-wrap: anywhere; cursor: pointer;
}
.rp-account-panel .rp-account-item:hover { background: var(--info-bg); text-decoration: none; }
.rp-account-panel .rp-account-item[aria-current="page"] { box-shadow: inset 3px 0 0 var(--teal); }
.rp-account-note { margin: 0; padding: 2px 10px 6px; font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
@media (max-width: 900px) {
  .rp-nav { position: relative; }
  .rp-account { position: static; }
  .rp-account-panel { left: 0; right: 0; width: auto; top: calc(100% + 8px); }
}

/* The judge roster table (A-15) stacks into labelled cards when the card is narrow: each cell names itself with its data-label. */
@media (max-width: 1100px) {
  table.tbl.judging-members { min-width: 0 !important; table-layout: auto !important; }
  table.tbl.judging-members thead { position: absolute; left: -9999px; }
  table.tbl.judging-members, table.tbl.judging-members tbody, table.tbl.judging-members tr, table.tbl.judging-members td { display: block; width: auto !important; }
  table.tbl.judging-members tr { padding: 12px 0; border-bottom: 1px solid var(--border); }
  table.tbl.judging-members td { border: 0; padding: 4px 0; text-align: left !important; }
  table.tbl.judging-members td[data-label]::before { content: attr(data-label); display: block; font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: var(--muted, #5d6b7a); }
}

/* Same-page field validation (Atin, 2026-09-30): the failing field is marked in the error colour and its message sits beside
   it in a slot that is always there, so marking a field moves nothing. A mark is never colour alone: it carries the message.
   Client half src/shell/client/field-validation.ts; server half src/shell/field-error.ts and partials/field-msg.eta. */
.rp-field-msg { min-height: 20px; margin-top: 4px; color: var(--red); font-size: 13px; font-weight: 700; line-height: 20px; }
[aria-invalid="true"] { border-color: var(--red); box-shadow: 0 0 0 1px var(--red); }
fieldset:has([aria-invalid="true"]), [data-field]:has([aria-invalid="true"]) { border-color: var(--red); }
[aria-invalid="true"]:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
/* A form built on the declarative layer (form[data-fields], src/shell/client/form-fields.ts) reserves two lines under every field, so a message that wraps at a narrow width never moves the field below it (RP-V1-62). */
form[data-fields] .rp-field-msg { min-height: 40px; }

/* iOS Safari zooms the page into any text field under 16 px when it takes focus (F42). At phone and tablet widths every text
   field is at least 16 px, whatever a component sets (the paste box is 14 px, the shell 15 px). The viewport stays zoomable. */
@media (max-width: 900px) {
  input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]), select, textarea { font-size: max(16px, 1em) !important; }
}
