/* Base tokens and page shell.
 *
 * Token values copied from world-is-fair-v2 web/event-grid.css and web/page.css, and from the landing site's
 * assets/css/main.css (read only). Only the tokens came across, not the component rules.
 *
 * The face is WIF Par flat0, copied into this repo. It has 80 glyphs and no ? ! = + & " ; * [ ] < > or accents.
 * Until the extended face arrives, Georgia renders only those missing characters. Figures are all one width
 * by construction, so tabular-nums only matters for the fallback.
 */

@font-face {
  font-family: "WIF Par";
  src: url("/build/assets/fonts/WIFPar-Flat0.woff2?v=c66ba7c95088") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* grounds: the near-black round the frame (and the wells inside it: fields, icon tiles), the frame's own
     surface, and the raised surfaces of cards on it, lighter as they come up (docs/UI-STEP-1-ROUND-4.md) */
  --ground: rgb(13, 13, 13);
  /* the background shades of the live voting site, worldisflat.fun/fair: copied from world-is-fair-v2
     (web/event-grid.css, --bg-panel, --bg-elevated and --panel-fill), neutral where these were warm */
  --surface: #161616;
  --elevated: #1c1c1c;
  /* the light inner edge of a card or a field (docs/UI-STEP-1-ROUND-3.md: one hairline colour) */
  --hairline: var(--edge-light);

  /* inks: warm cream, never pure white */
  --cream: #f2efe7;
  --warm-ink: 244 239 228;
  --ink: rgb(var(--warm-ink));
  --ink-muted: rgb(var(--warm-ink) / 0.66);
  --ink-subtle: rgb(var(--warm-ink) / 0.52);
  --paper: 237 234 227;

  /* the plate */
  --sky-deep: #757f79;
  --sky-mean: #949b8e;
  --cloud: #c5c3b3;
  --haze: #9f9e8b;

  /* accents (docs/UI-STEP-1-ROUND-4.md, section 7: round 3's warm yellow-brown is gone; labels are the sage) */
  --incised-shadow: #14100ae6;
  --incised-light: #fff8e59e;

  /* states: something to fix is a muted rose, never the green */
  --ok: var(--cloud);
  --alert: rgb(236 140 136);
  --warn: var(--alert);

  /* type scale, from the landing site */
  --t-section: clamp(28px, calc(1.48571429vw + 23.24571429px), 46px);
  --t-subhead: clamp(18px, calc(0.70714286vw + 15.73714286px), 26px);
  --t-label: clamp(15px, calc(0.27777778vw + 14.11111111px), 18px);
  --t-lead: clamp(16px, calc(0.36082474vw + 14.84536082px), 20px);
  --t-body: clamp(14px, calc(0.27358247vw + 13.12453608px), 17px);

  /* robinhood green, copied from world-is-fair-v2 web/event-grid.css (--pons-green, its only green; read only).
     Accents only: read the rules, read more, see all projects, the announcement dot, "$wif" in the projects line */
  --green: #d4fc50;
  /* the same hue (75°) with most of its saturation taken out: a soft sage that sits with the green. Category names
     and small labels, where round 3 had a warm yellow-brown */
  --green-muted: hsl(75 22% 66%);

  /* the frame (docs/UI-STEP-1-ROUND-3.md): the ground round it, its own surface, and the raised panel of the
     menus. Proportions measured on monologue.to */
  --frame-fill: #0d0d0d; /* its page, --bg-page, copied from world-is-fair-v2 */
  --rail: 1200px;
  --panel: #1f1f1f;

  /* the lines (docs/UI-STEP-1-ROUND-4.md, section 9), built the way monologue builds its own (studied at 2x):
     never a flat hairline but a dark core with a soft light edge beside it, so a line reads as cut into the plate
     and a card as raised from it.
     - a guide or a rule: a 1px dark line (black at 60%), with a 1px light line (cream at 20%) blurred by 1px beside
       it: outside a guide, above a rule;
     - the frame's edge: a 1px light line over everything, round the rounded corners;
     - a card, a field, a tab or a button: a 1px light inner edge (cream at 10%) inside a dark outer ring (black at
       60%, 1px, blurred by half a pixel) */
  --line-dark: rgb(0 0 0 / 0.6);
  --line-light: rgb(var(--warm-ink) / 0.2);
  --edge-light: rgb(var(--warm-ink) / 0.1);
  --ring: 0 0 0.5px 1px var(--line-dark);
  --rule: var(--line-dark);
  --panel-inset: rgb(0 0 0 / 0.2);
  --panel-shadow:
    var(--ring), inset 0 0 0 1px var(--edge-light),
    0 24px 64px rgb(0 0 0 / 0.44), 0 8px 20px rgb(0 0 0 / 0.24);

  /* the material (nav bar, tab bar, announcement box, cards, buttons): a translucent sheet over the ground with a
     subtle sheen from the top, a fine inner edge and a soft dark shadow under it. No glow. The feel was measured on
     me.sh's nav (16px blur, a 3% fill, a top-down sheen from 12% to nothing); the values here are our own */
  --material-fill: rgb(var(--warm-ink) / 0.04);
  --material-sheen: linear-gradient(
    180deg,
    rgb(var(--warm-ink) / 0.085),
    rgb(var(--warm-ink) / 0) 72%
  );
  --material-edge: rgb(var(--warm-ink) / 0.13);
  --material-shadow:
    inset 0 1px 0 rgb(var(--warm-ink) / 0.07), inset 0 -1px 0 rgb(0 0 0 / 0.35),
    0 10px 24px -14px rgb(0 0 0 / 0.9);
  /* the solid version, for what opens over the page (menus, the announcement list) */
  --material-solid: #161616;
  /* the bubble's slide and the counter's roll: me.sh's spring, measured (200ms, about 3% over, settled by 380ms) */
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --plate-rule: rgb(var(--warm-ink) / 0.55);

  --gutter: clamp(16px, 4vw, 44px);
  --maxw: 1240px;
  --radius-card: 20px;
  --radius-pill: 999px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --font-display: "WIF Par", Georgia, "Times New Roman", serif;

  color-scheme: dark;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

/* the hidden attribute always wins: a class that sets display (.btn is inline-flex) would otherwise show what the
   page has hidden */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-display);
  font-variation-settings: "FLAT" 0;
  font-kerning: normal;
  font-variant-numeric: tabular-nums;
  font-size: var(--t-body);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

input,
textarea,
select,
button {
  font: inherit;
  color: inherit;
}

/* every tappable thing is at least 44px to a finger (docs/UI-STEP-1.md): fields and selects get a 44px box, and
   links that stand on their own (a project, a person, an address, a builder's link) a 44px row */
input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"]),
select {
  min-height: 44px;
}

/* a link inside a sentence keeps its line: its box grows to 44px with padding, which an inline box adds without
   moving the text around it */
.check a {
  padding-block: max(0px, calc(23px - 0.5em));
}

a.out,
a.mono,
.hexlist a,
.tally td a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  max-width: 100%;
}

a {
  color: inherit;
}

/* the material ------------------------------------------------------------------------------------------------- */

.material,
.tabbar {
  background: var(--material-sheen), var(--material-fill);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  border: 1px solid var(--edge-light);
  box-shadow:
    var(--ring),
    inset 0 1px 0 rgb(var(--warm-ink) / 0.07),
    0 10px 24px -14px rgb(0 0 0 / 0.9);
}

/* the frame (docs/UI-STEP-1-ROUND-3.md, section 1) -------------------------------------------------------------- */

/* The whole page sits in one framed card, rebuilt on monologue.to's layout (measured there, nothing copied): an
   8px margin round it (16px from 1150px), rounded corners (16px on phones, 24px from 720px). Inside, every section
   is a row; rows are split by rules that run the full width of the frame, and each row's content sits in a rail
   between two guides, with side columns outside them: none on phones, 24px from 720px, then at least 60px with the
   rail at most 1200px wide.

   The lines are built as monologue builds them (docs/UI-STEP-1-ROUND-4.md, section 9; the tokens are in :root):
   the frame's edge is a light line drawn over everything; a rule is a dark line with a soft light line above it;
   a guide is a dark line with a soft light line outside it. Where a rule crosses a guide the rule is on top, so
   the crossing is one clean join. */
.frame {
  --side: 0px;
  --pad: 16px;
  --radius-frame: 16px;
  position: relative;
  margin: 8px;
  min-height: calc(100dvh - 16px);
  border-radius: var(--radius-frame);
  background: var(--frame-fill);
}

/* the edge: over the rows and the sticky nav row, under the tab bar and the sheets */
.frame::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 35;
  border: 1px solid var(--line-light);
  border-radius: inherit;
  pointer-events: none;
}

@media (min-width: 720px) {
  .frame {
    --side: 24px;
    --pad: 24px;
    --radius-frame: 24px;
  }
}

@media (min-width: 1150px) {
  .frame {
    --side: max(60px, calc((100% - var(--rail)) / 2));
    margin: 16px;
    min-height: calc(100dvh - 32px);
  }
}

@media (min-width: 1300px) {
  .frame {
    --pad: 40px;
  }
}

/* a row, and its rule along its top edge, across the whole frame. The first row (the nav row) carries its own rule
   along its bottom, so the rule stays with it while it sticks */
.row {
  position: relative;
}

.row::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 4;
  height: 1px;
  background: var(--line-dark);
  box-shadow: 0 -1px 1px var(--line-light);
  pointer-events: none;
}

.navrow + .row::before,
.navrow + main > .row:first-of-type::before {
  display: none;
}

/* the rail: the row's content between the two guides */
.rail {
  margin-inline: var(--side);
  padding: 32px var(--pad);
  border-inline: 1px solid var(--line-dark);
  box-shadow:
    -1px 0 1px var(--line-light),
    1px 0 1px var(--line-light);
  min-width: 0;
}

@media (max-width: 719px) {
  .rail {
    border-inline: 0;
    box-shadow: none;
  }
}

@media (min-width: 1150px) {
  .rail {
    padding-block: 40px;
  }
}

/* row 1, the nav row (section 2) ----------------------------------------------------------------------------- */

/* sticky at the top, inside the frame's width; opaque, so rows pass under it */
/* its rule along the bottom: the dark line with the light line under it, and a fine highlight along its top
   edge, inside the frame's edge (monologue's header, measured) */
.navrow {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--frame-fill);
  border-bottom: 1px solid var(--line-dark);
  border-radius: var(--radius-frame) var(--radius-frame) 0 0;
  box-shadow:
    inset 0 1px 0 rgb(var(--warm-ink) / 0.13),
    0 1px 0.5px var(--line-light);
}

.navrow__rail {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 20px;
  padding-block: 12px;
  min-height: 68px;
}

@media (min-width: 720px) {
  .navrow__rail {
    padding-block: 16px;
    min-height: 84px;
  }
}

@media (min-width: 1150px) {
  .navrow__rail {
    padding-block: 20px;
    min-height: 92px;
  }
}

.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-right: auto;
  text-decoration: none;
  font-size: clamp(18px, calc(0.5vw + 13.5px), 22px);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.navrow__end {
  display: flex;
  align-items: center;
  gap: 18px;
  min-width: 0;
}

.nav__note {
  color: var(--ink-muted);
}

/* phones: the wordmark may take two lines, so the profile button (or sign in) keeps its place beside it */
@media (max-width: 559px) {
  .wordmark {
    flex: 1 1 0;
    min-width: 0;
    white-space: normal;
    line-height: 1.15;
  }
}

/* phones, and from 1024px until the nav and the countdown both fit on one line (1280px): the wordmark (and the nav)
   and the profile button on the first line, the countdown across the second under a rule */
@media (max-width: 559px), (min-width: 1024px) and (max-width: 1279px) {
  .navrow__end {
    display: contents;
  }
  .account__wrap,
  .navrow .btn {
    margin-left: auto;
  }
  .navrow__clock {
    order: 3;
    flex: 1 0 100%;
    margin: 2px calc(-1 * var(--pad)) -4px;
    padding: 8px var(--pad) 0;
    border-top: 1px solid var(--rule);
  }
}

/* the nav: from 1024px, centred in the room between the wordmark and the end. Narrower, the bottom tab bar */
.navbar {
  display: none;
}

@media (min-width: 1024px) {
  .navbar {
    display: block;
    margin-inline: auto;
  }
  .wordmark {
    margin-right: 0;
  }
}

.navbar__list {
  display: flex;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* an item: a plain label; hovered, focused or open, monologue's highlighted pill; open, the chevron flips up */
.navbar__item {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: rgb(var(--warm-ink) / 0.8);
  font-size: 15px;
  letter-spacing: 0.04em;
  text-decoration: none;
  cursor: pointer;
  transition:
    color 0.16s,
    background-color 0.16s;
}

.navbar__item:hover,
.navbar__item:focus-visible,
.navbar__item.is-open {
  color: var(--ink);
  background: rgb(var(--warm-ink) / 0.07);
}

.navbar__item:focus-visible {
  outline-offset: -2px;
}

/* the page you are on: aria-current only, no mark of its own (docs/UI-STEP-1-ROUND-4.md, section 1); hovered or
   open it takes the pill like any other item */

.navbar__item .chevron {
  opacity: 0.64;
  transition: transform 0.2s var(--ease);
}

.navbar__item.is-open .chevron {
  transform: rotate(180deg);
}

/* the floating panel (section 3) ----------------------------------------------------------------------------- */

/* hangs 6px under its row, moves and resizes between menus. Measured on monologue: 340ms on (0.22, 1, 0.36, 1) */
.dd {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 40;
  visibility: hidden;
  pointer-events: none;
  transition:
    width 340ms var(--ease),
    height 340ms var(--ease),
    transform 340ms var(--ease),
    visibility 0s linear 220ms;
}

.dd[data-open="true"] {
  visibility: visible;
  pointer-events: auto;
  transition:
    width 340ms var(--ease),
    height 340ms var(--ease),
    transform 340ms var(--ease),
    visibility 0s;
}

.dd[data-still] {
  transition: none;
}

/* the panel's material: a raised sheet of the frame's own surface, a dark edge, a fine top highlight and a soft
   shadow. Opening: it fades in over 200ms and rises 6px from 98.5% over 300ms; closing, it fades over 150ms */
.dd__view {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 12px;
  background: var(--panel);
  box-shadow: var(--panel-shadow);
  opacity: 0;
  transform: translateY(-6px) scale(0.985);
  transform-origin: 50% 0;
  transition:
    opacity 150ms ease,
    transform 200ms var(--ease);
}

.dd[data-open="true"] .dd__view {
  opacity: 1;
  transform: none;
  transition:
    opacity 200ms ease,
    transform 300ms var(--ease);
}

/* each menu in the panel; going from one to the next, the old one slides 40px out and the new one in */
.dd__panel {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  transform: translateX(40px);
  transition:
    opacity 200ms ease,
    transform 340ms var(--ease);
}

.dd__panel[data-state="left"] {
  transform: translateX(-40px);
}

.dd__panel[data-state="in"] {
  opacity: 1;
  transform: none;
  transition:
    opacity 260ms ease 60ms,
    transform 340ms var(--ease);
}

.dd__panel[data-still] {
  transition: none;
}

/* the menu: two columns, the right one on a slightly darker inset surface, a small label over each */
.mpanel {
  display: flex;
  gap: 8px;
  width: max-content;
  padding: 8px;
}

.mcol {
  min-width: 0;
  padding: 12px 4px 4px;
}

.mcol--inset {
  width: 252px;
  padding: 12px 8px 4px;
  border-radius: 8px;
  background: var(--panel-inset);
  box-shadow: inset 0 0 0 1px rgb(var(--warm-ink) / 0.05);
}

/* the dropdowns from 1024px are wider rather than taller (docs/MENUS-WIDE.md): two columns, filled top to bottom
   (menus.js sets --rows). Projects: "all projects" across the top of the browse side, the categories under it; event:
   the judges, so a long role wraps to fewer lines. The phones' sheet builds them narrow and stays as it was */
.mpanel--wide[data-menu="projects"] .mcol:not(.mcol--inset) .mcol__list {
  grid-auto-flow: column;
  column-gap: 4px;
  grid-template-columns: repeat(2, minmax(0, 290px));
  grid-template-rows: auto repeat(var(--rows, 4), auto);
}

.mpanel--wide[data-menu="projects"]
  .mcol:not(.mcol--inset)
  .mcol__list
  > li:first-child {
  grid-column: 1 / -1;
}

.mpanel--wide[data-menu="event"] .mcol--inset {
  width: auto;
}

.mpanel--wide[data-menu="event"] .mcol--inset .mcol__list {
  grid-auto-flow: column;
  column-gap: 4px;
  grid-template-columns: repeat(2, minmax(0, 228px));
  grid-template-rows: repeat(var(--rows, 3), auto);
  align-items: start;
}

.mcol__label {
  margin: 0 0 8px;
  padding: 0 8px;
  font-size: 12px;
  line-height: 1.45;
  letter-spacing: 0.1em;
  color: rgb(var(--warm-ink) / 0.5);
}

.mcol__list {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* a left column row: the 32px framed tile with its emblem, the title, the one line description */
.mrow {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
  transition: background-color 160ms;
}

.mrow__tile {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  background: var(--ground);
  box-shadow: 0 0 0.5px 1px var(--edge-light);
  color: var(--ink);
}

.mrow__text {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.mrow__title {
  font-size: 15px;
  line-height: 1.25;
  color: var(--ink);
}

/* how many approved projects picked the category: on the row's right */
.mrow__count {
  align-self: start;
  margin-left: auto;
  padding-top: 2px;
  font-size: 12px;
  color: var(--green-muted);
}

.mrow__desc {
  font-size: 13px;
  line-height: 1.3;
  color: rgb(var(--warm-ink) / 0.55);
}

/* a right column row: a small framed picture or emblem, then the label */
.mlink {
  appearance: none;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 6px 8px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: rgb(var(--warm-ink) / 0.85);
  font-size: 15px;
  line-height: 1.25;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 160ms;
}

.mlink__pic {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--ground);
  box-shadow: 0 0 0.5px 1px var(--edge-light);
  color: var(--ink);
}

.mlink__face,
.mlink__face img {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  object-fit: cover;
  font-size: 13px;
}

.mlink--soon {
  color: rgb(var(--warm-ink) / 0.55);
  cursor: default;
}

/* a judge: the name, and under it the role, which may take two or three lines; the picture beside the name */
.mlink--judge {
  align-items: start;
}

.mlink--judge .mlink__pic {
  margin-top: 1px;
}

.mlink__text {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.mlink__desc {
  font-size: 13px;
  line-height: 1.3;
  color: rgb(var(--warm-ink) / 0.55);
}

/* the last row of the right column: "see all projects →" */
.mall {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 2px;
  padding: 0 8px;
  border-radius: 6px;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: rgb(var(--warm-ink) / 0.66);
  text-decoration: none;
  transition:
    color 160ms,
    background-color 160ms;
}

/* hover and keyboard focus on a row: the surface lifts a little */
.mrow:hover,
.mrow:focus-visible,
.mlink:not(.mlink--soon):hover,
.mlink:focus-visible,
.mall:hover,
.mall:focus-visible {
  background: rgb(var(--warm-ink) / 0.06);
  color: var(--ink);
}

.mrow:focus-visible,
.mlink:focus-visible,
.mall:focus-visible {
  box-shadow: inset 0 0 0 1px rgb(var(--warm-ink) / 0.4);
}

/* the bottom sheet (phones): the same menu, full width from the bottom, a drag handle on top ------------------ */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
}

.sheet__scrim {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.55);
  opacity: 0;
  transition: opacity 300ms ease;
}

.sheet[data-open="true"] .sheet__scrim {
  opacity: 1;
}

.sheet__panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  max-height: 86dvh;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-radius: 16px 16px 0 0;
  background: var(--panel);
  box-shadow: var(--panel-shadow);
  transform: translateY(100%);
  transition: transform 320ms var(--ease);
}

.sheet[data-open="true"] .sheet__panel {
  transform: none;
}

.sheet__panel[data-dragging] {
  transition: none;
}

/* the grip: the whole strip drags, the handle shows where */
.sheet__grip {
  flex: none;
  display: flex;
  justify-content: center;
  padding: 10px 0 8px;
  touch-action: none;
  cursor: grab;
}

.sheet__handle {
  width: 40px;
  height: 4px;
  border-radius: 2px;
  background: rgb(var(--warm-ink) / 0.3);
}

.sheet__body {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 8px 12px;
}

.sheet .mpanel {
  flex-direction: column;
  width: auto;
  padding: 0;
}

.sheet .mcol--inset {
  width: auto;
}

html.has-sheet {
  overflow: hidden;
}

/* the centered panel (sheet.js, center: true) from 720px: the sheet's material in the middle of the screen, no
   handle. It fades in and rises 12px, as the menus' panel does */
@media (min-width: 720px) {
  .sheet--center .sheet__panel {
    top: 50%;
    bottom: auto;
    left: 50%;
    right: auto;
    width: min(600px, calc(100vw - 64px));
    max-height: min(86dvh, 760px);
    padding-bottom: 0;
    border-radius: 14px;
    opacity: 0;
    transform: translate(-50%, calc(-50% + 12px)) scale(0.985);
    transition:
      opacity 200ms ease,
      transform 300ms var(--ease);
  }
  .sheet--center[data-open="true"] .sheet__panel {
    opacity: 1;
    transform: translate(-50%, -50%);
  }
  .sheet--center .sheet__grip {
    display: none;
  }
  .sheet--center .sheet__body {
    padding: 0;
  }
}

/* the bubble: a raised segment of the same material, sliding on the spring between items */
.bubble {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  border-radius: 12px;
  background: linear-gradient(
    180deg,
    rgb(var(--warm-ink) / 0.13),
    rgb(var(--warm-ink) / 0.05)
  );
  box-shadow:
    inset 0 1px 0 rgb(var(--warm-ink) / 0.12),
    inset 0 0 0 1px rgb(var(--warm-ink) / 0.08),
    0 2px 6px -2px rgb(0 0 0 / 0.6);
  pointer-events: none;
  transition:
    transform 260ms var(--spring),
    width 260ms var(--spring),
    height 260ms var(--spring),
    opacity 160ms ease-out;
}

.bubble[data-shown="false"] {
  opacity: 0;
}

.bubble[data-still="true"] {
  transition: none;
}

/* the countdown ------------------------------------------------------------------------------------------------ */

.cd {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  min-height: 44px;
}

.cd__label {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  line-height: 1.2;
  letter-spacing: 0.12em;
  /* brighter cream than round 3's, for reading on the dark (docs/UI-STEP-1-ROUND-4.md, section 2) */
  color: rgb(var(--warm-ink) / 0.9);
}

.cd__label a {
  color: var(--ink);
  padding-block: max(0px, calc(23px - 0.5em));
}

.cd__emblem {
  display: inline-flex;
  color: var(--ink);
}

/* no counter: the label alone, in full ink */
.cd[data-state="votesIn"] .cd__label,
.cd[data-state="winner"] .cd__label,
.cd[data-state="noWinner"] .cd__label,
.cd[data-state="unset"] .cd__label {
  font-size: 13px;
  color: var(--ink);
}

.cd__counter {
  display: flex;
  align-items: flex-end;
  gap: 7px;
}

.cd__group {
  display: inline-flex;
  align-items: flex-end;
  gap: 2px;
}

.cd__unit {
  margin-left: 2px;
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.08em;
  color: rgb(var(--warm-ink) / 0.85);
}

/* one counter wheel (docs/UI-STEP-1-ROUND-4.md, section 2): an ivory tile, like the white wheels of an old brass
   counter, with a near-black digit. A flat warm off-white (no gradient), a fine bevel (a bright line along its top
   edge, a darker one along its foot), a soft inner shadow round its edges, and the dark outer ring every raised
   thing has. A fixed box in tabular figures, so a digit rolling inside it never moves anything around it */
.wheel {
  --wh: 24px;
  position: relative;
  display: inline-block;
  width: 16px;
  height: var(--wh);
  overflow: hidden;
  border-radius: 3px;
  background: rgb(238 232 217);
  color: rgb(26 24 21);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.75),
    inset 0 -1px 0 rgb(120 108 86 / 0.55),
    inset 0 0 3px rgb(80 70 50 / 0.4),
    var(--ring),
    0 1px 1px rgb(0 0 0 / 0.5);
  font-size: 16px;
  line-height: var(--wh);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.wheel__stack {
  display: flex;
  flex-direction: column;
  transform: translateY(calc(-1 * var(--wh)));
}

.wheel__digit {
  display: block;
  height: var(--wh);
}

/* the next digit waits above and rolls down into the window, settling with the spring */
.wheel__stack.is-rolling {
  transform: translateY(0);
  transition: transform 300ms var(--spring);
}

/* row 2, the announcement row (docs/UI-STEP-1-ROUND-3.md, section 5) -------------------------------------------- */

/* one centred line, and the past announcements at the end of the row; on phones they stack */
.announce {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding-block: 14px;
  text-align: center;
}

/* from 1024px: the line in the middle, "past announcements" at the end; the side columns are at least as wide as
   that button, so the line stays centred and never runs into it */
@media (min-width: 1024px) {
  .announce {
    display: grid;
    grid-template-columns: minmax(184px, 1fr) minmax(0, auto) minmax(184px, 1fr);
    align-items: center;
    gap: 24px;
    padding-block: 10px;
  }
  .announce__line {
    grid-column: 2;
  }
  .announce__past {
    grid-column: 3;
    justify-self: end;
  }
}

/* one run of text: the emblem sits in the line, so a long announcement wraps round it as text does */
.announce__line {
  margin: 0;
  min-width: 0;
  line-height: 1.5;
  text-align: center;
  overflow-wrap: anywhere;
}

/* the light sweep (docs/UI-STEP-1-ROUND-4.md, section 3): a soft band of brighter cream passes over the letters,
   1.5 seconds a pass, once every 6 seconds. The text is painted by its own background through its glyphs; between
   passes the band rests off the text, so the letters are the plain cream. Reduced motion: no sweep */
.announce__text {
  background: linear-gradient(
      100deg,
      rgb(var(--warm-ink) / 0.9) 0%,
      rgb(var(--warm-ink) / 0.9) 40%,
      rgb(255 252 242) 50%,
      rgb(var(--warm-ink) / 0.9) 60%,
      rgb(var(--warm-ink) / 0.9) 100%
    )
    0 0 / 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: announce-sweep 6s linear infinite;
}

@keyframes announce-sweep {
  0% {
    background-position: 0% 0;
  }
  25% {
    background-position: 100% 0;
  }
  100% {
    background-position: 100% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .announce__text {
    animation: none;
  }
}

.announce__emblem {
  position: relative;
  display: inline-flex;
  margin-right: 10px;
  vertical-align: -4px;
  transform-origin: 50% 2px;
}

.announce__more {
  margin-left: 14px;
}

/* inline in its line: the 44px tap height comes from padding, which doesn't move the text round it */
.announce__more,
.past__more {
  display: inline;
  padding-block: max(0px, calc(23px - 0.5em));
  color: var(--green);
  text-decoration: none;
  white-space: nowrap;
}

.announce__past {
  appearance: none;
  min-height: 44px;
  padding: 0 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: rgb(var(--warm-ink) / 0.6);
  font-size: 13px;
  letter-spacing: 0.04em;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color 160ms,
    background-color 160ms;
}

.announce__past:hover,
.announce__past[aria-expanded="true"] {
  color: var(--ink);
  background: rgb(var(--warm-ink) / 0.07);
}

/* unread: "new" before the emblem, in green, with the light sweep v2 puts on its writing,
   copied from world-is-fair-v2's web/token.css (.mkt-sweep), technique and timing: a fixed 3em band of light, clipped to the letters, crosses
   them in 1.2s, and the next one enters as it leaves. Between passes the letters are the plain green. It shows until
   the viewer opens the past announcements or reads more (docs/UI-STEP-2-FIXES-2.md, section 2). Reduced motion: no
   sweep, the plain green */
.announce__new {
  --label-ink: var(--green);
  --glint: rgb(255 255 255 / 1);
  --glint-w: 3em;
  display: none;
  margin-right: 10px;
  color: var(--label-ink);
  font-size: 13px;
  letter-spacing: 0.08em;
}

.row--announce[data-new="true"] .announce__new {
  display: inline-block;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .announce__new {
    background:
      linear-gradient(
          100deg,
          rgb(255 255 255 / 0) 0%,
          var(--glint) 50%,
          rgb(255 255 255 / 0) 100%
        )
        left calc(-1 * var(--glint-w)) top 0 / var(--glint-w) 100% no-repeat,
      var(--label-ink);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    animation: label-sweep 1.2s linear infinite;
  }
}

@keyframes label-sweep {
  from {
    background-position:
      left calc(-1 * var(--glint-w)) top 0,
      0 0;
  }
  to {
    background-position:
      left calc(100% + var(--glint-w)) top 0,
      0 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .announce__new {
    animation: none;
  }
}

/* the 404 page and "this page couldn't load" (guard.js), one look (docs/UI-FINAL-PASS.md, section 4): in the frame's
   main column, centred, the ship, the line, a light button. In base.css because guard.js runs on every page */
.lost {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 24px;
  min-height: min(56vh, 520px);
  padding-block: 48px;
  text-align: center;
}

.lost__mark {
  display: grid;
  color: rgb(var(--warm-ink) / 0.8);
}

.lost .lost__line {
  max-width: 32ch;
  margin: 0;
  font-size: var(--t-section);
  font-weight: 400;
  line-height: 1.15;
}

/* the one swing as the page loads, when there is something new */
.row--announce[data-new="true"] .announce__emblem.is-swinging {
  animation: notice-swing 900ms ease-out 1;
}

@keyframes notice-swing {
  0% {
    transform: rotate(0);
  }
  20% {
    transform: rotate(-16deg);
  }
  40% {
    transform: rotate(11deg);
  }
  60% {
    transform: rotate(-6deg);
  }
  80% {
    transform: rotate(3deg);
  }
  100% {
    transform: rotate(0);
  }
}

.chevron {
  color: var(--ink-muted);
}

/* the past announcements, in the menus' panel: one column of rows */
.mpanel--past {
  width: min(420px, calc(100vw - 56px));
}

.mpanel--past .mcol {
  flex: 1;
}

.past__item {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 12px;
  padding: 8px;
  align-items: start;
  text-align: left;
}

.past__item + .past__item {
  border-top: 1px solid var(--rule);
}

.past__text {
  display: grid;
  gap: 2px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.past__meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  color: rgb(var(--warm-ink) / 0.55);
}

/* the profile button and its menu ------------------------------------------------------------------------------ */

.account__wrap {
  position: relative;
}

/* a square plate: the outer cream rule, a gap, the picture inside its own rule. 44px on phones, 48 from tablets */
.account {
  appearance: none;
  display: block;
  width: 44px;
  height: 44px;
  padding: 3px;
  border: 1px solid var(--plate-rule);
  border-radius: 9px;
  background: transparent;
  cursor: pointer;
}

.account__plate {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
}

.account__plate::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--plate-rule);
  border-radius: inherit;
  pointer-events: none;
}

@media (min-width: 768px) {
  .account {
    width: 48px;
    height: 48px;
  }
}

/* the menu: the nav menus' panel material (section 3) */
.account__menu {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  z-index: 40;
  margin: 0;
  padding: 6px;
  list-style: none;
  min-width: 220px;
  max-width: calc(100vw - 32px);
  background: var(--panel);
  border-radius: 12px;
  box-shadow: var(--panel-shadow);
}

.account__menu a,
.account__menu button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 160ms;
}

.account__menu a:hover,
.account__menu button:hover,
.account__menu a:focus-visible,
.account__menu button:focus-visible {
  background: rgb(var(--warm-ink) / 0.06);
}

.account__menu a:focus-visible,
.account__menu button:focus-visible {
  box-shadow: inset 0 0 0 1px rgb(var(--warm-ink) / 0.4);
}

.account__menu li:last-child {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--rule);
}

/* the bottom tab bar: below 1024px, where the nav row has no room for the nav (monologue folds its nav away below
   about 1000px). Fixed above the home bar, the material, and the sliding bubble; each tab with its emblem.
   projects and event open their menus as bottom sheets */
.tabbar {
  position: fixed;
  left: 8px;
  right: 8px;
  bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  z-index: 40; /* over the frame's edge (35) */
  border-radius: 18px;
  padding: 4px;
  background-color: rgb(20 19 17 / 0.88);
}

.tabbar ul {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.tab {
  position: relative;
  z-index: 1;
  appearance: none;
  border: 0;
  border-radius: 14px;
  background: transparent;
  width: 100%;
  min-height: 52px;
  padding: 6px 2px 5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  color: var(--ink-subtle);
  text-decoration: none;
  font-size: clamp(12px, calc(0.6vw + 10px), 14px);
  line-height: 1.1;
  cursor: pointer;
  transition: color 0.1s ease-in-out;
}

/* the current tab: full ink and the bubble under it, so it never rests on colour alone */
.tab[aria-current="page"],
.tab.is-bubbled {
  color: var(--ink);
}

.tab:focus-visible {
  outline-offset: -2px;
}

.tabbar .bubble {
  border-radius: 14px;
}

/* content clears the bar */
body {
  padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
}

@media (min-width: 1024px) {
  .tabbar {
    display: none;
  }
  body {
    padding-bottom: 0;
  }
}

/* the two buttons (docs/UI-STEP-1-ROUND-3.md, section 4, made slimmer by round 4, section 5), rebuilt on
   monologue's (measured, not copied), used everywhere on the site:
   - light (.btn): the main action. A metallic cream face: a vertical sheen a little darker at both edges than at
     its middle, a cream edge, a soft inner highlight along the top and a soft two-step shadow under it.
   - dark (.btn--quiet): everything secondary (read the rules, post an update, cancel). A dark face with a gentle
     top-down sheen, the light inner edge every card has, the same shadow.
   Both 44px tall (the tap rule's minimum, monologue's own height) with 16px sides; the hero's 48px with 20px.
   Hover lifts 1px and deepens the shadow; a press sinks 1px with the shadow turned inward. 180ms. */
.btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid rgb(242 239 231);
  border-radius: 9px;
  background: linear-gradient(
    180deg,
    rgb(214 209 198) 0%,
    rgb(250 248 243) 50%,
    rgb(214 209 198) 100%
  );
  color: rgb(38 36 33);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.6),
    0 1px 2px rgb(0 0 0 / 0.4),
    0 6px 14px rgb(0 0 0 / 0.16);
  font-size: 15px;
  letter-spacing: 0.03em;
  line-height: 1.1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color 180ms,
    box-shadow 180ms,
    transform 180ms;
}

.btn:hover {
  transform: translateY(-1px);
  border-color: rgb(255 253 248);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.75),
    0 4px 7px rgb(0 0 0 / 0.46),
    0 14px 26px rgb(0 0 0 / 0.3);
}

.btn:active {
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 3px rgb(0 0 0 / 0.2),
    0 1px 2px rgb(0 0 0 / 0.44);
}

.btn--quiet {
  border-color: var(--edge-light);
  background: linear-gradient(180deg, rgb(64 62 58) 0%, rgb(46 44 41) 100%);
  color: var(--ink);
  box-shadow:
    inset 0 1px 0 rgb(var(--warm-ink) / 0.08),
    0 1px 2px rgb(0 0 0 / 0.44),
    0 6px 14px rgb(0 0 0 / 0.2);
}

.btn--quiet:hover {
  border-color: rgb(var(--warm-ink) / 0.18);
  box-shadow:
    inset 0 1px 0 rgb(var(--warm-ink) / 0.12),
    0 4px 7px rgb(0 0 0 / 0.5),
    0 14px 26px rgb(0 0 0 / 0.32);
}

.btn--quiet:active {
  box-shadow:
    inset 0 2px 3px rgb(0 0 0 / 0.26),
    0 1px 2px rgb(0 0 0 / 0.48);
}

/* the hero's main button: a little larger, still slim */
.btn--large {
  min-height: 48px;
  padding: 0 20px;
  font-size: 16px;
}

.btn:disabled,
.btn:disabled:hover {
  cursor: default;
  transform: none;
  color: var(--ink-subtle);
  background: rgb(var(--warm-ink) / 0.04);
  border-color: var(--rule);
  box-shadow: none;
}

.btn:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* people: an uploaded avatar, or the first letter in a plain square */
.avatar {
  display: inline-block;
  width: 96px;
  height: 96px;
  border-radius: 12px;
  border: 1px solid var(--hairline);
  object-fit: cover;
  background: var(--surface);
  flex: none;
}

.avatar--small {
  width: 28px;
  height: 28px;
  border-radius: 6px;
}

.avatar--letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-muted);
  font-size: var(--t-subhead);
  text-transform: lowercase;
}

/* the profile button's picture, filling its plate; with no picture, the first letter set large in the same frame */
.avatar--plate {
  display: flex;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
}

.avatar--plate.avatar--letter {
  font-size: 24px;
  color: var(--ink);
}

.avatar--small.avatar--letter {
  font-size: var(--t-body);
}

.person {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex-wrap: wrap;
}

.person__name {
  overflow-wrap: anywhere;
  min-width: 0;
}

.person__handle {
  color: var(--ink-muted);
}

.nav__me {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.nav__me span {
  overflow-wrap: anywhere;
  min-width: 0;
}

/* text someone typed (a name, a team, a one liner, an update) can be one unbroken run of 60 or 80 characters; it
   wraps inside its box instead of pushing the page sideways */
.lead,
.panel__title,
.card__title,
.status,
.updates__meta,
.updates__body,
.team__name {
  overflow-wrap: anywhere;
}

.team,
.team__members li,
.person {
  min-width: 0;
  max-width: 100%;
}

/* motion: none for anyone who asked for less */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* ---- links and text buttons: no underlines, a hover effect instead (CLAUDE.md, docs/NO-UNDERLINES.md) -------------
   at rest a link is its text's own colour; on hover it turns --green and a trailing arrow (dom.js puts it in its own
   span) nudges 3px right over 150ms; the pointer shows; keyboard focus draws the cream ring, never removed. A link
   inside running text is --green-muted at rest, so it reads as a link without an underline. Reduced motion: the
   colour only. Links that are cards, rows, tabs or buttons keep their own hover and are left out here */
a,
a:hover,
a:focus,
button {
  text-decoration: none;
}

a,
button:not(:disabled),
[role="button"] {
  cursor: pointer;
}

:is(a, button:not(.btn)):not(
  .btn,
  .ptile,
  .ptile__link,
  .tcard,
  .checklist__item,
  .steplist__item,
  .pfilter,
  .mrow,
  .mlink,
  .mall,
  .tab,
  .wordmark,
  .ilink,
  .vposter,
  .navbar__item,
  .choice,
  .lplate
) {
  transition: color 150ms;
}

:is(a, button:not(.btn)):not(
    .btn,
    .ptile,
    .ptile__link,
    .tcard,
    .checklist__item,
    .steplist__item,
    .pfilter,
    .mrow,
    .mlink,
    .mall,
    .tab,
    .wordmark,
    .ilink,
    .vposter,
    .navbar__item,
    .choice,
    .lplate
  ):not(:disabled):hover {
  color: var(--green);
}

/* a link inside a sentence: the sage at rest */
:is(.check, .prose, .field__help, .lead, .form__help) a:not(.btn) {
  color: var(--green-muted);
}

:is(.check, .prose, .field__help, .lead, .form__help) a:not(.btn):hover {
  color: var(--green);
}

/* the trailing arrow, in its own span (dom.js): it nudges right on hover */
.arrow {
  display: inline-block;
  transition: transform 150ms ease-out;
}

:is(a, button):hover .arrow {
  transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  :is(a, button):hover .arrow {
    transform: none;
  }
}

/* keyboard focus: the cream ring on every link and button, never removed */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[role="menuitem"]:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* the privy sign in modal in our register, as far as privy allows (docs/UI-FINAL-PASS.md, section 4): our ground,
   the cream ink, the green accent, our corners and our font. Privy sets these on :root from its config; html:root
   is one step more specific, so ours hold */
html:root {
  /* copied from world-is-fair-v2 (web/trollbox.css): the page, a panel, a raised row */
  --privy-color-background: #0d0d0d;
  --privy-color-background-2: #161616;
  --privy-color-background-3: #1c1c1c;
  --privy-color-background-clicked: rgb(64 64 63);
  --privy-color-foreground: rgb(244 239 228);
  --privy-color-foreground-2: rgb(214 208 196);
  --privy-color-foreground-3: rgb(170 164 152);
  --privy-color-foreground-4: rgb(120 116 107);
  --privy-color-foreground-accent: rgb(26 24 21);
  --privy-color-accent: #d4fc50;
  --privy-color-border-default: rgb(70 68 63);
  --privy-border-radius-xs: 4px;
  --privy-border-radius-sm: 6px;
  --privy-border-radius-md: 9px;
  --privy-border-radius-mdlg: 12px;
  --privy-border-radius-lg: 14px;
}

#privy-dialog,
#privy-modal-content {
  font-family: var(--font-display);
}

/* the drawer (sheet.js, side: true): a full-screen sheet on phones; from 720px it slides in from the right, full
   height, no handle */
/* The drawer floats as the frame does (docs/JUDGE-PANEL-FIXES.md, section 1): the frame's own gap from the window's
   edges (8px, 16px from 1150px) and its corners (16px, 24px from 720px), with the same light edge. On phones it is
   the full width, rising from the foot to 8px under the top. */
.sheet--side .sheet__panel {
  top: 8px;
  max-height: none;
  border: 1px solid var(--line-light);
  border-bottom: 0;
  border-radius: 16px 16px 0 0;
}

@media (min-width: 720px) {
  .sheet--side .sheet__panel {
    top: 8px;
    right: 8px;
    bottom: 8px;
    left: auto;
    width: min(640px, calc(100vw - 48px));
    border-bottom: 1px solid var(--line-light);
    border-radius: 24px;
    overflow: hidden;
    transform: translateX(calc(100% + 8px));
  }
  .sheet--side[data-open="true"] .sheet__panel {
    transform: none;
  }
  .sheet--side .sheet__grip {
    display: none;
  }
}

@media (min-width: 1150px) {
  .sheet--side .sheet__panel {
    top: 16px;
    right: 16px;
    bottom: 16px;
    transform: translateX(calc(100% + 16px));
  }
}

/* its content fills it, so a footer in it sits at the foot even under a short page (docs/JUDGE-DRAWER.md) */
.sheet--side .sheet__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: 0;
}
