/* ═══ HELHEIMRS — Runestone of Quests «سنگ‌نبشته‌ی مأموریت‌ها» ═══ */
.pg-quests {
  /* a standing stone's head: one gentle peak, straight flanks. Symmetric, so a
     row of them reads as a row rather than a rubble field. */
  --stone-clip: polygon(0 26px, 12% 9px, 50% 0, 88% 9px, 100% 26px, 100% 100%, 0 100%);
  /* جمعه, the weekly holiday, in a red that still reads as text on basalt */
  --q-holiday: #EC8073;
}
:root[data-theme="light"] .pg-quests { --q-holiday: var(--danger); }
/* Icons on these pages come in the site's four sizes (base.css: 16/20/24/32,
   the stroke following the size). A rule here only names the size, as --n on
   the icon; the 15px facts, 14px locks and 18px tabs it used to draw by hand
   came out with strokes from 0.98 to 1.35px. ICON-6 */

/* ── page head ── */
.pg-quests .q-head { padding-block: var(--s-8) var(--s-5); position: relative; }
.pg-quests .q-head h1 { margin-bottom: var(--s-2); }
.pg-quests .q-head .lede { color: var(--fg-muted); font-size: var(--fs-lg); max-width: 60ch; }
/* .rune-band is direction:ltr, so `start` would resolve LEFT — opposite the RTL heading */
.pg-quests .q-head .rune-band { text-align: start; margin-bottom: var(--s-3); font-size: var(--rune-sm); }
.pg-quests .q-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3) var(--s-5); margin-bottom: var(--s-4); }
.pg-quests .q-bar .tab { padding: var(--s-2) var(--s-4); display: inline-flex; align-items: center; gap: var(--s-half); }
/* the view switcher is navigation, so it carries aria-current, not aria-selected —
   re-state the shared underline-tab treatment for that attribute */
.pg-quests .q-bar .tab[aria-current="page"] { color: var(--accent-text); }
.pg-quests .q-bar .tab[aria-current="page"]::after { content: ""; position: absolute; inset-inline: var(--s-3); bottom: -1px; height: 2px; background: var(--emerald); box-shadow: var(--glow-soft); }
.pg-quests .q-count { color: var(--fg-muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
/* On a phone the four views (with "my calendar") share the row in four equal
   columns, the icon over the word, rather than the last one scrolling out of
   sight. */
@media (max-width: 34em) {
  .pg-quests .q-bar .tabs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); width: 100%; overflow: visible; }
  .pg-quests .q-bar .tab { flex-direction: column; justify-content: center; gap: 2px; padding: var(--s-2) 2px; font-size: var(--fs-xs); white-space: normal; text-align: center; min-width: 0; }
  .pg-quests .q-bar .tab[aria-current="page"]::after { inset-inline: var(--s-2); }
}
.pg-quests .q-tools { margin-inline-start: auto; gap: var(--s-2); }

/* ── filters: search, two either-or groups, two flags, and the rest folded away ── */
.pg-quests .q-filters { display: grid; gap: var(--s-3); margin-bottom: var(--s-6); }
.pg-quests .q-search { position: relative; max-width: 440px; }
.pg-quests .q-search > .ico { --n: 20; position: absolute; inset-inline-start: 14px; top: 50%; translate: 0 -50%; color: var(--fg-muted); pointer-events: none; }
.pg-quests .q-search .input { padding-inline-start: 44px; }
.pg-quests .q-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); }
.pg-quests .q-seg { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; }
/* a hairline between the groups: a choice inside a group replaces, across groups it narrows */
.pg-quests .q-chips > .q-seg + .q-seg, .pg-quests .q-chips > .q-seg + .chip { margin-inline-start: var(--s-1); padding-inline-start: var(--s-3); border-inline-start: 1px solid var(--line-strong); }
.pg-quests .q-seg__l { font-size: var(--fs-xs); color: var(--fg-muted); font-weight: 700; margin-inline-end: var(--s-1); min-width: 5.5em; }
.pg-quests .q-tones-btn::after { content: ""; width: 7px; height: 7px; border-inline-end: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform var(--t-ui) var(--ease-press); }
.pg-quests .q-tones-btn[aria-expanded="true"]::after { transform: translateY(2px) rotate(-135deg); }
.pg-quests .q-n { display: inline-grid; place-items: center; min-width: 20px; height: 20px; font-size: var(--fs-2xs); color: var(--accent-fg); background: var(--emerald-grad); clip-path: var(--clip-hex); }
.pg-quests .q-tones-panel { --bd: var(--line); display: grid; gap: var(--s-2); padding: var(--s-3) var(--s-4); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); --facet: 8px; }
.pg-quests .q-tones-panel[hidden] { display: none; }
.pg-quests .q-active { margin: 0; }
.pg-quests .q-clear { background: none; border: 0; padding: 4px 0; font: inherit; font-size: var(--fs-sm); color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
@media (max-width: 43.75em) {
  .pg-quests .q-head { padding-block: var(--s-5) var(--s-3); }
  .pg-quests .q-head .lede { font-size: var(--fs-md); margin-bottom: var(--s-2); }
  .pg-quests .q-bar { gap: var(--s-2) var(--s-3); }
  .pg-quests .q-tools { margin-inline-start: 0; }
  /* one row that scrolls sideways, fading at the far edge so it says there is more */
  .pg-quests .q-chips { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; padding-bottom: 2px; margin-inline-end: calc(-1 * var(--gutter)); padding-inline-end: var(--gutter);
    -webkit-mask-image: linear-gradient(to left, transparent, #000 28px); mask-image: linear-gradient(to left, transparent, #000 28px); }
  [dir="ltr"] .pg-quests .q-chips { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px); mask-image: linear-gradient(to right, transparent, #000 28px); }
  .pg-quests .q-chips::-webkit-scrollbar { display: none; }
  .pg-quests .q-chips > * { scroll-snap-align: start; flex: none; }
  .pg-quests .q-seg { flex-wrap: nowrap; }
  .pg-quests .q-tones-panel .q-seg { flex-wrap: wrap; }
  .pg-quests .q-filters { margin-bottom: var(--s-4); }
}

/* ── the misty field: ground haze behind the stones, a mist band drifting in front.
   Every layer is an ellipse that has faded to nothing at its own box's edges
   (closest-side): a gradient that peaks at an edge draws that edge — the mist
   used to be brightest at its very bottom, a lit straight-sided box under the
   last row. With one row or ten there is no edge anywhere, only ground that
   thickens toward the feet. ILLUSTRATOR-24 ── */
.pg-quests .qfield { position: relative; padding: var(--s-6) 0 var(--s-9); isolation: isolate; overflow-x: clip; }
.pg-quests .qfield::before { content: ""; position: absolute; inset: 18% 0 0; z-index: 0; pointer-events: none; background: radial-gradient(closest-side at 50% 62%, rgba(var(--fog-color), .17), rgba(var(--fog-color), .07) 58%, transparent); }
.pg-quests .qfield::after { content: ""; position: absolute; inset-inline: 0; bottom: 24px; height: 220px; z-index: 0; pointer-events: none; background: radial-gradient(closest-side at 26% 55%, rgba(var(--fog-color), .13), transparent), radial-gradient(closest-side at 72% 45%, rgba(var(--fog-color), .1), transparent); }
.pg-quests .qfield__mist { position: absolute; inset-inline: 0; bottom: 8px; height: 150px; z-index: 2; pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(var(--fog-color), .12) 38%, rgba(var(--fog-color), .2) 60%, rgba(var(--fog-color), .08) 82%, transparent);
  -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent); mask-image: radial-gradient(closest-side, #000 55%, transparent); }
.pg-quests .stones { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: var(--s-7) var(--s-6); align-items: stretch; }

/* ── runestone ── */
.pg-quests .stone { position: relative; display: flex; min-width: 0; transition: transform var(--t-slow) var(--ease-stone); }
.pg-quests .stone.revealed { transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-stone); }
.pg-quests .stone:hover, .pg-quests .stone:focus-within { transform: translateY(-6px); z-index: 2; }
/* fog pooling at the foot of each stone — kept inside the column: a negative
   inline inset here made the pseudo 444px wide in a 358px track and pushed the
   whole mobile document sideways. */
.pg-quests .stone::after { content: ""; position: absolute; inset-inline: 0; bottom: -30px; height: 76px; z-index: -1; pointer-events: none; background: radial-gradient(closest-side at 50% 45%, rgba(var(--fog-color), .3), transparent); }
/* the lit rim: light rakes the top-right shoulder, dies along the shaded flank */
.pg-quests .stone__body { position: relative; flex: 1; min-width: 0; display: flex; clip-path: var(--stone-clip); padding: 1px; background: linear-gradient(196deg, var(--line-glow), var(--line-strong) 26%, var(--line) 62%, rgba(47,211,154,.22)); transition: background var(--t-slow) var(--ease-stone); }
.pg-quests .stone:hover .stone__body { background: linear-gradient(196deg, var(--emerald), var(--line-glow) 32%, var(--line-strong) 68%, var(--emerald)); }
/* the keyboard's mark: the whole rim lights and thickens */
.pg-quests .stone:has(.stone__title a:focus-visible) .stone__body { padding: 2px; background: var(--emerald); box-shadow: var(--glow); }
.pg-quests .stone__title a:focus-visible { outline: none; }
/* Carved basalt: one light direction (upper right), three cut planes, and the
   vertical columnar jointing basalt actually fractures into. */
.pg-quests .stone__face {
  position: relative; clip-path: var(--stone-clip); padding: var(--s-6) var(--s-5) var(--s-4);
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-2);
  background:
    linear-gradient(196deg, rgba(255,255,255,.055) 0 13%, transparent 13.4%),
    repeating-linear-gradient(93deg, rgba(0,0,0,.15) 0 1px, rgba(255,255,255,.012) 1px 2px, transparent 2px 37px),
    var(--stone-grad);
  box-shadow: var(--shadow-stone);
}
/* Frost: at 15% black the joints read as ruled paper on the pale face. Two
   faint sets at different pitches and the noise carry the stone instead. */
:root[data-theme="light"] .pg-quests .stone__face {
  background:
    linear-gradient(196deg, rgba(255,255,255,.5) 0 13%, transparent 13.4%),
    repeating-linear-gradient(91deg, rgba(0,0,0,.035) 0 1px, transparent 1px 37px),
    repeating-linear-gradient(95deg, rgba(0,0,0,.025) 0 1px, transparent 1px 53px),
    var(--stone-grad);
}
:root[data-theme="light"] .pg-quests .stone__face::before { opacity: 1; }
.pg-quests .stone__face::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.02 .06' numOctaves='2'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .08 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); }
.pg-quests .stone__face::after { content: ""; position: absolute; inset: auto 0 0 0; height: 45%; pointer-events: none; background: radial-gradient(ellipse at 50% 110%, rgba(47,211,154,.22), transparent 65%); opacity: 0; transition: opacity var(--t-slow) var(--ease-stone); }
.pg-quests .stone:hover .stone__face::after { opacity: 1; }
.pg-quests .stone__face > * { position: relative; z-index: 1; min-width: 0; }
/* the band is cut into the stone's shoulder: sunk, not printed, and it catches
   the emerald only when the stone turns toward you */
.pg-quests .stone .rune-band { font-size: var(--rune-sm); letter-spacing: .3em; line-height: 1.2; color: var(--ornament); text-shadow: 0 1px 0 rgba(255,255,255,.06); transition: color var(--t-slow) var(--ease-stone), text-shadow var(--t-slow) var(--ease-stone); margin: 0 0 var(--s-1); white-space: nowrap; overflow: hidden; }
.pg-quests .stone:hover .rune-band { color: var(--accent-text); text-shadow: 0 0 10px rgba(47,211,154,.7); }
.pg-quests .stone__kind { display: flex; justify-content: space-between; align-items: center; gap: var(--s-2); font-size: var(--fs-xs); color: var(--fg-muted); }
.pg-quests .stone__tags { display: flex; flex-wrap: wrap; gap: var(--s-1); min-width: 0; }
/* waiting for an admin: the dashed edge the site gives everything not yet out */
.pg-quests .q-pending { color: var(--fg); }
/* the title is the brightest thing on the stone; engraved, not printed: a dark
   rim where the chisel enters, a lit lip where it leaves */
.pg-quests .stone__title { position: static; font-size: var(--fs-xl); margin: var(--s-1) 0 0; line-height: 1.3; color: var(--fg-strong); text-shadow: 0 -1px 0 rgba(0,0,0,.95), 0 1px 0 rgba(255,255,255,.1); transition: text-shadow var(--t-slow) var(--ease-stone); }
:root[data-theme="light"] .pg-quests .stone__title { color: #1E2421; text-shadow: 0 -1px 0 rgba(20,24,22,.25), 0 1px 0 rgba(255,255,255,.95); }
.pg-quests .stone:hover .stone__title { text-shadow: 0 -1px 0 rgba(0,0,0,.95), 0 1px 0 rgba(255,255,255,.1), 0 0 16px rgba(47,211,154,.45); }
.pg-quests .stone__title a { color: inherit; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; text-align: start; }
/* The title reads in its own direction (so a cut falls at its end); it still
   sits on the page's side. Not by text-align on the clamped box: Chromium lays
   a line pinned to the far side out as if the clamp's «…» were not there, so
   the «…» hung past the box and was clipped, and a cut title read as whole
   (UI-C-R5-1). The heading puts the anchor on the page's side instead, and the
   anchor is no wider than its words, so its own start is where they start. */
[dir="ltr"] .pg-quests :is(.stone__title, .qrow__title):has(> a[dir="rtl"]) { display: flex; justify-content: left; }
[dir="rtl"] .pg-quests :is(.stone__title, .qrow__title):has(> a[dir="ltr"]) { display: flex; justify-content: right; }
[dir="ltr"] .pg-quests :is(.stone__title, .qrow__title) > a[dir="rtl"], [dir="rtl"] .pg-quests :is(.stone__title, .qrow__title) > a[dir="ltr"] { text-align: start; min-width: 0; max-width: 100%; }
.pg-quests .stone__title a:hover { text-decoration: none; }
/* the whole stone is the link: the title's anchor stretches over the face */
.pg-quests .stone__title a::after { content: ""; position: absolute; inset: 0; z-index: 3; }
.pg-quests .stone__dm { display: flex; align-items: center; gap: var(--s-2); margin: 0; color: var(--fg-muted); font-size: var(--fs-sm); }
.pg-quests .stone__dm .avatar { width: 28px; height: 28px; flex: none; font-size: var(--fs-2xs); }
.pg-quests .stone__dm b { color: var(--fg); font-weight: 600; }
/* «روایتگر: name»: the label stays whole and the name is the part that is cut, in its own direction */
.pg-quests .stone__dmname { min-width: 0; display: flex; gap: .3em; white-space: nowrap; }
.pg-quests :is(.stone__dmn, .qrow__dmn, .stone__place, .cal__evt, .qrow__tones) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pg-quests .stone__dmn { color: var(--fg); font-weight: 600; }
/* In a list row's meta line the DM comes whole before the moods do
   (A11Y-TYPE-R9-3): a player picks a table by its DM, and «د…» told them
   nothing. «روایتگر: name» is one piece that never shrinks; where it does not
   fit beside the kind and the mode it takes a line of its own, and its name is
   cut — in its own direction, the whole of it in `title` — only when it alone
   is wider than the column. The moods take what room is left on the last
   line, and leave first when the column is narrow. */
.pg-quests .qrow__meta > .qrow__dm { flex: none; max-width: 100%; min-width: 0; display: flex; gap: .3em; }
.pg-quests .qrow__meta > .qrow__moods { flex: 1 1 0; min-width: 4em; display: flex; }
.pg-quests .qrow__main { container-type: inline-size; }
@container (max-width: 18em) { .pg-quests .qrow__meta > .qrow__moods { display: none; } }
/* The facts are never cut, they wrap (A11Y-TYPE-R6-4): an ellipsis drawn at a
   right-to-left line's end lands on a figure's first digits, so at a larger
   text size «یک‌شنبه ۱۲ مهر» read «یک‌شنبه ۲…» — a wrong date, not a short
   one. Two columns while each has 9rem, one when it has not: measured in rem,
   so a reader's larger text drops the second column. Each icon keeps to its
   fact's first line. */
.pg-quests .stone__facts { list-style: none; padding: 0; margin: var(--s-1) 0 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, max(9rem, 45%)), 1fr)); gap: var(--s-2) var(--s-3); font-size: var(--fs-sm); color: var(--fg); }
.pg-quests .stone__facts li { display: flex; align-items: flex-start; gap: 6px; min-width: 0; }
.pg-quests .stone__facts li > span { min-width: 0; }
.pg-quests .stone__facts li > :is(.ico, .q-lock) { margin-block-start: calc((1lh - 16px) / 2); }
/* the place a member typed wraps too, up to three lines; a figure in it moves whole (quests.js placeHTML) */
.pg-quests .stone__facts :is(li, .stone__wherep) > .stone__place { overflow: hidden; white-space: normal; text-overflow: clip; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow-wrap: break-word; }
/* A place in the other script is clamped as a title is (UI-C-R7-2, after
   R5-1): the box reads from its own start and is no wider than its lines, so
   the clamp's «…» lands inside it. Aligned to the page's side, Chromium set
   the far-pinned last line as if the «…» were not there and clipped it: a
   Persian address cut in the English page read as whole. The row puts the
   box on the page's side, beside its pin. */
[dir="ltr"] .pg-quests .stone__place[dir="rtl"], [dir="rtl"] .pg-quests .stone__place[dir="ltr"] { text-align: start; width: fit-content; max-width: 100%; }
/* An evening that meets somewhere of its own (UX-2-R7-1): the place of the
   date above it, and under it, small, that it is this sitting's only. */
.pg-quests .stone__where { display: grid; justify-items: start; gap: 2px; min-width: 0; }
/* The place and its lock are one row, the lock 6px after the place's last
   letter as on every other stone: the block is as wide as its widest line, so
   a lock after the block floated by the note's end, beside nothing (UI-C-R8-1). */
.pg-quests .stone__wherep { display: flex; align-items: flex-start; gap: 6px; min-width: 0; max-width: 100%; }
.pg-quests .stone__wherep > .q-lock { margin-block-start: calc((1lh - 16px) / 2); }
.pg-quests .stone__once { font-size: var(--fs-2xs); color: var(--fg-muted); }
.pg-quests .stone__facts .num { display: inline-block; }
/* a word and the short figure it names never part (A11Y-TYPE-R9-1): «پلاک ۷» */
.q-bind { white-space: nowrap; }
.pg-quests .stone__facts .ico { --n: 16; color: var(--fg-muted); }
.pg-quests .q-lock { display: inline-flex; flex: none; color: var(--fg-muted); }
.pg-quests .q-lock .ico { --n: 16; }
.pg-quests .stone__tones { display: flex; flex-wrap: wrap; gap: var(--s-half); align-items: center; }
.pg-quests .stone__skulls { margin-inline-start: auto; }
/* the foot: what it costs and who is sitting, the same height on every stone
   of a row. Nothing in it is cut (A11Y-TYPE-R6-4): where the price and the
   count do not both fit on one line, the count steps under the price. Which
   stones step is decided by the foot's width, never by what a stone says: a
   paid table with a waitlist stepped while its free neighbour did not, and
   its rule and price rode 32px above the neighbour's (UI-C-R7-1, after
   R5-2). Every foot of a row is as wide as the next, so they all step
   together. The widths are the longest price and count the site writes —
   «۱٬۲۵۰٬۰۰۰ تومان هر جلسه» beside «پر شده ᛫ ۱۲ نفر در انتظار» is 20.2rem,
   the English pair 22.3rem — with room for one more figure in the price; in
   rem, so a reader's larger text steps the whole row at once. The seats
   take the line under them. */
.pg-quests .stone__foot { container: stonefoot / inline-size; margin-top: auto; padding-top: var(--s-3); border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3); align-items: center; }
@container stonefoot (max-width: 21.5rem) { .pg-quests .stone__count { flex-basis: 100%; justify-content: flex-end; } }
@container stonefoot (max-width: 23.5rem) { [dir="ltr"] .pg-quests .stone__count { flex-basis: 100%; justify-content: flex-end; } }
.pg-quests .stone__seats { display: contents; }
.pg-quests .stone__seats > .seats { order: 2; flex: 1 0 100%; }
.pg-quests .stone__fee { flex: 1 1 auto; min-width: 0; margin: 0; font-size: var(--fs-sm); font-weight: 700; color: var(--fg); }
.pg-quests .stone__fee small { display: inline-block; font-weight: 400; color: var(--fg-muted); }
/* one line of its own text, whatever it holds: the seats left in a larger
   figure, a waitlist, or a table's end in a tag were three heights, and a
   stepped foot stood 2–8px taller on one stone than on the next */
.pg-quests .stone__count { order: 1; margin: 0; margin-inline-start: auto; display: inline-flex; align-items: center; gap: 6px; min-height: 1lh; font-size: var(--fs-xs); color: var(--fg-muted); white-space: nowrap; }
.pg-quests .stone__count b { color: var(--accent-text); font-size: var(--fs-sm); line-height: 1; }
.pg-quests .stone__go { display: inline-flex; color: var(--fg-muted); transition: color var(--t-ui) var(--ease-stone), transform var(--t-ui) var(--ease-stone); }
.pg-quests .stone__go .ico { --n: 16; }
/* How many more the table needs to start. It stands at the end of the stone's
   body, just above the foot's rule, outside the foot: inside it, a stone with
   a minimum carried a taller foot and its fee, rule and seats rode higher than
   on a neighbour without one (UI-C-R5-2). Here the foot is the same on every
   stone of a row, and the room the line takes comes out of the space above.
   The wall's legend key, small, says which mark it means. */
.pg-quests .stone__quorum { margin: auto 0 0; display: flex; align-items: center; gap: 6px; font-size: var(--fs-xs); font-weight: 700; color: var(--fg); }
.pg-quests .stone__quorum + .stone__foot { margin-top: 0; }
.pg-quests .stone__key { flex: none; width: 12px; height: 6px; border: 2px solid currentColor; border-top: 0; }
.pg-quests .stone__quorum.is-met { color: var(--accent-text); }
/* the campaign's own face, cut into the stone's head beside its name (OWNER-R2-2) */
.pg-quests .stone__id { display: grid; grid-template-columns: minmax(0, 1fr) 72px; column-gap: var(--s-3); row-gap: var(--s-2); align-items: start; }
.pg-quests .stone__id > .stone__title { grid-column: 1; }
.pg-quests .stone__id > .stone__dm { grid-column: 1; }
.pg-quests .stone__cover { grid-column: 2; grid-row: 1 / span 2; position: relative; width: 72px; height: 72px; padding: 1px; margin-top: 2px; clip-path: var(--clip-facet); --facet: 10px; background: linear-gradient(196deg, var(--line-glow), var(--line-strong) 60%); }
.pg-quests .stone__cover img { width: 100%; height: 100%; object-fit: cover; clip-path: var(--clip-facet); --facet: 9.5px; filter: saturate(.85) contrast(1.05); }
.pg-quests .stone--full .stone__cover img { filter: saturate(.4) brightness(.8); }
.pg-quests .stone:is(:hover, :focus-within) .stone__go { color: var(--accent-text); transform: translateX(-3px); }
[dir="ltr"] .pg-quests .stone:is(:hover, :focus-within) .stone__go { transform: translateX(3px); }
/* A full table sinks back: the face darkens under its words (text keeps its
   contrast), the rune band is struck through, and it carries a stamp. */
.pg-quests .stone--full .stone__body { background: linear-gradient(196deg, var(--line-strong), var(--line) 50%, var(--line)); }
.pg-quests .stone--full .stone__face { box-shadow: var(--shadow-stone), inset 0 0 0 999px rgba(6,7,8,.36); }
:root[data-theme="light"] .pg-quests .stone--full .stone__face { box-shadow: var(--shadow-stone), inset 0 0 0 999px rgba(226,228,222,.55); }
.pg-quests .stone--full .rune-band { text-decoration: line-through; text-decoration-color: var(--fg-muted); }
.pg-quests .stone--full .stone__title { color: var(--fg); }
.pg-quests .stone__stamp { position: absolute; top: 34px; inset-inline-end: 18px; z-index: 4; pointer-events: none; font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xs); line-height: 1; color: var(--fg-muted); padding: 5px 9px 4px; border: 1.5px solid currentColor; transform: rotate(-4deg); background: rgba(6,7,8,.4); }
:root[data-theme="light"] .pg-quests .stone__stamp { background: rgba(255,255,255,.5); }
@media (max-width: 43.75em) { .pg-quests .stones { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); } .pg-quests .stone__face { padding-top: var(--s-5); } .pg-quests .stone__title { font-size: var(--fs-lg); }
  /* one stone to a row has no neighbour to line up with: the line stays under the seats it counts */
  .pg-quests .stone__quorum { order: 1; margin-top: 0; } .pg-quests .stone__quorum + .stone__foot { margin-top: auto; } }
@media (prefers-reduced-motion: reduce) { .pg-quests .stone { transition: none; } .pg-quests .stone:hover, .pg-quests .stone:focus-within { transform: none; } }

/* ── seats: round, the brand's round shield (ICON-11) ──
   The disc, its lit rim and its boss ring are the shared .shield (components.css);
   these pages only say how big. On a card the free seats are the one lit thing
   and a taken one carries a plain boss (a card does not say who sits there,
   OWNER-10); on the session's own page each carries the member's mark. */
.pg-quests .seats { display: flex; flex-wrap: nowrap; gap: 4px; min-width: 0; }
/* eight to a row, 32px each, giving a little on the narrowest card rather than spilling */
.pg-quests .seats .shield { flex: 0 1 var(--seat); min-width: 22px; height: auto; aspect-ratio: 1; }
.pg-quests .seat__boss { width: 42%; aspect-ratio: 1; border-radius: 50%; background: radial-gradient(circle at 36% 32%, color-mix(in srgb, var(--fg-muted) 55%, #fff), var(--fg-muted) 45%, color-mix(in srgb, var(--fg-muted) 55%, #000)); opacity: .55; }
.pg-quests .seats .shield--more { color: var(--fg-muted); font-weight: 800; }
.pg-quests .seats--sm { gap: 3px; }
.pg-quests .seats--sm .shield { --seat: 16px; flex: none; min-width: 0; }
.pg-quests .seats--sm .shield--taken { background: var(--line-strong); box-shadow: none; }
.pg-quests .seats--sm .shield--taken::after, .pg-quests .seats--sm .seat__boss { display: none; }
.pg-quests .seats--sm .shield--more { width: auto; min-width: 16px; aspect-ratio: auto; padding-inline: 4px; border-radius: 8px; clip-path: none; font-size: var(--fs-2xs); line-height: 16px; }

/* ── difficulty: notches cut in a bar, and the number ── */
.pg-quests .qdiff { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--fg-muted); white-space: nowrap; }
.pg-quests .qdiff__bar { display: inline-flex; gap: 2px; align-items: flex-end; }
.pg-quests .qdiff__bar i { width: 4px; height: 12px; background: var(--line-strong); transform: skewX(-12deg); }
.pg-quests .qdiff__bar i.on { background: var(--fg); }
.pg-quests .qdiff__bar i.on:nth-last-child(-n+2):nth-child(n+4) { background: var(--q-holiday); }
/* "8/10" reads as one fraction, left to right, wherever it sits (a fact's <b> is a flex row) */
.pg-quests .qdiff .qdiff__n { display: inline; color: var(--fg); font-size: inherit; font-weight: 700; font-variant-numeric: tabular-nums; }
.pg-quests .qdiff .qdiff__n small { color: var(--fg-muted); font-weight: 400; }
.pg-quests .fact .qdiff .qdiff__n { font-size: var(--fs-md); color: var(--fg-strong); }

/* ── paging: the next batch, asked for ── */
.pg-quests .q-more { display: grid; justify-items: center; gap: var(--s-2); margin: var(--s-5) 0 var(--s-8); }
/* never the scroll anchor: kept in place by the browser, it threw the whole view a batch down when the next batch arrived above it (MOTION-17) */
.pg-quests [data-more-box] { overflow-anchor: none; }
.pg-quests .q-more__n { margin: 0; font-size: var(--fs-sm); color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.pg-quests .q-more__btn { width: min(100%, 520px); justify-content: center; }
.pg-quests .q-more__btn small { color: var(--fg-muted); font-weight: 400; }
@media (prefers-reduced-motion: no-preference) {
  .pg-quests .is-new { animation: q-in 240ms var(--ease-out) backwards; animation-delay: calc(var(--i, 0) * 40ms); }
}
/* the next batch lands where the reader is looking: it brightens and settles, but is never a blank */
@keyframes q-in { from { opacity: .55; transform: translateY(8px); } }

/* ── the empty field: three blank stones in mist ── */
/* one track no wider than the column: an auto track grew to the three stones'
   full width (360px) and took the sentence and the page with it on a phone */
.pg-quests .q-empty { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; gap: var(--s-3); padding: var(--s-6) 0 var(--s-9); }
.pg-quests .q-empty h2 { margin: var(--s-3) 0 0; font-size: var(--fs-2xl); }
.pg-quests .q-empty p { margin: 0; max-width: 52ch; color: var(--fg-muted); }
.pg-quests .q-empty__acts { justify-content: center; gap: var(--s-3); margin-top: var(--s-2); }
.pg-quests .q-empty__field { position: relative; display: flex; align-items: flex-end; justify-content: center; gap: var(--s-5); width: min(100%, 520px); height: 220px; isolation: isolate; }
.pg-quests .q-empty__field i { width: 104px; height: 168px; clip-path: var(--stone-clip); background: linear-gradient(196deg, rgba(255,255,255,.06) 0 14%, transparent 14.4%), repeating-linear-gradient(93deg, rgba(0,0,0,.18) 0 1px, transparent 1px 31px), var(--stone-grad); box-shadow: var(--shadow-stone); }
.pg-quests .q-empty__field i:nth-child(1) { height: 138px; }
.pg-quests .q-empty__field i:nth-child(3) { height: 150px; }
/* the way to becoming a DM: the same blank field, then three steps from asking
   to a first table, the one this member stands at lit */
.pg-quests .q-apply { padding-top: var(--s-4); }
.pg-quests .q-apply h1 { margin: var(--s-3) 0 0; }
.pg-quests .q-apply h1:focus { outline: none; }
.pg-quests .q-apply__steps { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); width: min(100%, 760px); text-align: start; }
.pg-quests .q-apply__steps li { --bd: var(--line-strong); position: relative; display: grid; align-content: start; gap: 4px; padding: var(--s-4); border: 1px solid var(--bd); background: var(--facet-edges), var(--bg-elev); clip-path: var(--clip-facet); --facet: 8px; font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quests .q-apply__n { font-style: normal; font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); line-height: 1; color: var(--ornament); }
.pg-quests .q-apply__steps b { color: var(--fg-strong); font-size: var(--fs-md, 1rem); }
.pg-quests .q-apply__steps .is-now { --bd: var(--line-glow); box-shadow: var(--glow-inset); }
.pg-quests .q-apply__steps :is(.is-now, .is-done) .q-apply__n { color: var(--accent-text); }
.pg-quests .q-apply__n.is-check .ico { --n: 24; }
@media (max-width: 45em) { .pg-quests .q-apply__steps { grid-template-columns: minmax(0, 1fr); } }
/* the form says up front that this session waits for an admin */
.pg-quests .q-await { max-width: 72ch; }
.pg-quests .q-await .rune { color: var(--accent-text); margin-inline-end: 4px; }
/* a drawn ornament in its holder (quests.js rune()): one stave height, the
   holder's colour, set on the line of the words beside it — never the rune
   font's half-height ᛃ or its thinner face (ICONOGRAPHER-R3-1) */
.q-rune { display: inline-flex; flex: none; align-items: center; justify-content: center; vertical-align: -.15em; font-size: inherit; letter-spacing: 0; line-height: 1; }
/* A stave that leads a line of its own (a rule, the dice-soon line, the
   awaiting notice) is one line box tall, the text's own line height, with the
   stave centred in it: it sits on the first line at any text size, however
   many lines the sentence wraps to on a phone (ICONOGRAPHER-R5-1). */
:is(.pg-quests .rules li, .pg-quests .q-soon-line, .pg-quest .qd-await) > .q-rune { line-height: inherit; block-size: 1lh; }
/* the mist lies across the stones' feet, inside the column: wider than the
   field, it gave a phone a sideways scroll */
.pg-quests .q-empty__mist { position: absolute; inset: auto 0 -10px; height: 90px; z-index: 1; background: radial-gradient(66% 70% at 50% 70%, rgba(var(--fog-color), .32), transparent 75%); }

/* ── list view: one table, every column on the same line on every row ── */
/* The list is laid out by the room it has, measured in its own text size: a
   container query in em follows a reader who set a larger text size, where a
   px breakpoint left a 2000px-wide table at 200% text (A11Y-TYPE-29). */
.pg-quests [data-body] { container-type: inline-size; container-name: qbody; }
/* The seats column has a fixed width (A11Y-TYPE-R9-3): sized by its widest
   cell, one table's «حدنصاب کامل است» widened it for every row and took the
   room from every title and DM's name. A cell that needs more wraps in itself. */
.pg-quests .qlist { display: grid; grid-template-columns: minmax(12rem, 2fr) 8.5rem 5.5rem 6.5rem 8.5rem 6.5rem minmax(8.5rem, 10.5rem) 20px; column-gap: var(--s-4); row-gap: 6px; }
.pg-quests .qrow { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; position: relative; padding: var(--s-3) var(--s-4); --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); --facet: 10px; transition: border-color var(--t-ui) var(--ease-stone), background var(--t-ui) var(--ease-stone); }
.pg-quests .qrow > * { min-width: 0; }
.pg-quests .qrow:hover, .pg-quests .qrow:has(a:focus-visible) { --bd: var(--line-glow); background: var(--facet-edges), var(--bg-elev-2); }
.pg-quests .qrow--head { position: sticky; top: var(--hdr-h); z-index: 2; padding-block: var(--s-2); background: var(--bg); border-color: transparent; border-bottom-color: var(--line-strong); clip-path: none; font-size: var(--fs-2xs); color: var(--fg-muted); font-weight: 700; }
.pg-quests .qrow--head:hover { background: var(--bg); border-color: transparent; border-bottom-color: var(--line-strong); }
.pg-quests .qrow__h button { font: inherit; color: inherit; background: none; border: 0; padding: 4px 0; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.pg-quests .qrow__h[aria-sort="ascending"] button { color: var(--accent-text); text-decoration: underline; }
.pg-quests .qrow__h[aria-sort="ascending"] button::after { content: " ↓"; }
.pg-quests .qrow__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-md); line-height: 1.35; color: var(--fg-strong); margin: 0; }
.pg-quests .qrow__title a { color: inherit; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.pg-quests .qrow__title a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.pg-quests .qrow__title a:focus-visible { outline: none; }
.pg-quests .qrow:has(.qrow__title a:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
/* The meta line wraps between its items, never inside one, so nothing in it
   is cut without an ellipsis: the label «روایتگر:» was cut through its glyph
   ("DI") when a wide seats cell left the line no room. Every item carries its
   separator in front of it, in a strip of fixed width; the line is drawn that
   strip early and the strip is clipped away, so a line that wraps starts with
   its words, never with a stray «᛫». */
.pg-quests .qrow__meta { --q-sep: 18px; color: var(--fg-muted); font-size: var(--fs-xs); display: flex; flex-wrap: wrap; gap: 0; margin: 2px 0 0; margin-inline-start: calc(-1 * var(--q-sep)); white-space: nowrap; }
[dir="rtl"] .pg-quests .qrow__meta { clip-path: inset(-6px var(--q-sep) -6px -6px); }
[dir="ltr"] .pg-quests .qrow__meta { clip-path: inset(-6px -6px -6px var(--q-sep)); }
.pg-quests .qrow__meta > span { flex: none; }
/* where an in-person table meets, short (OWNER-R2-2): a long town gives way before the DM's name does */
.pg-quests .qrow__meta > .qrow__place { flex: 0 1 auto; min-width: 3em; max-width: 14em; display: flex; }
.pg-quests .qrow__placet { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pg-quests .qrow__meta > span::before { content: "᛫"; display: inline-block; flex: none; inline-size: var(--q-sep); text-align: center; font-family: var(--font-rune); color: var(--fg-muted); }
.pg-quests .qrow__meta > :is(.qrow__dm, .qrow__moods)::before { margin-inline-end: -.3em; }
.pg-quests .qrow__moods { gap: .3em; }
.pg-quests .qrow__meta .q-pending { min-height: 0; padding: 0 6px; margin-inline: var(--q-sep) 8px; }
.pg-quests .qrow__meta .q-pending::before, .pg-quests .qrow__meta .q-pending + span::before { content: none; }

.pg-quests .qrow__cell { font-size: var(--fs-sm); display: grid; gap: 1px; font-variant-numeric: tabular-nums; }
.pg-quests .qrow__cell small { color: var(--fg-muted); font-size: var(--fs-xs); }
.pg-quests .qrow__k { display: none; }
.pg-quests .qrow__fee > span { white-space: nowrap; }
/* «per sitting» goes under the amount, so a seven-digit fee keeps to its column */
.pg-quests .qrow__fee small { display: block; color: var(--fg-muted); }
.pg-quests .qrow__seats { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; }
.pg-quests .qrow__seats small { white-space: nowrap; }
.pg-quests .qrow__seats .qrow__quorum { white-space: normal; }
/* how many more the table needs to start, under its seats as the stone says it (OWNER-R4-3) */
/* the count stays beside the seats, and «حدنصاب کامل است» takes the line under them when the cell has no room for it there */
.pg-quests .qrow__seatn { display: contents; }
.pg-quests .qrow__seats .qrow__quorum { color: var(--fg); font-weight: 700; }
.pg-quests .qrow__seats .qrow__quorum.is-met { color: var(--accent-text); }
.pg-quests .qrow__go { color: var(--fg-muted); display: flex; width: 20px; justify-content: center; }
.pg-quests .qrow__go .ico { --n: 16; }
/* the campaign's own face beside its title */
.pg-quests .qrow__main.has-cover { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: var(--s-3); align-items: center; }
.pg-quests .qrow__main.has-cover > :not(.qrow__cover) { grid-column: 2; }
.pg-quests .qrow__cover { grid-column: 1; grid-row: 1 / span 2; width: 40px; height: 40px; clip-path: var(--clip-facet); --facet: 6px; background: var(--line-strong); padding: 1px; }
.pg-quests .qrow__cover img { width: 100%; height: 100%; object-fit: cover; clip-path: var(--clip-facet); --facet: 5.5px; }
.pg-quests .qrow:hover .qrow__go { color: var(--accent-text); }
.pg-quests :is(.qrow--full, .qrow--over) .qrow__title { color: var(--fg); }
/* a table that is over says so where a running one counts its free seats
   (UX-2-R5-3): a quiet tag, the size of the count it replaces, never lit */
.pg-quests .q-over { min-height: 0; padding: 0 6px; font-size: var(--fs-2xs); font-weight: 600; color: var(--fg-muted); }
.pg-quests .stone__count .q-over { font-size: var(--fs-xs); }
.pg-quests .qlist__hour { grid-column: 1 / -1; position: sticky; top: calc(var(--hdr-h) + 34px); z-index: 1; padding: 6px var(--s-2); background: var(--bg-elev); border-inline-start: 2px solid var(--accent-text); font-weight: 800; font-variant-numeric: tabular-nums; }
.pg-quests .qlist__hour small { font-weight: 400; color: var(--fg-muted); margin-inline-start: var(--s-2); }
/* narrower desktops drop the difficulty column before anything wraps */
@container qbody (max-width: 71.25em) and (min-width: 56.25em) {
  .pg-quests .qlist { grid-template-columns: minmax(11rem, 2fr) 8rem 5rem 6rem 8rem minmax(8.5rem, 10.5rem) 1.5rem; }
  .pg-quests .qrow > :nth-child(6) { display: none; }
}
/* below that, each row is a card: the title, then its facts on a line or two */
@container qbody (max-width: 56.24em) {
  .pg-quests .qlist { grid-template-columns: minmax(0, 1fr); }
  .pg-quests .qrow { display: flex; flex-wrap: wrap; gap: 2px var(--s-3); align-items: baseline; padding: var(--s-3); }
  .pg-quests .qrow--head { display: none; }
  .pg-quests .qrow__main { flex: 1 0 100%; }
  .pg-quests .qrow__title a { -webkit-line-clamp: 2; }
  .pg-quests .qrow__cell { display: inline-flex; align-items: baseline; gap: 4px; font-size: var(--fs-xs); }
  .pg-quests .qrow__k--keep { display: inline; color: var(--fg-muted); }
  .pg-quests .qrow__diff { display: none; }
  .pg-quests .qrow__fee small { display: inline; }
  .pg-quests .qrow__date { flex-direction: row; gap: 6px; }
  .pg-quests .qrow__date small { font-size: var(--fs-xs); }
  .pg-quests .qrow__seats { margin-inline-start: auto; align-self: center; }
  /* on the card's seats line: «۴ خالی ᛫ ۲ تا شروع» */
  .pg-quests .qrow__seatn { display: inline-flex; flex-wrap: wrap; gap: 0 6px; }
  .pg-quests .qrow__seatn .qrow__quorum::before { content: "᛫"; font-family: var(--font-rune); font-weight: 400; color: var(--fg-muted); margin-inline-end: 6px; unicode-bidi: isolate; }
  .pg-quests .qrow__go { display: none; }
  .pg-quests .qlist__hour { top: var(--hdr-h); }
  /* A busy day in the calendar, on a phone: one line a session — its title, its
     price, the seats left — about 56px each under its hour, so sixteen in one
     evening are two screens, not four (UX2-44). The full row is a tap away. */
  .pg-quests .qlist--day { row-gap: 4px; }
  .pg-quests .qlist--day .qrow:not(.qrow--head) { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: baseline; align-content: center; gap: 0 var(--s-3); min-height: 56px; padding: 6px var(--s-3); }
  .pg-quests .qlist--day .qrow__main { min-width: 0; }
  .pg-quests .qlist--day .qrow__title { font-size: var(--fs-sm); }
  .pg-quests .qlist--day .qrow__title a { -webkit-line-clamp: 1; }
  .pg-quests .qlist--day .qrow__meta { display: none; }
  .pg-quests .qlist--day .qrow > :is(.qrow__date, :nth-child(3), :nth-child(4)) { display: none; }
  .pg-quests .qlist--day .qrow__fee { font-weight: 700; }
  .pg-quests .qlist--day .qrow__fee small, .pg-quests .qlist--day .qrow__k { display: none; }
  .pg-quests .qlist--day .qrow__seats { margin: 0; display: block; }
  .pg-quests .qlist--day .qrow__seats .seats { display: none; }
  .pg-quests .qlist--day .qrow__seats small { color: var(--accent-text); font-weight: 700; }
  .pg-quests .qlist--day .qrow__seatn { display: grid; justify-items: end; }
  .pg-quests .qlist--day .qrow__seatn .qrow__quorum::before { content: none; }
  .pg-quests .qlist--day .qrow__seats .qrow__quorum:not(.is-met) { color: var(--fg); }
  .pg-quests .qlist--day .qrow--full .qrow__seats small { color: var(--fg-muted); font-weight: 400; }
  .pg-quests .qlist--day .qrow--over .qrow__fee { color: var(--fg-muted); font-weight: 400; }
  .pg-quests .qlist--day .qrow__main.has-cover { grid-template-columns: 32px minmax(0, 1fr); }
  .pg-quests .qlist--day .qrow__cover { width: 32px; height: 32px; grid-row: 1; }
}

/* ── calendar view ── */
.pg-quests .cal { --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); padding: var(--s-5); min-width: 0; }
/* one centred group: the arrows sit beside the month they move */
.pg-quests .cal__head { position: relative; display: flex; align-items: center; justify-content: center; gap: var(--s-3); margin-bottom: var(--s-4); min-height: 44px; }
.pg-quests .cal__nav { display: inline-flex; align-items: center; gap: var(--s-2); }
.pg-quests .cal__head h2 { margin: 0; font-size: var(--fs-2xl); min-width: 8ch; text-align: center; }
.pg-quests .cal__head .num { font-family: var(--font-body); color: var(--fg-muted); font-weight: 400; font-size: var(--fs-lg); }
.pg-quests .cal__head [data-cal="today"] { position: absolute; inset-inline-end: 0; }
.pg-quests .cal__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.pg-quests .cal__wd { text-align: center; font-size: var(--fs-xs); color: var(--fg-muted); padding: var(--s-2) 0; font-weight: 700; }
.pg-quests .cal__wd.is-off { color: var(--q-holiday); }
.pg-quests .cal__wd .short { display: none; }
.pg-quests .cal__day { --heat: 0; position: relative; min-width: 0; min-height: 96px; padding: 6px 8px; border: 1px solid var(--line); border-radius: var(--r-1); text-align: start; display: flex; flex-direction: column; gap: 4px; cursor: pointer; color: inherit; font: inherit;
  background: linear-gradient(rgba(47,211,154, calc(.035 * var(--heat))), rgba(47,211,154, calc(.035 * var(--heat)))), var(--bg);
  transition: border-color var(--t-ui) var(--ease-stone), box-shadow var(--t-ui) var(--ease-stone); }
.pg-quests .cal__day:hover { border-color: var(--line-strong); }
.pg-quests .cal__day.is-empty { background: transparent; border-color: transparent; cursor: default; }
.pg-quests .cal__day.is-off { background: linear-gradient(rgba(47,211,154, calc(.035 * var(--heat))), rgba(47,211,154, calc(.035 * var(--heat)))), linear-gradient(rgba(194,58,43,.05), rgba(194,58,43,.05)), var(--bg); }
.pg-quests .cal__day.is-off .cal__n { color: var(--q-holiday); }
.pg-quests .cal__top { display: flex; align-items: center; gap: 6px; }
.pg-quests .cal__n { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--fs-sm); color: var(--fg); line-height: 1; }
/* today you can point at in a second: a lit hex behind the number, and the word */
.pg-quests .cal__day.is-today { border-color: var(--line-glow); }
.pg-quests .cal__day.is-today .cal__n { display: inline-grid; place-items: center; width: 28px; height: 28px; clip-path: var(--clip-hex); background: var(--emerald-grad); color: var(--accent-fg); box-shadow: var(--glow-soft); }
.pg-quests .cal__today { font-size: var(--fs-2xs); font-weight: 800; color: var(--accent-text); }
.pg-quests .cal__day.is-sel { border-color: var(--accent); box-shadow: var(--glow-inset); }
/* past days keep their words readable: only the ground and the number recede */
.pg-quests .cal__day.is-past { background: transparent; }
.pg-quests .cal__day.is-past .cal__n { color: var(--fg-muted); font-weight: 400; }
.pg-quests .cal__day.is-past .cal__ev { color: var(--fg-muted); }
.pg-quests .cal__evs { display: grid; gap: 3px; min-width: 0; }
.pg-quests .cal__ev { display: flex; align-items: center; gap: 5px; min-width: 0; font-size: var(--fs-2xs); line-height: 1.5; color: var(--fg); }
.pg-quests .cal__ev i { flex: none; width: 6px; height: 6px; clip-path: var(--clip-hex); background: var(--emerald); box-shadow: 0 0 6px var(--emerald); }
.pg-quests .cal__ev > span { flex: 1 1 auto; }
[dir="ltr"] .pg-quests .cal__evt[dir="rtl"] { text-align: left; }
[dir="rtl"] .pg-quests .cal__evt[dir="ltr"] { text-align: right; }
/* a projected weekly sitting: a hollow mark and a quieter title, told apart without colour */
.pg-quests .cal__ev.is-recur i, .pg-quests .cal__dots i.is-recur { background: transparent; box-shadow: inset 0 0 0 1.5px var(--emerald); }
.pg-quests .cal__ev.is-recur span { color: var(--fg-muted); }
.pg-quests .cal__more { font-size: var(--fs-2xs); font-weight: 800; color: var(--accent-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-quests .cal__dots { display: none; }
.pg-quests .cal__void { display: grid; justify-items: center; gap: var(--s-2); text-align: center; padding: var(--s-5) var(--s-3) var(--s-2); }
.pg-quests .cal__void p { margin: 0; color: var(--fg-muted); }
.pg-quests .cal__void .row { justify-content: center; gap: var(--s-2); }
.pg-quests .cal.is-void .cal__day:not(.is-empty) { background: transparent; border-style: dashed; cursor: default; }
.pg-quests .cal__sel { margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--line); }
.pg-quests .cal__sel :is(h2,h3) { font-size: var(--fs-lg); margin-bottom: var(--s-3); }
.pg-quests .cal__sel h3 small { font-size: var(--fs-sm); font-weight: 400; color: var(--fg-muted); margin-inline-start: var(--s-2); }
.pg-quests .cal__legend { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); font-size: var(--fs-xs); color: var(--fg-muted); margin-top: var(--s-3); }
.pg-quests .cal__legend i { display: inline-block; width: 9px; height: 9px; clip-path: var(--clip-hex); background: var(--emerald); margin-inline-end: 6px; }
.pg-quests .cal__legend i.recur { background: transparent; box-shadow: inset 0 0 0 1.5px var(--emerald); }
/* My calendar: what each sitting asks of the member, told by the mark's shape
   as well as its colour — a run table a diamond, an unpaid one red, one they
   are not coming to hollow and struck, a projected week hollow (OWNER-17) */
.pg-quests .cal__ev.is-dm i, .pg-quests .cal__dots i.is-dm, .pg-quests .cal__legend i.dm { clip-path: none; transform: rotate(45deg) scale(.85); }
.pg-quests .cal__ev.is-owed i, .pg-quests .cal__dots i.is-owed, .pg-quests .cal__legend i.owed { background: var(--danger); box-shadow: none; }
.pg-quests .cal__ev:is(.is-skip, .is-off) i, .pg-quests .cal__dots i:is(.is-skip, .is-off), .pg-quests .cal__legend i.skip { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-muted); }
.pg-quests .cal__ev:is(.is-skip, .is-off) span { color: var(--fg-muted); text-decoration: line-through; }
.pg-quests .my-sits { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.pg-quests .my-sit { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--s-2) var(--s-4); padding: var(--s-3) var(--s-4); --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); --facet: 8px; }
.pg-quests .my-sit__t { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--fg-strong); }
.pg-quests .my-sit__what { display: grid; gap: 2px; min-width: 0; }
.pg-quests .my-sit__what a { font-weight: 700; overflow-wrap: anywhere; }
.pg-quests .my-sit__who { font-size: var(--fs-xs); color: var(--fg-muted); }
[dir="ltr"] .pg-quests .my-sit__what a[dir="rtl"] { text-align: left; }
[dir="rtl"] .pg-quests .my-sit__what a[dir="ltr"] { text-align: right; }
.pg-quests .my-sit__what small { font-size: var(--fs-xs); }
/* the place in a row of my calendar opens its map (OWNER-R8-2): the line's
   own size and weight, underlined so it reads as a link and not a coloured
   word — the same as the usual venue on the session page (.fact__usual) */
.pg-quests .my-sit__what .q-maplink { font-weight: 400; text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 50%, transparent); text-underline-offset: .3em; }
.pg-quests .my-sit__what .q-maplink:hover { text-decoration-color: currentColor; }
.pg-quests .my-sit__st { display: flex; flex-wrap: wrap; gap: 4px var(--s-2); align-items: center; justify-content: flex-end; }
.pg-quests .my-sit:is(.is-skip, .is-off) .my-sit__what a { color: var(--fg-muted); text-decoration: line-through; }
.pg-quests .my-sit.is-dm { border-inline-start: 2px solid var(--accent-text); }
@media (max-width: 40em) { .pg-quests .my-sit { grid-template-columns: auto minmax(0, 1fr); } .pg-quests .my-sit__st { grid-column: 2; justify-content: flex-start; } }
.pg-quests .my-feed { display: grid; gap: var(--s-2); justify-items: start; margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--line); }
.pg-quests .my-feed h3 { margin: 0; font-size: var(--fs-lg); }
.pg-quests .my-feed p { margin: 0; max-width: 70ch; }
.pg-quests .my-feed__row { display: flex; gap: var(--s-2); width: min(100%, 640px); }
.pg-quests .my-feed__row .input { flex: 1; min-width: 0; font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: var(--fs-xs); }
.pg-quests .my-feed__acts { gap: var(--s-2); flex-wrap: wrap; }
.pg-quests [data-body][aria-busy="true"] .cal { opacity: .6; transition: opacity var(--t-ui) var(--ease-out); }
/* a busy day narrows there and then: tier of play and mood */
.pg-quests .cal__filters { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3); margin-bottom: var(--s-3); min-width: 0; }
.pg-quests .cal__filters .q-seg { flex-wrap: wrap; min-width: 0; }
@media (max-width: 43.75em) {
  /* on a phone the narrowing is one row that scrolls sideways, fading at its far end */
  .pg-quests .cal__filters { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; -webkit-mask-image: linear-gradient(to left, transparent, #000 28px); mask-image: linear-gradient(to left, transparent, #000 28px); }
  [dir="ltr"] .pg-quests .cal__filters { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px); mask-image: linear-gradient(to right, transparent, #000 28px); }
  .pg-quests .cal__filters::-webkit-scrollbar { display: none; }
  .pg-quests .cal__filters .q-seg { flex: none; flex-wrap: nowrap; }
  .pg-quests .cal__filters .chip { flex: none; }
}
@media (max-width: 45em) {
  .pg-quests .cal { padding: var(--s-3); }
  .pg-quests .cal__head { justify-content: space-between; }
  .pg-quests .cal__head [data-cal="today"] { position: static; }
  .pg-quests .cal__head h2 { font-size: var(--fs-xl); }
  .pg-quests .cal__wd .long { display: none; } .pg-quests .cal__wd .short { display: inline; }
  .pg-quests .cal__grid { gap: 3px; }
  .pg-quests .cal__day { min-height: 58px; padding: 4px; align-items: center; }
  .pg-quests .cal__today, .pg-quests .cal__evs { display: none; }
  .pg-quests .cal__day.is-today .cal__n { width: 24px; height: 24px; }
  /* up to three dots; a busier day shows its number instead */
  .pg-quests .cal__dots { display: flex; flex-wrap: wrap; justify-content: center; gap: 3px; margin-top: auto; }
  .pg-quests .cal__dots i { width: 7px; height: 7px; clip-path: var(--clip-hex); background: var(--emerald); }
  .pg-quests .cal__dots b { min-width: 22px; padding: 0 4px; font-size: var(--fs-2xs); line-height: 18px; text-align: center; color: var(--accent-fg); background: var(--emerald-grad); clip-path: var(--clip-hex); }
}

/* ── detail page ── */
.pg-quest .qd-hero { position: relative; padding: var(--s-5) 0 var(--s-7); border-bottom: 1px solid var(--line); overflow: hidden; isolation: isolate; }
/* The key art behind the title: the session's own picture, or the painting
   its title names (the crown, the dragon…). It is the page a DM shares, so the
   subject has to read: the art stands at 75% and is set in the middle of the
   hero, between the title and the seats — its subject lands in the third the
   seats panel does not cover, never behind it — fading to nothing at every
   edge. The title column gets its own 35% scrim, and only it. ILLUSTRATOR-13 */
.pg-quest .qd-hero__bg { position: absolute; inset-block: 0; inset-inline-start: 0; width: 100%; z-index: -1; opacity: .75; pointer-events: none;
  -webkit-mask-image: radial-gradient(closest-side, #000 52%, transparent); mask-image: radial-gradient(closest-side, #000 52%, transparent); }
.pg-quest .qd-hero__bg.is-photo { opacity: .7; }
.pg-quest .qd-hero__bg img, .pg-quest .qd-art, .pg-quest .qd-art > svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.pg-quest .qd-art { position: absolute; inset: 0; }
/* one picture in two grades: the dark plate, or the same plate graded for Frost (quests.js frostGrade) */
.pg-quest .qd-art--frost { display: none; }
:root[data-theme="light"] .pg-quest .qd-art--dark { display: none; }
:root[data-theme="light"] .pg-quest .qd-art--frost { display: block; }
@media (min-width: 60.0625em) {
  /* two-thirds of the hero, centred a step toward the title: in a right-to-left
     page the seats hang on the left, so the art leans right, and the reverse */
  .pg-quest .qd-hero__bg { inset-inline-start: auto; left: 50%; width: 64%; translate: calc(-50% + 7vw) 0; }
  [dir="ltr"] .pg-quest .qd-hero__bg { translate: calc(-50% - 7vw) 0; }
  /* Frost (ILLUSTRATOR-R3-3): the graded plate at its full value — the subject
     the darkest thing, the sky the lightest — never washed thin over the pale
     page. It fades to the page only in straight lines: long toward the title,
     short toward the seats and at the hero's top and bottom, so no oval edge
     is drawn anywhere. A photo stands the same way. */
  /* and it stands a step further from the title than the dark plate does: an
     ink branch under black type has no contrast to lend it (A11Y-TYPE-R3-2) */
  :root[data-theme="light"] .pg-quest .qd-hero__bg { opacity: 1; translate: calc(-50% + 2vw) 0;
    -webkit-mask-image: linear-gradient(to left, transparent 10%, #000 46%, #000 84%, transparent), linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
    mask-image: linear-gradient(to left, transparent 10%, #000 46%, #000 84%, transparent), linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
    -webkit-mask-composite: source-in; mask-composite: intersect; }
  :root[data-theme="light"][dir="ltr"] .pg-quest .qd-hero__bg { translate: calc(-50% - 2vw) 0;
    -webkit-mask-image: linear-gradient(to right, transparent 10%, #000 46%, #000 84%, transparent), linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
    mask-image: linear-gradient(to right, transparent 10%, #000 46%, #000 84%, transparent), linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent); }
}
/* in a left-to-right page the painting is the mirror of the Persian one, so its
   subject keeps the same place between the title and the seats (never a photo) */
[dir="ltr"] .pg-quest .qd-hero__bg:not(.is-photo) .qd-art > svg { transform: scaleX(-1); }
.pg-quest .qd-hero__text { position: relative; }
.pg-quest .qd-hero__text::before { content: ""; position: absolute; z-index: -1; inset: calc(-1 * var(--s-6)) calc(-1 * var(--s-7)); pointer-events: none;
  background: color-mix(in srgb, var(--bg) 35%, transparent);
  -webkit-mask-image: radial-gradient(closest-side, #000 70%, transparent); mask-image: radial-gradient(closest-side, #000 70%, transparent); }
/* Frost: no wash over the title column — over a plate at full value a
   page-coloured scrim is itself the grey oval (it lay across the crown). The
   plate already fades out under the title; what small type still crosses it
   stands on a ground of its own (below), the rest on a halo of the page. */
:root[data-theme="light"] .pg-quest .qd-hero__text::before { content: none; }
:root[data-theme="light"] .pg-quest .qd-hero :is(.crumbs, .qd-hero__dm, .qd-hero__when, h1) { text-shadow: 0 0 2px var(--bg), 0 0 10px var(--bg), 0 0 22px var(--bg); }
/* the hero's small type stands on a real ground in Frost, not on the painting:
   the tags on the slab colour, «روایتگر:» and the date in body ink */
:root[data-theme="light"] .pg-quest .qd-hero__meta .tag { background: color-mix(in srgb, var(--bg-elev) 92%, transparent); color: var(--fg); border-color: var(--line-strong); }
:root[data-theme="light"] .pg-quest .qd-hero__meta .tag--accent { color: var(--accent-text); border-color: color-mix(in srgb, var(--accent-text) 45%, transparent); }
:root[data-theme="light"] .pg-quest .qd-hero__dm, :root[data-theme="light"] .pg-quest .qd-hero__when { color: var(--fg); }
/* The phone's picture: a band of its own between the path and the title, the
   drawing cut to its shape (800 × 440), full bleed, and no text printed over
   it; it melts into the page at its foot. On a tablet's single column it is
   the same band, 560px at most, its sides melting too. ILLUSTRATOR-13 */
.pg-quest .qd-stage { display: none; }
/* Where a DM's cover starts to fade toward its foot, and how far it fades
   (--fade-at, --fade-end), are theirs when they set them (quests.js coverLook,
   on .qd-hero); otherwise each band keeps its own line below. */
/* A desktop whose gap between the title and the seats is too narrow for the
   subject (quests.js fitHero) shows the band instead: the picture across the
   title's column, above the title, drawn for that shape and melting on every
   side, with the seats panel beside it, its top level with the picture's
   (ILLUSTRATOR-R4-1). Nothing is painted behind the words then, so the title
   column's scrim goes too. */
@media (min-width: 60.0625em) {
  .pg-quest .qd-hero.is-band .qd-hero__bg, .pg-quest .qd-hero.is-band .qd-hero__text::before { display: none; }
  .pg-quest .qd-hero.is-band .qd-hero__in { align-items: start; }
  .pg-quest .qd-hero.is-band .qd-wall { margin-top: var(--band-top, 0px); }
  .pg-quest .qd-hero.is-band .qd-stage { display: block; position: relative; height: clamp(15rem, 24vw, 21rem); margin: 0 0 var(--s-3);
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 var(--fade-at, 78%), rgb(0 0 0 / var(--fade-end, 0))), linear-gradient(to right, transparent, #000 9%, #000 91%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 var(--fade-at, 78%), rgb(0 0 0 / var(--fade-end, 0))), linear-gradient(to right, transparent, #000 9%, #000 91%, transparent);
    -webkit-mask-composite: source-in; mask-composite: intersect; }
  .pg-quest .qd-hero.is-band .qd-stage img { width: 100%; height: 100%; object-fit: cover; display: block; }
  [dir="ltr"] .pg-quest .qd-hero.is-band .qd-stage:not(.is-photo) .qd-art > svg { transform: scaleX(-1); }
}
@media (max-width: 60em) {
  .pg-quest .qd-hero__bg, .pg-quest .qd-hero__text::before { display: none; }
  .pg-quest .qd-stage { display: block; position: relative; aspect-ratio: 800 / 440; width: min(100% + 2 * var(--gutter), 560px); margin-block: 0 var(--s-1); margin-inline: max(calc(-1 * var(--gutter)), calc((100% - 560px) / 2));
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 var(--fade-at, 72%), rgb(0 0 0 / var(--fade-end, 0))), linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 var(--fade-at, 72%), rgb(0 0 0 / var(--fade-end, 0))), linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
    -webkit-mask-composite: source-in; mask-composite: intersect; }
  .pg-quest .qd-stage img { width: 100%; height: 100%; object-fit: cover; display: block; }
  [dir="ltr"] .pg-quest .qd-stage:not(.is-photo) .qd-art > svg { transform: scaleX(-1); }
}
@media (max-width: 35em) {
  /* a phone's band runs to the screen's edges: only its foot melts */
  .pg-quest .qd-stage { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 var(--fade-at, 74%), rgb(0 0 0 / var(--fade-end, 0))); mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 var(--fade-at, 74%), rgb(0 0 0 / var(--fade-end, 0))); }
}
.pg-quest .qd-hero__in { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 400px); gap: var(--s-6) var(--s-8); align-items: end; }
.pg-quest .qd-hero__text { min-width: 0; }
.pg-quest .qd-hero h1 { overflow-wrap: anywhere; }
.pg-quest .qd-hero .rune-band { text-align: start; margin-bottom: var(--s-3); color: var(--rune-lit); text-shadow: 0 0 12px rgba(47,211,154,.45); -webkit-mask-image: none; mask-image: none; }
.pg-quest .qd-hero__meta { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-3); }
.pg-quest .qd-hero__dm { display: inline-flex; align-items: center; gap: var(--s-2); margin-top: var(--s-4); color: var(--fg-muted); font-size: var(--fs-sm); text-decoration: none; max-width: 100%; }
.pg-quest .qd-hero__dm b { color: var(--fg-strong); }
.pg-quest .qd-hero__dm:hover b { color: var(--accent-text); }
.pg-quest .qd-hero__dm .avatar { width: 32px; height: 32px; flex: none; font-size: var(--fs-xs); }
.pg-quest .qd-hero__when { display: flex; align-items: flex-start; gap: var(--s-2); margin: var(--s-3) 0 0; font-weight: 600; color: var(--fg); }
.pg-quest .qd-hero__when .ico { --n: 20; color: var(--fg-muted); margin-top: 2px; }
.pg-quest .qd-hero__when small { color: var(--fg-muted); font-weight: 400; }
.pg-quest .qd-await { display: flex; align-items: flex-start; gap: var(--s-2); font-weight: 600; }
.pg-quest .qd-await .rune { color: var(--danger); }
/* the longhouse wall: the seats hang between two dark beams */
.pg-quest .qd-wall { position: relative; display: grid; gap: var(--s-3); padding: var(--s-5); background: var(--stone-grad-2); box-shadow: var(--shadow-stone); clip-path: var(--clip-facet); --facet: 14px; transition: box-shadow 600ms var(--ease-out); }
.pg-quest .qd-wall.is-registered { box-shadow: var(--shadow-stone), var(--glow-inset), inset 0 0 60px rgba(47,211,154,.3); }
.pg-quest .qd-wall__h { margin: 0; font-size: var(--fs-xs); font-weight: 700; color: var(--fg-muted); }
.pg-quest .qd-wall__beam { position: relative; padding: 18px var(--s-3); background: linear-gradient(180deg, rgba(0,0,0,.4) 0 8px, rgba(255,255,255,.05) 8px 9px, transparent 9px calc(100% - 9px), rgba(255,255,255,.05) calc(100% - 9px) calc(100% - 8px), rgba(0,0,0,.4) calc(100% - 8px)), rgba(0,0,0,.14); }
:root[data-theme="light"] .pg-quest .qd-wall__beam { background: linear-gradient(180deg, rgba(40,30,20,.28) 0 8px, transparent 8px calc(100% - 8px), rgba(40,30,20,.28) calc(100% - 8px)), rgba(0,0,0,.03); }
.pg-quest .seats--wall { flex-wrap: wrap; justify-content: center; gap: 10px 8px; }
.pg-quest .seats--wall .shield { --seat: 44px; flex: none; width: var(--seat); height: var(--seat); font-size: var(--fs-sm); }
.pg-quest .seats--wall .shield--taken { background: var(--bg-elev-3); color: var(--fg-strong); }
.pg-quest .qd-wall__count { margin: 0; font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quest .qd-wall__count b { color: var(--accent-text); font-size: var(--fs-lg); }
.pg-quest .qd-wall__note { margin: 0; font-size: var(--fs-xs); color: var(--fg-muted); }
/* a table closed to new players (OWNER-16): its free seats are not on offer,
   so they are unlit rings — no emerald, no glow — and the line under them
   says why in the muted ink (UI-C-R4-1, OWNER-R4-2) */
.pg-quests :is(.seats--closed, .roster.is-closed) .shield--free { background: none; box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.pg-quest .qd-wall__count.is-closed { color: var(--fg-muted); font-weight: 600; }
/* a table that is over (UX-2-R5-3): the line says what became of it, in the
   page's ink, its rune quiet; nothing under it to press */
.pg-quest .qd-wall__count.is-over { display: flex; align-items: baseline; gap: var(--s-2); color: var(--fg); }
.pg-quest .qd-wall__count.is-over .rune { color: var(--fg-muted); }
/* "Four is enough to start" (OWNER-15): the seats the table needs stand on one
   rail, a bracket under the first N — filled or not, a group read at a glance.
   Strong ink while the table still waits for them, emerald once it has them.
   The legend under the wall draws the same bracket and says the number. */
.pg-quest .seats--quorum { --q-need: var(--fg-strong); }
.pg-quest .qd-wall:has(.qd-wall__quorum.is-met) .seats--quorum, .pg-quest .qd-wall__quorum.is-met { --q-need: var(--accent-text); }
.pg-quest .seats--quorum .seat { position: relative; display: grid; padding-bottom: 12px; }
/* the page's side, not the seat's: a seat holding a Persian initial carries dir="rtl" of its own (HX.enhance) */
.pg-quest .seats--quorum .seat.is-need::after { content: ""; position: absolute; left: -4px; right: -4px; bottom: 0; height: 6px; border-bottom: 2.5px solid var(--q-need); pointer-events: none; }
:root[dir="rtl"] .pg-quest .seats--quorum .seat.is-first::after, :root[dir="ltr"] .pg-quest .seats--quorum .seat.is-last::after { right: 4px; border-right: 2.5px solid var(--q-need); }
:root[dir="rtl"] .pg-quest .seats--quorum .seat.is-last::after, :root[dir="ltr"] .pg-quest .seats--quorum .seat.is-first::after { left: 4px; border-left: 2.5px solid var(--q-need); }
.pg-quest .qd-wall__quorum { --q-need: var(--fg-strong); margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px var(--s-2); font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quest .qd-wall__quorum b { margin-inline-start: auto; color: var(--fg-strong); }
.pg-quest .qd-wall__quorum.is-met b { color: var(--accent-text); }
.pg-quest .qd-wall__key { flex: none; width: 30px; height: 8px; border: 2.5px solid var(--q-need); border-top: 0; }
.pg-quest .qd-hero__cta { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.pg-quest .qd-hero__cta .stone__cta { display: flex; flex: 1 1 100%; }
.pg-quest .qd-hero__cta .stone__cta .btn { flex: 1; }
/* the price beside the verb on the button, quieter than the verb */
.q-cta__fee { font-weight: 600; opacity: .85; white-space: nowrap; }
/* a full paid table: the one thing left to do, and what it promises */
.pg-quest .q-watch { display: flex; flex-wrap: wrap; align-items: center; gap: 4px var(--s-2); margin: 0; font-size: var(--fs-sm); color: var(--fg); }
.pg-quest .q-watch .rune { color: var(--accent-text); }
.pg-quest .q-watch__off { background: none; border: 0; padding: 4px 0; font: inherit; color: var(--fg-muted); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; min-height: 32px; }
.pg-quest .qd-hero__cta > .btn[data-action="watch"] { flex: 1 1 100%; }
@media (max-width: 60em) { .pg-quest .qd-hero__in { grid-template-columns: minmax(0, 1fr); align-items: start; } }
.pg-quests .engraved-tag { display: inline-flex; align-items: center; gap: var(--s-2); min-height: 44px; padding: 0 var(--s-4); color: var(--accent-text); --bd: var(--line-glow); border: 1px solid var(--bd); clip-path: var(--clip-facet); --facet: 8px; background: var(--facet-edges), rgba(47,211,154,.08); font-weight: 700; font-size: var(--fs-sm); flex: 1; box-shadow: var(--glow-inset); }
.pg-quests .engraved-tag .rune { opacity: 1; }
.pg-quests .engraved-tag--dim { color: var(--fg-muted); --bd: var(--line-strong); background: var(--facet-edges); box-shadow: none; }
.pg-quests .engraved-tag--dim .rune { color: var(--ornament); }

/* On a phone the booking control stays one tap away: a bar above the bottom
   navigation, under every overlay, appearing once the hero's own button is gone. */
.pg-quest .qd-bar { display: none; }
@media (max-width: 56.25em) {
  .pg-quest .qd-bar { position: fixed; inset-inline: 0; bottom: calc(64px + env(safe-area-inset-bottom)); z-index: calc(var(--z-nav) - 1); display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); min-height: 72px; padding: 8px var(--gutter) 14px;
    background: var(--bg-veil); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border-top: 1px solid var(--line-strong);
    transform: translateY(110%); visibility: hidden; transition: transform var(--t-ui) var(--ease-out), visibility 0s linear var(--t-ui); }
  .pg-quest .qd-bar.is-on { transform: none; visibility: visible; transition: transform var(--t-ui) var(--ease-out), visibility 0s linear; }
  .pg-quest .qd-bar__info { display: grid; gap: 2px; min-width: 0; font-size: var(--fs-sm); }
  .pg-quest .qd-bar__info b { color: var(--accent-text); }
  .pg-quest .qd-bar__info span { color: var(--fg-muted); font-size: var(--fs-xs); white-space: nowrap; }
  .pg-quest .qd-bar .btn { min-height: 44px; flex: none; }
}
/* The page ends above the booking bar as well as the bottom nav, so its last
   control (the footer's) can be scrolled clear of both, and a control reached
   with Tab is kept out from under the bar while it shows (A11Y-TYPE-23). The
   room is there while the page has a bar at all, so the page never changes
   height as the bar comes and goes. */
@media (max-width: 56.25em) {
  body:has(.pg-quest .qd-bar) { padding-bottom: calc(var(--bnav-h) + 72px + var(--s-5) + env(safe-area-inset-bottom)); }
  html:has(.pg-quest .qd-bar.is-on) { --page-bar-b: 72px; }
}
/* Frost: the bar is a surface, not a veil. The pale veil over the always-dark
   map or hero mixed to a mid grey under the blur, and the date beside the
   button fell to 4:1 (A11Y-TYPE-R4-2); the blur stays for the edge. */
:root[data-theme="light"] .pg-quest .qd-bar { background: color-mix(in srgb, var(--bg-elev) 96%, transparent); }
@media (prefers-reduced-motion: reduce) { .pg-quest .qd-bar { transition: none; } }
.pg-quest .qd-bar .q-cta__fee { display: none; }
@media (min-width: 23em) { .pg-quest .qd-bar .q-cta__fee { display: inline; } }

/* the page at work after an action on it: a hairline under the header, only
   once the wait is long enough to notice (MOTION-R2-1) */
.q-wait-line { position: fixed; inset-inline: 0; top: var(--hdr-h); z-index: calc(var(--z-nav) + 1); height: 2px; overflow: hidden; pointer-events: none; background: color-mix(in srgb, var(--emerald) 18%, transparent); }
.q-wait-line::after { content: ""; position: absolute; inset-block: 0; width: 34%; background: linear-gradient(90deg, transparent, var(--emerald), transparent); animation: q-wait 1.1s cubic-bezier(.4,0,.6,1) infinite; }
@keyframes q-wait { from { inset-inline-start: -34%; } to { inset-inline-start: 100%; } }
@media (prefers-reduced-motion: reduce) { .q-wait-line::after { animation: none; inset-inline: 0; width: auto; opacity: .6; } }
/* the old page, pinned where it was seen while the new one fades in under it:
   above the page, below the header, the bottom nav, the booking bar and the toasts */
.q-ghost { position: fixed; z-index: calc(var(--z-nav) - 2); margin: 0; pointer-events: none; }

.pg-quests .qd-grid { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--s-7); padding-block: var(--s-7); align-items: start; }
.pg-quests .qd-side { position: sticky; top: calc(var(--sticky-top) + var(--s-3)); display: grid; gap: var(--s-4); }
.pg-quests .qd-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-7); min-width: 0; }
.pg-quests .qd-main h2 { font-size: var(--fs-2xl); overflow-wrap: anywhere; }
.pg-quests .qd-main :is(h2, h3)[tabindex="-1"]:focus { outline: none; }
@media (max-width: 60em) { .pg-quests .qd-grid { grid-template-columns: minmax(0, 1fr); } .pg-quests .qd-side { position: static; } }

/* the facts: what the session is, then what it costs and the rules of paying */
.pg-quests .facts { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }
.pg-quests .facts .qd-sub { margin: 0; font-size: var(--fs-md); font-weight: 800; color: var(--fg-muted); }
.pg-quests .facts h3.qd-sub { margin-top: var(--s-2); }
.pg-quests .facts__grid { --bd: var(--line); position: relative; min-width: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--facet-edges), var(--line); border: 1px solid var(--bd); clip-path: var(--clip-facet); }
/* The cells paint over the grid's own ground, and a map over its mat, so the
   two cut corners are drawn on a layer above them, the size of the border box
   (as the rule book does, well.css): a border runs along straight sides only,
   and without it both chamfers were open (UI-C-R9-1). The map has no
   overflow: hidden for that reason — its clip-path already cuts the picture,
   and hidden would cut this layer back to the padding box. */
.pg-quests :is(.facts__grid, .qmap)::after { content: ""; position: absolute; inset: -1px; z-index: 3; pointer-events: none; background: var(--facet-edges); }
.pg-quests .fact { padding: var(--s-3) var(--s-4); background: var(--bg-elev); display: grid; gap: 4px; align-content: start; min-width: 0; }
.pg-quests .fact--wide { grid-column: 1 / -1; }
.pg-quests .fact small { color: var(--fg-muted); font-size: var(--fs-xs); }
/* the label is one line; anything said under the value wraps in its cell
   (UI-C-R3-1, A11Y-TYPE-R3-1: the hidden-address note was one unbreakable
   line that pushed the phone page wider than the screen) */
.pg-quests .fact > small:first-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-quests .fact__note { margin: 0; font-size: var(--fs-xs); line-height: 1.5; color: var(--fg-muted); white-space: normal; overflow-wrap: anywhere; }
.pg-quests .fact b { color: var(--fg-strong); font-size: var(--fs-md); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; overflow-wrap: anywhere; }
.pg-quests .fact b > .ico { --n: 16; color: var(--fg-muted); }
/* the address wraps beside its pin rather than dropping under it as a whole */
.pg-quests .fact__where { flex: 0 1 auto; min-width: 0; }
/* a compound with a seam is set whole, and opens at the seam only when it is wider than the line (quests.js seamCt) */
.pg-quests .fact__place .q-word { display: inline-block; max-width: 100%; }
/* pin, place and lock on one line, the name wrapping between them in a narrow
   cell. Picked by the cell's own class, not `b:has(> .fact__place)` (MOTION-R8-1):
   a :has() before the last compound cannot be scoped, so every node added
   anywhere on /quests, and deep in the lightbox, paid 1.8 ms to re-ask it.
   `.fact__place` only ever sits in this cell's <b> (quests.js, the facts). */
.pg-quests .fact--place > b { align-items: flex-start; flex-wrap: nowrap; }
.pg-quests .fact--place > b > .ico { margin-block-start: calc((1lh - 16px) / 2); }
/* The lock is in the place's own run, after its last word, 6px from its ink,
   on whatever line that word lands (UI-C-R11-2). A flex item of its own, it
   stood at the cell's far edge once the place wrapped and took the whole
   width: «کافه‌ی ………… 🔒 / سنگ‌نبشته». It hangs: its room is kept at every
   line's end, as the flex item's was, and it takes none in the line, so the
   place wraps exactly as before and the lock never goes to a line alone.
   Chromium breaks before an inline block even after a word joiner or a
   no-break space, so a joiner could not hold it to the word. It is outside
   the place's isolate, so it is after the words in the page's direction in
   either language; top-aligned and dropped by half the slack, it is centred
   on its line as the pin is. */
.pg-quests .fact__where--lock { --lk: calc(6px + 16px); padding-inline-end: var(--lk); }
.pg-quests .fact__where > .q-lock { vertical-align: top; margin-block-start: calc((1lh - 16px) / 2); margin-inline: 6px calc(-1 * var(--lk)); }
.pg-quests .fact__link { font-size: var(--fs-sm); }
/* the usual venue under a sitting met elsewhere opens its own map: the
   place is the link, underlined so it is not read as a coloured word (OWNER-R8-2) */
.pg-quests .fact__usual { text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 50%, transparent); text-underline-offset: .3em; }
.pg-quests .fact__usual:hover { text-decoration-color: currentColor; }
/* the next sitting meets somewhere of its own (UX-2-R7-1): the fact says so
   under the place, and where the table usually meets under its map */
.pg-quests .fact .q-once { justify-self: start; }
.pg-quest .qd-hero__where { margin-top: var(--s-2); font-weight: 400; }
.pg-quest .qd-hero__where b { font-weight: 700; color: var(--fg-strong); }
/* «this sitting only» and «open in maps» are one pair after the place, 12px
   apart, the room the ᛫ gives the parts of the line above (UI-C-R8-2): a
   bordered tag and an underlined link 4px apart read as one smudge and one
   cramped target. Where the line is short, the pair goes under the place whole. */
.pg-quest .qd-hero__pair { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-3); vertical-align: 1px; }
.pg-quest .qd-hero__map { font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; }
.pg-quests .fact__bar { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 3px; max-width: 420px; margin-top: 4px; }
.pg-quests .fact__bar i { height: 6px; background: var(--line-strong); transform: skewX(-14deg); }
.pg-quests .fact__bar i.on { background: var(--emerald); }
.pg-quests .facts__money { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap: var(--s-3) var(--s-5); margin: 0; padding: var(--s-4); --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); }
.pg-quests .facts__money > div { display: grid; gap: 2px; align-content: start; }
.pg-quests .facts__money dt { font-size: var(--fs-xs); color: var(--fg-muted); }
.pg-quests .facts__money dd { margin: 0; font-weight: 700; color: var(--fg-strong); }
.pg-quests .facts__fee { grid-column: 1 / -1; }
.pg-quests .facts__fee b { font-family: var(--font-display); font-size: 1.3rem; font-weight: 900; white-space: nowrap; }
.pg-quests .facts__fee small { color: var(--fg-muted); font-weight: 400; }
@media (max-width: 40em) { .pg-quests .facts__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* On the narrowest phones, and at a larger text size, the two long facts —
   when, and where — take the whole row: in half of a 320px screen the place
   had 63px beside its pin and lock, and «سنگ‌نبشته» was cut inside its
   letters (A11Y-TYPE-R5-1). The short ones pair up around them. */
.pg-quests .facts { container: qfacts / inline-size; }
@container qfacts (max-width: 21em) {
  .pg-quests .facts__grid { grid-auto-flow: row dense; }
  .pg-quests :is(.fact--when, .fact--place) { grid-column: 1 / -1; }
}

/* the DM's strip: this week, and the way into the parts of the page they work in */
.pg-quests .qd-dmbar { --bd: var(--line-glow); display: grid; gap: var(--s-3); padding: var(--s-4) var(--s-5); border: 1px solid var(--bd); background: var(--facet-edges), rgba(47,211,154,.04); clip-path: var(--clip-facet); }
.pg-quests .qd-main .qd-dmbar h2 { margin: 0; font-size: var(--fs-lg); }
.pg-quests .qd-dmbar__stats { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-6); margin: 0; }
.pg-quests .qd-dmbar__stats dt { font-size: var(--fs-xs); color: var(--fg-muted); }
.pg-quests .qd-dmbar__stats dd { margin: 0; font-weight: 700; color: var(--fg-strong); font-variant-numeric: tabular-nums; }
.pg-quests .qd-dmbar__stats dd.is-bad { color: var(--danger); }
.pg-quests .qd-dmbar__jump { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.pg-quests .qd-dmbar__jump [data-cancel-campaign] { margin-inline-start: auto; }
/* over: not the week ahead but what became of the table, in the quiet edge of a closed thing */
.pg-quests .qd-dmbar--over { --bd: var(--line-strong); background: var(--facet-edges); }
.pg-quests .qd-main .qd-dmbar--over h2 { display: flex; align-items: baseline; gap: var(--s-2); }
.pg-quests .qd-dmbar--over h2 .rune { color: var(--fg-muted); }
.pg-quests .qd-dmbar__say { margin: 0; color: var(--fg); font-size: var(--fs-sm); max-width: 60ch; }
/* the table's sign-up, a switch the DM flips at any time (OWNER-16) */
.pg-quests .qd-dmbar__recruit dd { display: flex; align-items: center; gap: var(--s-2); font-weight: 600; }
.pg-quests .qd-dmbar__recruit .switch[aria-checked="false"] + span { color: var(--fg-muted); }
/* the dice under «به‌زودی»: one quiet line where the table would be, never a roll button the server refuses (OWNER-19) */
.pg-quests .q-soon-line { display: flex; align-items: flex-start; gap: var(--s-2); margin: 0; padding: var(--s-3) var(--s-4); border: 1px dashed var(--line-strong); color: var(--fg-muted); font-size: var(--fs-sm); }
.pg-quests .q-soon-line .rune { color: var(--ornament); }
.pg-quests .rules__act { margin: var(--s-3) 0 0; }

.pg-quests .dm-card { display: grid; gap: var(--s-3); }
.pg-quests .dm-card__top { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.pg-quests .dm-card__top a { min-width: 0; }
.pg-quests .dm-card__top b { display: block; color: var(--fg-strong); font-family: var(--font-display); font-size: var(--fs-lg); overflow-wrap: anywhere; }
.pg-quests .dm-card__top small { color: var(--fg-muted); }
.pg-quests .dm-card p { font-size: var(--fs-sm); color: var(--fg); margin: 0; }

/* the land: the inked hide (or the DM's picture), with the page's own road
   laid over it through the places the DM named. The same names as a list: read
   aloud everywhere, shown only on a phone, where the lettering is too small to
   read. The hide is dark in both themes, so the road keeps fixed inks. */
.pg-quests .qmap { --bd: var(--line-strong); position: relative; margin: 0; aspect-ratio: 900 / 420; clip-path: var(--clip-facet); border: 1px solid var(--bd); background: var(--facet-edges), var(--bg-elev); }
.pg-quests .qmap__art { position: absolute; inset: 0; }
.pg-quests .qmap svg.hx-cover, .pg-quests .qmap__road { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The DM's own map, whole and at its own shape on the mat — never cropped to a
   strip — no taller than most of the screen; a tap opens it full size. OWNER-R2-1 */
.pg-quests .qmap.qmap--photo { aspect-ratio: auto; }
.pg-quests .qmap__open { display: block; position: relative; width: 100%; padding: 0; border: 0; background: var(--bg-elev); cursor: zoom-in; }
.pg-quests .qmap__open .qmap__img { display: block; width: 100%; height: auto; max-height: 70vh; object-fit: contain; }
.pg-quests .qmap__open:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.pg-quests .qmap__zoom { position: absolute; bottom: var(--s-3); inset-inline-end: var(--s-3); display: grid; place-items: center; width: 40px; height: 40px; color: #E9F2EE; background: rgba(10,10,11,.72); clip-path: var(--clip-hex); }
.pg-quests .qmap__zoom .ico { --n: 20; }
.pg-quests .qmap__open:hover .qmap__zoom { color: var(--emerald); }
.pg-quests .qmap__road { pointer-events: none; }
.pg-quests .qmap__way { fill: none; stroke: #2FD39A; stroke-opacity: .9; stroke-linecap: round; }
.pg-quests .qmap__pin { fill: #DCE7E3; fill-opacity: .7; stroke: #0B0C0D; stroke-width: 1.5; }
.pg-quests .qmap__pin.is-here { fill: #9CF0D3; fill-opacity: 1; }
/* a dark halo under each name keeps it legible where it crosses a peak or the road */
.pg-quests .qmap__road text { font-size: 15px; text-anchor: middle; fill: #DCE7E3; fill-opacity: .82; stroke: #0B0C0D; stroke-width: 4px; stroke-linejoin: round; stroke-opacity: .85; paint-order: stroke; }
.pg-quests .qmap__road text.is-here { fill: #9CF0D3; fill-opacity: 1; font-weight: 700; }
.pg-quests .qmap__places:not(.sr-only) { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quests .qmap__places .is-here { color: var(--fg); font-weight: 700; }
/* on a wide screen the map's own lettering names the places: the list is read
   aloud but not shown, unless the map had to cut a name short (.is-shown) */
@media (min-width: 35.0625em) {
  .pg-quests .qmap__places:not(.sr-only):not(.is-shown) { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
.pg-quests .qmap__places li { counter-increment: place; display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.pg-quests .qmap__places i { flex: none; width: 10px; height: 12px; clip-path: var(--clip-hex); background: var(--fg-dim, var(--fg-muted)); opacity: .6; }
.pg-quests .qmap__places .is-here i { background: var(--emerald); opacity: 1; box-shadow: var(--glow); }
.pg-quests .qmap__places span { overflow-wrap: anywhere; }
.pg-quests .qmap__title { position: absolute; top: var(--s-3); inset-inline-start: var(--s-4); font-family: var(--font-display); font-weight: 800; color: #E9F2EE; z-index: 2; padding: 2px 10px; background: rgba(10,10,11,.78); clip-path: var(--clip-facet); --facet: 6px; max-width: calc(100% - 2 * var(--s-4)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 35em) {
  .pg-quests .qmap { aspect-ratio: 4 / 3; }
  /* too small to read at this width: the list under the map names the road instead */
  .pg-quests .qmap svg text { display: none; }
}

/* the campaign so far: what was played lit, the next one ringed, what is ahead hollow */
.pg-quests .tl { list-style: none; padding: 0; margin: 0; position: relative; display: grid; gap: var(--s-4); padding-inline-start: 28px; }
.pg-quests .tl::before { content: ""; position: absolute; top: 8px; bottom: 8px; inset-inline-start: 7px; width: 2px; background: linear-gradient(180deg, var(--emerald) var(--done, 0%), var(--line-strong) var(--done, 0%)); }
.pg-quests .tl li { position: relative; }
.pg-quests .tl li::before { content: ""; position: absolute; top: 6px; inset-inline-start: -28px; width: 16px; height: 16px; clip-path: var(--clip-hex); background: var(--bg-elev-2); box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.pg-quests .tl li.is-done::before { background: var(--emerald); box-shadow: var(--glow); }
/* the next sitting is ringed and lit, and holds still: the page does not pulse at rest */
.pg-quests .tl li.is-next::before { background: var(--bg); box-shadow: inset 0 0 0 2.5px var(--emerald), 0 0 12px rgba(47,211,154,.6); }
.pg-quests .tl li.is-cancelled .tl__t b { text-decoration: line-through; color: var(--fg-muted); }
.pg-quests .tl__t { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--s-2); }
.pg-quests .tl__t b { color: var(--fg-strong); }
.pg-quests .tl__t small { color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.pg-quests .tl li.is-next .tl__t b { color: var(--accent-text); }
.pg-quests .tl p { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--fg-muted); }

/* the party in even rows, never one tile alone at the end (UI-C-R4-4): the
   count a row takes comes from the seat count for each width (quests.js
   rosterStyle), chosen here by the column's own width, measured in its text
   size; a tile is never wider than 11rem, so two seats are two tiles, not two
   halves of the column */
.pg-quests .q-party { container-type: inline-size; }
.pg-quests .roster { display: grid; grid-template-columns: repeat(var(--c-s, 3), minmax(0, 11rem)); gap: var(--s-3); }
@container (min-width: 30em) { .pg-quests .roster { grid-template-columns: repeat(var(--c-m, 4), minmax(0, 11rem)); } }
@container (min-width: 45em) { .pg-quests .roster { grid-template-columns: repeat(var(--c-l, 6), minmax(0, 11rem)); } }
.pg-quests .roster__p { position: relative; display: grid; justify-items: center; align-content: start; gap: var(--s-half); padding: var(--s-3); --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); --facet: 8px; font-size: var(--fs-sm); text-align: center; min-width: 0; }
/* open, its menu hangs past the tile, which is square for that moment: no diagonal drawn across a corner that is not cut */
.pg-quests .roster__p:has(.qmenu[open]) { clip-path: none; z-index: 3; background: var(--bg-elev); }
.pg-quests .roster__p .shield { --seat: 44px; font-size: var(--fs-sm); }
.pg-quests .roster__p.is-free { color: var(--fg-muted); border-style: dashed; }
.pg-quests .roster__name { min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
/* the DM's actions on a player wait behind a quiet menu, not on every tile */
.pg-quests .qmenu { position: absolute; top: 4px; inset-inline-end: 4px; }
.pg-quests .qmenu > summary { list-style: none; cursor: pointer; min-width: 32px; min-height: 32px; font-weight: 800; letter-spacing: .05em; }
.pg-quests .qmenu > summary::-webkit-details-marker { display: none; }
.pg-quests .qmenu__pop { position: absolute; top: calc(100% + 4px); inset-inline-end: 0; z-index: 5; min-width: 170px; padding: 6px; background: var(--bg-elev-2); border: 1px solid var(--line-strong); box-shadow: var(--shadow-drop); display: grid; }
.pg-quests .qmenu__pop .btn { justify-content: flex-start; width: 100%; }
.pg-quests .rules { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-2); }
/* each rule's stave in a column of its own width, level with its sentence's
   first line: the sentences start on one line, and a rule that wraps on a
   phone keeps its stave on its first line, the way every rune-led list on the
   site does (UI-C-R4-3, ICONOGRAPHER-R5-1) */
.pg-quests .rules li { display: flex; align-items: flex-start; gap: var(--s-3); padding: var(--s-3) var(--s-4); background: var(--bg-elev); border-inline-start: 2px solid var(--jade); font-size: var(--fs-sm); }
.pg-quests .rules li .rune { inline-size: 16px; color: var(--rune-lit); }
/* the community rules and the refund rules are named inside a sentence here, so
   their links are underlined like any link in running text (base.css): emerald
   beside body text is a change of hue only, which WCAG 1.4.1 does not accept */
:is(.pg-quests .rules li, .reg__terms li) a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .25em; text-decoration-color: color-mix(in srgb, currentColor 55%, transparent); }
:is(.pg-quests .rules li, .reg__terms li) a:hover { text-decoration-color: currentColor; }
.pg-quests .wait { display: grid; gap: var(--s-3); }
.pg-quests .wait :is(h2,h3) { margin: 0; }
.pg-quests .wait p { margin: 0; font-size: var(--fs-sm); }
.pg-quests .avatar--md { width: 64px; height: 64px; font-size: var(--fs-lg); }

/* ── registration: the stone turns toward you ──
   The stone is the dialog: the shared modal's card, border and frame are
   dropped here, so the stone you clicked is the one object on screen. */
/* The stone has a width of its own — 560px, or the screen less its gutters —
   never its contents': the backdrop's one track is the screen's width, so a
   long name cannot widen the stone past the phone's edge (UI-C-R2-1). */
.modal.modal--stone { width: min(100%, 560px); min-width: 0; max-height: none; overflow: visible; padding: 0; background: none; border: 0; clip-path: none; box-shadow: none; animation: none; }
.modal-backdrop--stone { overflow-y: auto; place-items: safe center; grid-template-columns: minmax(0, 1fr); padding-block: 96px var(--s-6); }
.modal-backdrop--stone.is-leaving { opacity: 0; transition: opacity 240ms var(--ease-out) 80ms; }
/* the close button sits on the stone's shoulder */
.modal--stone .modal__close { top: 30px; inset-inline-end: 10px; z-index: 3; }
/* it belongs to the stone: it leaves when the stone turns away, never after (MOTION-R3-2) */
.modal--stone:has(.reg__stone.is-leaving) .modal__close { opacity: 0; pointer-events: none; transition: opacity 160ms cubic-bezier(.4,0,1,1); }
.reg { --stone-clip: polygon(0 26px, 12% 9px, 50% 0, 88% 9px, 100% 26px, 100% 100%, 0 100%); perspective: 1400px; width: 100%; min-width: 0; }
/* the turn answers a click, so it moves on its first frame: --ease-out, not the heavy curve's dead start (MOTION-12) */
.reg__stone { position: relative; width: 100%; min-width: 0; transform-origin: 50% 100%; transform: rotateY(-35deg) translateZ(-120px) scale(.92); opacity: 0; filter: drop-shadow(0 30px 40px rgba(0,0,0,.6));
  transition: transform 620ms var(--ease-out), opacity 420ms var(--ease-out); }
:root[data-theme="light"] .reg__stone { filter: drop-shadow(0 26px 34px rgba(20,30,26,.28)); }
.reg__stone.is-facing { transform: none; opacity: 1; }
.reg__stone.no-motion { transform: none; opacity: 1; transition: none; }
.reg__stone.is-leaving { transform: rotateY(35deg); opacity: 0; transition: transform 320ms cubic-bezier(.4,0,1,1), opacity 320ms cubic-bezier(.4,0,1,1); }
/* a 2px lit rim, then the carved face: the same gable as the stones in the field */
.reg__body { clip-path: var(--stone-clip); padding: 2px; background: linear-gradient(196deg, var(--emerald), var(--line-glow) 26%, var(--line-strong) 62%, rgba(47,211,154,.3)); }
.reg__face { --reg-pad: var(--s-6); --reg-bar: #25272A; clip-path: var(--stone-clip); position: relative; min-width: 0; padding: var(--s-8) var(--reg-pad) var(--s-6);
  background:
    linear-gradient(196deg, rgba(255,255,255,.06) 0 13%, transparent 13.4%),
    repeating-linear-gradient(93deg, rgba(0,0,0,.14) 0 1px, rgba(255,255,255,.012) 1px 2px, transparent 2px 37px),
    var(--stone-grad-2); }
:root[data-theme="light"] .reg__face { --reg-bar: #F4F5F1; background: linear-gradient(196deg, rgba(255,255,255,.55) 0 13%, transparent 13.4%), repeating-linear-gradient(91deg, rgba(0,0,0,.03) 0 1px, transparent 1px 41px), var(--stone-grad-2); }
.reg__face::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.02 .06' numOctaves='2'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .08 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); }
.reg__face > * { position: relative; }
.reg__head { text-align: center; margin-bottom: var(--s-5); }
.reg__head .rune-band { font-size: var(--rune-sm); }
.reg__head :is(h2,h3) { margin: var(--s-2) 0 0; font-size: var(--fs-2xl); overflow-wrap: anywhere; }
.reg__head p { margin: 4px auto 0; color: var(--fg-muted); font-size: var(--fs-sm); }
.reg__form { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-3); opacity: 0; transform: translateY(8px); transition: opacity var(--t-slow) var(--ease-out) 320ms, transform var(--t-slow) var(--ease-out) 320ms; }
.is-facing .reg__form, .no-motion .reg__form { opacity: 1; transform: none; }
/* on submit the fields sink away one after another */
.reg__form.is-sinking > * { opacity: 0; transform: translateY(6px); transition: opacity 160ms cubic-bezier(.4,0,1,1), transform 160ms cubic-bezier(.4,0,1,1); }
.reg__form.is-sinking > :nth-child(2) { transition-delay: 40ms; } .reg__form.is-sinking > :nth-child(3) { transition-delay: 80ms; } .reg__form.is-sinking > :nth-child(n+4) { transition-delay: 120ms; }
.reg__form .two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }
@media (max-width: 37.5em) { .reg__form .two { grid-template-columns: 1fr; } .reg__face { --reg-pad: var(--s-4); padding: var(--s-7) var(--reg-pad) var(--s-5); } }
.reg__terms { margin: 0; padding-inline-start: 1.1em; display: grid; gap: 4px; font-size: var(--fs-sm); color: var(--fg); }
.reg__terms li::marker { color: var(--rune-lit); }
/* The pledge is said, not ticked: one sentence above the button, and the
   booking commits in one tap (UX2-5). The primary is the largest thing on the
   stone; "back" is a quiet link before it (UI-C-25). An error is red alone. */
.reg__pledge { margin: 0; max-width: none; padding: var(--s-3) var(--s-4); font-size: var(--fs-sm); line-height: 1.7; color: var(--fg); border-inline-start: 2px solid var(--line-glow); background: rgba(0,0,0,.14); }
:root[data-theme="light"] .reg__pledge { background: rgba(255,255,255,.5); }
.reg__error { margin: 0; max-width: none; padding: var(--s-2) var(--s-3); font-size: var(--fs-sm); color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger); border-inline-start-width: 3px; }
.reg__error[hidden] { display: none; }
.reg__actions { display: flex; gap: var(--s-3) var(--s-5); justify-content: space-between; align-items: center; flex-wrap: wrap; margin-top: var(--s-2); }
.reg__back { min-height: 44px; padding: 0 var(--s-1); background: none; border: 0; font: inherit; font-size: var(--fs-sm); color: var(--fg-muted); text-decoration: underline; text-underline-offset: 4px; text-decoration-color: color-mix(in srgb, currentColor 50%, transparent); cursor: pointer; transition: color var(--t-fast) var(--ease-stone); }
.reg__back:hover { color: var(--fg-strong); }
.reg__back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the primary takes the row: the largest control on the stone, never the size of "back" */
.reg__go { flex: 1 1 auto; min-width: 200px; }
@media (max-width: 37.5em) {
  .reg__actions { flex-direction: column; align-items: stretch; gap: var(--s-1); }
  .reg__actions .reg__back { align-self: center; }
  .reg__go { width: 100%; min-width: 0; }
  /* the price rides on the button here too, on a line of its own under the verb */
  .reg__go:has(.q-cta__fee) { flex-direction: column; gap: 0; line-height: 1.3; padding-block: var(--s-2); }
  .reg__go .q-cta__fee .q-sep { display: none; }
  .reg__go .q-cta__fee { font-size: var(--fs-sm); }
}
/* On a short screen the commitment stays in reach (UX-2-R5-4): the deadline,
   skip and hold lines are each right, and together they pushed «pay» below
   the fold just as the sheet opened. The actions row stands at the sheet's
   foot while the terms run on behind it, bled to the face's edges, and takes
   the face's surface and a hairline only while it stands over them (.is-stuck,
   set while the form's end is out of view). The primary stays the primary,
   «back» the quiet one. */
.reg__end { position: absolute; bottom: 0; inset-inline-start: 0; width: 1px; height: 1px; pointer-events: none; }
@media (max-width: 45em), (max-height: 45em) {
  /* bottom: the backdrop's own end padding, which a sticky box stays inside */
  .reg__actions { position: sticky; bottom: calc(-1 * var(--s-6)); z-index: 2; margin: 0 calc(-1 * var(--reg-pad)); padding: var(--s-3) var(--reg-pad) calc(var(--s-3) + env(safe-area-inset-bottom, 0px)); }
  .reg__actions.is-stuck { background: var(--stone-face), var(--reg-bar); box-shadow: 0 -1px 0 var(--line-strong), 0 -18px 24px -18px rgba(0,0,0,.75); }
  :root[data-theme="light"] .reg__actions.is-stuck { box-shadow: 0 -1px 0 var(--line-strong), 0 -18px 24px -18px rgba(20,30,26,.3); }
  /* A field reached by Tab is scrolled into view above the bar, never under it
     (WCAG 2.4.11, A11Y-TYPE-R6-2): the sheet keeps the bar's height, measured
     by quests.js as --reg-bar-h, and a breath more free at its foot. Not while
     the focus is on the bar's own buttons: they are in view where the bar
     stands, and reaching them scrolls nothing. */
  .modal-backdrop--stone:not(:has(.reg__actions :focus)) { scroll-padding-block-end: calc(var(--reg-bar-h, 96px) + var(--s-3)); }
}
/* the raven waits on the stone's shoulder from the moment it faces you */
.reg__raven { position: absolute; top: -58px; inset-inline-start: 7%; width: 84px; z-index: 2; pointer-events: none; opacity: 0; transition: opacity 400ms var(--ease-out) 500ms; }
.reg__raven svg { width: 100%; height: auto; display: block; }
/* the perched bird faces the inline end; on a right-to-left stone it sits at the
   right and looks in, across the stone */
.reg__raven.is-flipped svg { transform: scaleX(-1); }
.is-facing > .reg__raven, .no-motion > .reg__raven { opacity: 1; }
@media (prefers-reduced-motion: no-preference) { .is-facing > .reg__raven { animation: perch 3.2s ease-in-out 1.4s infinite; transform-origin: 40% 90%; } }
@keyframes perch { 0%, 80%, 100% { transform: none; } 86% { transform: rotate(-6deg); } 93% { transform: rotate(2deg); } }
.reg-flight { position: fixed; z-index: var(--z-raven); pointer-events: none; }
.reg-flight svg { width: 100%; height: auto; display: block; }

/* engraving: each line one run of text, wiped in by a mask in its own reading
   direction. The name fits the stone's own width (quests.js layoutName): it
   gets smaller, then takes a second line, never the stone wider. */
.reg__engrave { display: grid; justify-items: center; gap: var(--s-4); text-align: center; padding-block: var(--s-5) var(--s-3); outline: none; min-width: 0; }
.reg__engrave .lead { color: var(--fg-muted); margin: 0; }
.engrave { --wipe: to right; position: relative; display: grid; justify-items: center; width: 100%; min-width: 0; font-family: var(--font-display); font-weight: 900; font-size: clamp(2rem, 7vw, 3.2rem); line-height: 1.3; }
.engrave[dir="rtl"] { --wipe: to left; }
.engrave__line { --p: 0; display: inline-grid; max-width: 100%; white-space: nowrap; padding-inline: .12em; }
.engrave__line > span { grid-area: 1 / 1; }
.engrave__ink { color: var(--fg-strong); text-shadow: 0 -1px 0 rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.08), 0 2px 3px rgba(0,0,0,.45);
  -webkit-mask-image: linear-gradient(var(--wipe), #000 calc(var(--p) * 100%), transparent calc(var(--p) * 100% + 6%)); mask-image: linear-gradient(var(--wipe), #000 calc(var(--p) * 100%), transparent calc(var(--p) * 100% + 6%)); }
:root[data-theme="light"] .engrave__ink { text-shadow: 0 -1px 0 rgba(20,24,22,.3), 0 1px 0 rgba(255,255,255,.9); }
/* the fresh cut glows just behind the edge, then settles into the stone */
.engrave__glow { color: var(--accent-text); text-shadow: 0 0 18px var(--emerald), 0 0 36px rgba(47,211,154,.55); opacity: 0;
  -webkit-mask-image: linear-gradient(var(--wipe), transparent calc(var(--p) * 100% - 25%), #000 calc(var(--p) * 100% - 3%), transparent calc(var(--p) * 100% + 4%)); mask-image: linear-gradient(var(--wipe), transparent calc(var(--p) * 100% - 25%), #000 calc(var(--p) * 100% - 3%), transparent calc(var(--p) * 100% + 4%)); }
.engrave__line.is-cutting .engrave__glow { opacity: 1; }
.engrave__line.is-cut .engrave__ink, .engrave.is-done .engrave__ink { -webkit-mask-image: none; mask-image: none; }
.engrave__line.is-cut .engrave__glow, .engrave.is-done .engrave__glow { opacity: 0; transition: opacity 400ms var(--ease-out); }
.engrave__chisel { position: absolute; top: 50%; left: 0; width: 2px; height: 1.05em; margin: -.52em 0 0 -1px; background: var(--emerald); box-shadow: 0 0 12px var(--emerald), 0 0 3px #fff; opacity: 0; pointer-events: none; }
.engrave__chisel::before { content: ""; position: absolute; top: -4px; left: -2px; width: 6px; height: 6px; clip-path: var(--clip-hex); background: var(--emerald); }
.engrave.is-cutting .engrave__chisel { opacity: 1; }
.spark { position: absolute; width: 4px; height: 4px; clip-path: var(--clip-hex); background: var(--emerald); box-shadow: 0 0 8px var(--emerald); pointer-events: none; animation: spark .65s var(--ease-out) forwards; }
@keyframes spark { 0% { opacity: 1; transform: translate(0, 0) scale(1); } 100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.2); } }
.reg__done { display: grid; justify-items: center; gap: var(--s-2); opacity: 0; transform: translateY(6px); transition: opacity 240ms var(--ease-out), transform 240ms var(--ease-out); }
.reg__done.is-on { opacity: 1; transform: none; }
.reg__done b { color: var(--accent-text); font-size: var(--fs-lg); }
@media (prefers-reduced-motion: reduce) {
  .reg__stone, .reg__stone.is-leaving { transform: none; transition: opacity 200ms linear; }
  .reg__form { opacity: 1; transform: none; transition: none; }
  .reg__done { transform: none; transition: none; }
}

/* ── dice table (live) ── */
/* the table chat's frame and the shapes that wait for its room (the room
   itself, and everything in it, is css/pages/messages.css, fetched with it) */
.pg-quests .qchat { --bd: var(--line-strong); border: 1px solid var(--bd); padding: var(--s-5); background: var(--facet-edges), rgba(255,255,255,.015); clip-path: var(--clip-facet); scroll-margin-block-start: calc(var(--hdr-h) + var(--s-4)); }
.pg-quests .qchat__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); margin-block-end: var(--s-4); }
.pg-quests .qchat__head h2 { margin: 0; }
.pg-quests .qchat__wait { display: flex; flex-direction: column; justify-content: flex-end; gap: var(--s-3); height: clamp(18rem, 58svh, 34rem); padding: var(--s-4); border: 1px solid var(--line); }
.pg-quests .qchat__wait span { height: 44px; width: 55%; background: var(--bg-elev-2); opacity: .55; }
.pg-quests .qchat__wait span:nth-child(2) { width: 38%; margin-inline-start: auto; }
/* the unread count on a way to the chat: a badge on its corner, out of the
   line, so its coming and going moves neither the way nor its neighbours */
.pg-quests .q-chat-at { position: relative; display: inline-flex; }
.pg-quests .q-chat-n { position: absolute; z-index: 1; inset-block-start: -7px; inset-inline-end: -7px; pointer-events: none; }
@media (max-width: 38.75em) { .pg-quests .qchat { padding: var(--s-3); } }
/* a phone shows the chat in brief on this page (messages.css .qchat__peek) and
   opens the room over it: its waiting shape is the brief's size, and an open
   room is not cut by the section's facets (its layer is fixed to the screen) */
@media (max-width: 56.25em) {
  .pg-quests .qchat__wait { height: 9.5rem; }
  .pg-quests .qchat:is(.is-full, .is-leaving) { clip-path: none; }
}
.pg-quests .qtable { --bd: var(--line-strong); border: 1px solid var(--bd); padding: var(--s-5); background: var(--facet-edges), rgba(255,255,255,.015); clip-path: var(--clip-facet); }
.pg-quests .qtable__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.pg-quests .qtable__head h2 { margin: 0; }
.pg-quests .qtable__live { font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quests .qtable__live.is-on { color: var(--accent-text); }
.pg-quests .qtable__live.is-on::before { content: ''; display: inline-block; width: .5em; height: .5em; border-radius: 50%; background: currentColor; margin-inline-end: .4em; box-shadow: 0 0 8px currentColor; }
.pg-quests .qtable__form { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: var(--s-3) var(--s-4); align-items: start; margin-block: var(--s-4); }
.pg-quests .qtable__quick { grid-column: 1 / -1; gap: var(--s-2); flex-wrap: wrap; align-items: center; }
/* advantage and disadvantage sit with the dice, set off by a hairline: one tap each */
.pg-quests .qtable__adv { display: inline-flex; gap: var(--s-2); margin-inline-start: var(--s-1); padding-inline-start: var(--s-3); border-inline-start: 1px solid var(--line-strong); }
/* who sees the roll, in the row of the button that makes it, and the button says it too */
.pg-quests .qtable__go { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
.pg-quests .qtable__vis { --bd: var(--line-strong); display: inline-flex; padding: 3px; gap: 2px; border: 1px solid var(--bd); background: var(--facet-edges), var(--bg); clip-path: var(--clip-facet); --facet: 6px; }
.pg-quests .qtable__seg { position: relative; display: inline-grid; place-items: center; min-height: 38px; padding: 0 var(--s-3); font-size: var(--fs-sm); color: var(--fg-muted); cursor: pointer; transition: color var(--t-fast) var(--ease-stone), background var(--t-fast) var(--ease-stone); }
.pg-quests .qtable__seg input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.pg-quests .qtable__seg:has(input:checked) { color: var(--fg-strong); background: var(--bg-elev-2); box-shadow: inset 0 0 0 1px var(--line-glow); }
.pg-quests .qtable__seg:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
.pg-quests .qtable__roll.is-hidden-roll, .pg-quests .qtable__roll.is-hidden-roll:hover { --btn-bg: rgba(47,211,154,.06); --bd: transparent; color: var(--accent-text); box-shadow: none; filter: none; outline: 1.5px dashed currentColor; outline-offset: -5px; }
/* a die set aside stays legible: struck through and dashed, in the muted ink at full strength (A11Y-TYPE-R3-3) */
.pg-quests .roll__die.is-out { color: var(--fg-muted); border-style: dashed; text-decoration: line-through; text-decoration-thickness: 1.5px; }
@media (max-width: 38.75em) { .pg-quests .qtable__form { grid-template-columns: minmax(0, 1fr); } }
/* the older rolls scroll in their own box, which the keyboard can reach once it scrolls (quests.js syncBox) */
.pg-quests .rollfeed__box { max-height: 26rem; overflow-y: auto; overscroll-behavior: contain; }
.pg-quests .rollfeed__box:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pg-quests .rollfeed { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.pg-quests .roll { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); padding: var(--s-2) var(--s-3); border: 1px solid var(--line); background: rgba(0,0,0,.18); }
/* Frost: a row is a shade of the slab, never black laid over it */
:root[data-theme="light"] .pg-quests .roll { background: color-mix(in srgb, var(--fg) 4%, var(--bg-elev)); }
.pg-quests .roll__who { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; flex: 1 1 12rem; }
.pg-quests .roll__who .muted { font-size: var(--fs-sm); }
.pg-quests .roll__expr { font-size: var(--fs-sm); color: var(--fg-muted); }
/* the dice read as the expression they came from, left to right in both
   languages: a term's sign and the modifier's stand on the left of their
   numbers, never «۵+» (A11Y-TYPE-R4-1) */
.pg-quests .roll__dice { display: inline-flex; gap: .3em; flex-wrap: wrap; direction: ltr; unicode-bidi: isolate; }
.pg-quests .roll__die { font-style: normal; min-width: 1.8em; text-align: center; padding: 0 .3em; border: 1px solid var(--line-strong); font-size: var(--fs-sm); }
.pg-quests .roll__die.is-top { border-color: var(--accent-text); color: var(--accent-text); }
.pg-quests .roll__die.is-low { border-color: var(--danger); color: var(--danger); }
.pg-quests .roll__mod { font-size: var(--fs-sm); color: var(--fg-muted); }
.pg-quests .roll__total { font-size: 1.5rem; min-width: 2ch; text-align: center; color: var(--fg-strong); }
.pg-quests .roll--nat20 { border-color: var(--line-glow); box-shadow: var(--glow-inset); }
.pg-quests .roll--nat1 { border-color: rgba(194,58,43,.5); }
.pg-quests .roll__fail { color: var(--danger); background: var(--danger-bg); }
.pg-quests .roll--hidden { border-style: dashed; }
@media (prefers-reduced-motion: no-preference) { .pg-quests .rollfeed .roll:first-child { animation: roll-in .35s var(--ease-out, ease-out); } }
@keyframes roll-in { from { opacity: 0; transform: translateY(-6px); } }

/* ── DM tools ── */
.pg-quests .qwait { padding-inline-start: 1.6em; display: grid; gap: var(--s-2); }
:root[lang="fa"] .pg-quests .qwait { list-style-type: persian; }
.pg-quests .qwait li > * { vertical-align: middle; }
.pg-quests .qwait .btn { margin-inline-start: var(--s-3); }
.pg-quests .q-note { margin: 0; padding: var(--s-4); border: 1px dashed var(--line-strong); color: var(--fg-muted); font-size: var(--fs-sm); }
/* The DM's payment grid (UX-2-R4-1): the player and what they owe stand still
   at the start while the sittings scroll under them, the next sitting's column
   faintly lit; a shadow at either edge says there is more that way (quests.js
   sets .is-start / .is-end, and --who-w, where the first column ends). */
.pg-quests .q-ledger-box { position: relative; }
.pg-quests .q-ledger td, .pg-quests .q-ledger th { white-space: nowrap; }
.pg-quests .q-ledger .num { text-align: end; font-variant-numeric: tabular-nums; }
.pg-quests .q-ledger tfoot th, .pg-quests .q-ledger tfoot td { color: var(--fg-muted); font-size: var(--fs-xs); border-top: 1px solid var(--line-strong); }
.pg-quests .q-ledger .q-ledger__who { position: sticky; z-index: 2; min-width: 7rem; max-width: 12rem; white-space: normal; overflow-wrap: anywhere; background: linear-gradient(rgba(255,255,255,.02), rgba(255,255,255,.02)), var(--bg); }
.pg-quests .q-ledger .q-ledger__owes { position: sticky; z-index: 2; background: var(--bg); }
/* the page's side, not the cell's: a cell holding a Persian name carries dir="rtl" of its own (HX.enhance) */
:root[dir="rtl"] .pg-quests .q-ledger .q-ledger__who { right: 0; text-align: right; } :root[dir="ltr"] .pg-quests .q-ledger .q-ledger__who { left: 0; text-align: left; }
:root[dir="rtl"] .pg-quests .q-ledger .q-ledger__owes { right: var(--who-w, 9rem); } :root[dir="ltr"] .pg-quests .q-ledger .q-ledger__owes { left: var(--who-w, 9rem); }
.pg-quests .q-ledger th.q-ledger__owes { background: linear-gradient(rgba(255,255,255,.02), rgba(255,255,255,.02)), var(--bg); }
.pg-quests .q-ledger .q-owes { color: var(--fg-strong); }
.pg-quests .q-ledger .is-next { background: rgba(47,211,154,.05); }
.pg-quests .q-ledger th.is-next { color: var(--accent-text); }
.pg-quests .q-ledger th.is-next small { display: block; font-size: var(--fs-2xs); font-weight: 400; color: var(--fg-muted); }
.pg-quests .q-ledger__d, .pg-quests .q-ledger__k, .pg-quests .q-ledger .q-ledger__all { display: none; }
.pg-quests .q-ledger .q-ledger__owes::after, .pg-quests .q-ledger-box::after { content: ""; position: absolute; inset-block: 0; pointer-events: none; opacity: 0; transition: opacity var(--t-fast) var(--ease-out); }
.pg-quests .q-ledger .q-ledger__owes::after { left: -16px; width: 16px; background: linear-gradient(to left, rgba(0,0,0,.6), transparent); }
.pg-quests .q-ledger-box::after { left: 0; z-index: 3; width: 28px; background: linear-gradient(to right, rgba(0,0,0,.6), transparent); }
[dir="ltr"] .pg-quests .q-ledger .q-ledger__owes::after { left: auto; right: -16px; background: linear-gradient(to right, rgba(0,0,0,.6), transparent); }
[dir="ltr"] .pg-quests .q-ledger-box::after { left: auto; right: 0; background: linear-gradient(to left, rgba(0,0,0,.6), transparent); }
:root[data-theme="light"] .pg-quests .q-ledger .q-ledger__owes::after { background: linear-gradient(to left, rgba(20,32,27,.16), transparent); }
:root[data-theme="light"] .pg-quests .q-ledger-box::after { background: linear-gradient(to right, rgba(20,32,27,.18), transparent); }
:root[data-theme="light"][dir="ltr"] .pg-quests .q-ledger .q-ledger__owes::after { background: linear-gradient(to right, rgba(20,32,27,.16), transparent); }
:root[data-theme="light"][dir="ltr"] .pg-quests .q-ledger-box::after { background: linear-gradient(to left, rgba(20,32,27,.18), transparent); }
.pg-quests .q-ledger-box.is-start .q-ledger__owes::after, .pg-quests .q-ledger-box.is-end::after { opacity: 1; }
/* On a phone each player is a card: their name and what they owe, the next
   sitting's state with its «بخشیدن», and the other weeks behind «همه‌ی جلسه‌ها»,
   each with its date. Nothing scrolls sideways. */
@media (max-width: 40em) {
  .pg-quests .q-ledger-wrap { overflow: visible; }
  .pg-quests .q-ledger, .pg-quests .q-ledger tbody { display: block; }
  .pg-quests .q-ledger :is(thead, tfoot) { display: none; }
  .pg-quests .q-ledger tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: var(--s-2) var(--s-3); padding: var(--s-3) 0; border-bottom: 1px solid var(--line); }
  .pg-quests .q-ledger :is(th, td, .q-ledger__who, .q-ledger__owes, .is-next) { position: static; min-width: 0; max-width: none; padding: 0; border: 0; background: none; white-space: normal; text-align: start; }
  .pg-quests .q-ledger .q-ledger__who { grid-area: 1 / 1; font-size: var(--fs-md); }
  .pg-quests .q-ledger .q-ledger__owes { grid-area: 1 / 2; display: grid; justify-items: end; text-align: end; }
  .pg-quests .q-ledger .q-ledger__owes::after { content: none; }
  .pg-quests .q-ledger__k { display: block; font-size: var(--fs-2xs); color: var(--fg-muted); font-weight: 400; }
  .pg-quests .q-ledger td:not(.q-ledger__owes, .q-ledger__all) { grid-column: 1 / -1; display: none; }
  .pg-quests .q-ledger :is(td.is-next, tr.is-open td:not(.q-ledger__owes, .q-ledger__all)) { display: flex; flex-wrap: wrap; align-items: center; gap: 4px var(--s-2); }
  .pg-quests .q-ledger td.is-next { grid-row: 2; padding: var(--s-2); background: rgba(47,211,154,.05); }
  .pg-quests .q-ledger .q-ledger__all { display: block; grid-area: 3 / 1 / 4 / -1; }
  .pg-quests .q-ledger .q-ledger__all .q-quiet { padding-inline: 0; }
  .pg-quests .q-ledger tr.is-open td:not(.is-next, .q-ledger__owes, .q-ledger__all) { padding-inline: var(--s-2); }
  .pg-quests .q-ledger__d { display: inline-block; min-width: 6.5em; color: var(--fg-muted); font-size: var(--fs-xs); }
  .pg-quests .q-ledger .is-next .q-ledger__d { color: var(--accent-text); font-weight: 700; }
  .pg-quests .q-ledger .q-waive { margin-inline-start: 0; min-height: 32px; }
}
.pg-quests .sitting__state .q-got { color: var(--fg-muted); }
/* a sitting paid for and then called off or skipped: where the money went, in the page's ink (UX-2-R6-1) */
.pg-quests .sitting__state .q-back { color: var(--fg); }
/* the member said this sitting never happened (OWNER-R2-8): with the admins now */
.pg-quests .sitting__state .q-reported { color: var(--danger); }
.pg-quests .q-waive { margin-inline-start: 6px; padding: 2px 4px; background: none; border: 0; font: inherit; font-size: var(--fs-xs); color: var(--fg-muted); text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }
.pg-quests .q-waive:hover { color: var(--fg-strong); }
/* A quiet action: words, not a button's plate. Calling one sitting off is one
   of these on every row the DM runs, so it rests in the body's ink and turns
   red only under the pointer or the keyboard — a ladder of red at rest was
   alarm, not safety; the confirm it opens is the danger (UI-C-R3-4). */
.pg-quests .q-quiet { min-height: 32px; padding: 4px var(--s-1); background: none; border: 0; font: inherit; font-size: var(--fs-sm); color: var(--fg-muted); text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); text-underline-offset: 4px; cursor: pointer; transition: color var(--t-fast) var(--ease-stone); }
.pg-quests .q-quiet:hover { color: var(--fg-strong); text-decoration-color: currentColor; }
.pg-quests .q-quiet--danger:is(:hover, :focus-visible) { color: var(--danger); }
.pg-quests .q-quiet:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.earn-neg { color: var(--danger); } .earn-pos { color: var(--accent-text); }

/* moving one sitting: the when, the where and the link to it, each a field of
   its own with room between them (the dialog lives outside the page) */
.q-move { display: grid; gap: var(--s-4); }
.q-move h2 { margin: 0; font-size: var(--fs-xl); line-height: 1.35; padding-inline-end: var(--s-7); }
.q-move > :is(p, .row) { margin: 0; }
.q-move .field[hidden] { display: none; }

/* A map link left pointing at the old address (UX-2-R7-2): said under the
   link, in the warning's red rule, with the one thing to do about it. In the
   edit form and in the move dialog, which is not inside the page, so not
   under .pg-quests. */
.q-stale { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); padding: var(--s-2) var(--s-3); border-inline-start: 3px solid var(--danger); background: var(--danger-bg); font-size: var(--fs-sm); line-height: 1.7; color: var(--fg); }
.q-stale p { flex: 1 1 16rem; margin: 0; }
/* empty, it stays in the page (a live region must be there before it speaks)
   and takes no room, the field's gap above it given back */
.q-stale:not(.is-on) { margin-top: calc(-1 * var(--s-2)); padding: 0; border: 0; background: none; }

/* What everyone will read of a place, said under the field while it is typed
   (OWNER-R8-1): the field's hint, with the public words picked out in the
   page's ink. An address with no comma is public whole — a home's street and
   unit on the open list — so the line turns into the warning's red rule, the
   one the stale map link uses, before anything is saved. Not under
   .pg-quests: the move dialog lives outside the page. */
.q-pub { display: flex; align-items: flex-start; gap: 6px; font-size: var(--fs-xs); line-height: var(--lh-ui); color: var(--fg-muted); }
.q-pub > .ico { --n: 16; flex: none; margin-block-start: calc((1lh - 16px) / 2); }
.q-pub > span { min-width: 0; overflow-wrap: anywhere; }
.q-pub b { font-weight: 700; color: var(--fg-strong); }
.q-pub .num { display: inline-block; }
.q-pub.is-warn { padding: var(--s-2) var(--s-3); border-inline-start: 3px solid var(--danger); background: var(--danger-bg); font-size: var(--fs-sm); line-height: 1.7; color: var(--fg); }
.q-pub.is-warn > .ico { color: var(--danger); }
/* the sittings a new usual place leaves where they are (UX-2-R8-2): a note
   under the address, quiet, in the field's own measure */
.q-kept { display: flex; align-items: flex-start; gap: 6px; padding: var(--s-2) var(--s-3); border: 1px dashed var(--line-strong); font-size: var(--fs-sm); line-height: 1.7; color: var(--fg); }
.q-kept[hidden] { display: none; }
.q-kept > .ico { --n: 16; flex: none; color: var(--fg-muted); margin-block-start: calc((1lh - 16px) / 2); }
.q-kept p { margin: 0; }
.q-kept > :is(p, div) { min-width: 0; overflow-wrap: anywhere; }
.q-kept ul { margin: 2px 0; padding-inline-start: 1.2em; display: grid; gap: 2px; }
.q-kept b { font-weight: 700; color: var(--fg-strong); }

/* ── the create and edit form and its date picker: css/pages/quests-tools.css, fetched with the quests module ── */

/* ── what a whole cancel means, said before it happens ── */
.qcancel { display: grid; gap: var(--s-4); }
.qcancel h2 { margin: 0; font-size: var(--fs-xl); overflow-wrap: anywhere; }
.qcancel__list { margin: 0; padding-inline-start: 1.2em; display: grid; gap: var(--s-2); }
.qcancel__list li::marker { color: var(--danger); }
.qcancel__t { font-weight: 800; color: var(--fg-strong); }
.btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

/* ── what a member owes, and the page back from the gateway: css/pages/quests-tools.css, fetched with the quests module ── */

/* ── sittings: one row a week ── */
.sittings { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-2); }
.sitting { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.1fr) auto; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); --bd: var(--line); background: var(--facet-edges), var(--bg-elev); border: 1px solid var(--bd); clip-path: var(--clip-facet); }
/* A sitting called off is a hollow face, the outline of the evening it would
   have been. Its cut corners are drawn (--facet-edges) as every faceted
   shape's are: with the fill gone they were two gaps, the frame's lines
   stopping short of each other at both cuts (UI-C-R7-3). */
.sitting.is-cancelled { background: var(--facet-edges); }
.sitting.is-cancelled .sitting__when span { text-decoration: line-through; color: var(--fg-muted); }
.sitting.is-skipped .sitting__when span { color: var(--fg-muted); }
.sitting__when { display: grid; gap: 2px; }
.sitting__state { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.sitting__acts { display: flex; flex-wrap: wrap; gap: var(--s-2); justify-content: flex-end; }
@media (max-width: 40em) { .sitting { grid-template-columns: 1fr; } .sitting__acts { justify-content: flex-start; } .sitting > .is-void { display: none; } }
/* ── a narrator's earnings: css/pages/earnings.css, fetched with that page ── */
.vh-owed { margin-bottom: var(--s-5); }
.vh-owed__list { list-style: none; padding: 0; display: grid; gap: var(--s-2); }
.vh-owed__list li { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.pg-quests .nowrap { white-space: nowrap; }
/* the rune separator between facts that carry numbers */
/* isolated: a rune is a left-to-right letter, and loose in a Persian line it pulls the numbers beside it out of order */
.q-sep { font-family: var(--font-rune); color: var(--fg-muted); font-weight: 400; unicode-bidi: isolate; }
/* the rune band sits over the heading's own edge: right in Persian, left in English */
.pg-quests .q-head .rune-band, .pg-quest .qd-hero .rune-band { text-align: right; }
[dir="ltr"] .pg-quests .q-head .rune-band, [dir="ltr"] .pg-quest .qd-hero .rune-band { text-align: left; }
