/* ==========================================================================
   Gathering — Amsterdam, 22–25 September 2026
   ==========================================================================

   The visual idea: a ship's log kept during four days at sea. The schedule is
   a typed watch bill, so the display face is monospace with tabular figures —
   which also stops the live clock from jittering as digits change width. What
   people write by hand (bios, wishes, notes on stickers, feedback) is set in
   an old-style serif, so the difference between "the plan" and "a person" is
   visible before you read a word. Controls use the system sans and stay quiet.

   No web fonts: the CSP is font-src 'self' and a self-hosted face would cost
   a render-blocking round trip for eight people on hotel wifi.

   Dynamic numbers (progress, positions) arrive as custom properties set from
   JavaScript via el.style.setProperty. The CSP has no 'unsafe-inline' for
   style-src, so a style="" attribute in rendered markup would be dropped on
   the floor; the CSSOM route is not inline content and works.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* Harbour water at night, hull steel, oxidized copper, brass, chart paper. */
  --ink: #0a1a21;
  --ink-2: #061116;
  --hull: #10262f;
  --hull-2: #17323d;
  --verdigris: #5cb8a3;
  --verdigris-dim: #3c8a78;
  --brass: #c9a227;
  --signal: #e2543b;
  --chart: #ece4d3;
  --fog: #8ba0a9;
  --rope: rgba(236, 228, 211, 0.12);
  --rope-strong: rgba(236, 228, 211, 0.24);

  --font-log: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Consolas, monospace;
  --font-hand: "Iowan Old Style", "Palatino Linotype", Palatino, "Hoefler Text", Georgia, serif;
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --step--1: 0.78rem;
  --step-0: 0.94rem;
  --step-1: 1.12rem;
  --step-2: 1.4rem;
  --step-3: 1.85rem;

  --gap: 0.75rem;
  --pad: 1rem;
  --radius: 3px;
  --rail: 15rem;
  --rail-time: 6.6rem;
  --measure: 46rem;

  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --tabbar-h: 3.65rem;
}

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

html {
  -webkit-text-size-adjust: 100%;
  background: var(--ink-2);
}

body {
  margin: 0;
  min-height: 100dvh;
  background:
    radial-gradient(120% 60% at 50% -10%, rgba(92, 184, 163, 0.09), transparent 60%),
    linear-gradient(180deg, var(--ink) 0%, var(--ink-2) 100%);
  background-attachment: fixed;
  color: var(--chart);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.5;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-log);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

p { margin: 0 0 0.75em; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--verdigris);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}
a:hover { color: var(--chart); }

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

img { max-width: 100%; display: block; }

/* --------------------------------------------------------------------------
   One rule, because the alternative is remembering it twelve times.

   Every box below is sized by its container and filled with a string somebody
   typed: a name, a bio, a note on a sticker, an admin-written block title, an
   address with no spaces in it, a pasted URL. Without this, one long unbroken
   word does not overflow its own box quietly — it widens the grid row or flex
   line it sits in, which pushes the column next to it off the screen and puts
   the whole page into horizontal scroll. Breaking mid-word is the lesser evil,
   and it only happens to strings that had no better break point anyway.

   Excluded on purpose: `.log-time`, `.watch-clock`, `.masthead-where` and the
   other tabular fields, which are short, fixed in shape, and align in columns
   that a wrap would break.
   -------------------------------------------------------------------------- */
.page-title, .page-sub,
.watch-title, .watch-when, .watch-next,
.log-title, .log-notes,
.card-title, .card-aside,
.daychip,
.roll-name,
.chip-name, .chip-what,
.sticker-who, .sticker-note,
.prose, .wishes, .feedback-item,
.notice, .hint, .empty, .label,
.photo-row-name, .photo-row-mail,
.admin-day > summary, .kv dd,
.code-value {
  overflow-wrap: anywhere;
}

:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
  border-radius: 2px;
}

::selection { background: rgba(201, 162, 39, 0.34); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: -3rem;
  left: 0.5rem;
  z-index: 100;
  padding: 0.5rem 0.75rem;
  background: var(--brass);
  color: var(--ink-2);
  font-family: var(--font-log);
  text-decoration: none;
}
.skip-link:focus { top: calc(0.5rem + var(--safe-t)); }

.boot {
  margin: 25vh auto 0;
  max-width: 20rem;
  padding: 0 1rem;
  color: var(--fog);
  font-family: var(--font-log);
  text-align: center;
}

/* --------------------------------------------------------------------------
   Shell: bottom tabs on a phone, a left rail from 900px up.
   -------------------------------------------------------------------------- */

.shell {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100dvh;
}

/* The column beside the rail. `min-width: 0` because a grid item sized by its
   contents would be widened by the day rail's row of chips instead of letting
   it scroll. */
.page { min-width: 0; }

/* The read-only shell has no tab bar, so the main pane keeps the room the tab
   bar would have taken. */
.shell-bare .main { padding-bottom: calc(var(--safe-b) + 1.5rem); }

/* The calendar card closes a page rather than opening one, so it keeps its
   distance from the log above it. */
.calendar-card { margin-top: 2rem; }
.calendar-card code {
  display: block;
  overflow-wrap: anywhere;
}

.viewer-note {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rope);
}

.main {
  padding: var(--pad);
  padding-bottom: calc(var(--tabbar-h) + var(--safe-b) + 1.5rem);
  max-width: var(--measure);
  width: 100%;
  margin: 0 auto;
}

.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: calc(0.6rem + var(--safe-t)) var(--pad) 0.6rem;
  background: rgba(6, 17, 22, 0.86);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rope);
}

.masthead-mark {
  font-size: var(--step-1);
  line-height: 1;
}

/* One flex line with no room to spare on a small phone. The name is the half
   that stays readable when it is cut, so the name is the half that shrinks and
   the dates keep their full width — otherwise the two run into each other and
   the whole strip overflows sideways. */
.masthead-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-log);
  font-size: var(--step-0);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.masthead-where {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   The watch bar — the signature element.

   It is the same object in two sizes: a strip at the top of every page saying
   what is running right now, and, on the schedule, the head of a day timeline
   that a moving position line runs through.
   -------------------------------------------------------------------------- */

.watch {
  position: relative;
  margin: 0 0 var(--gap);
  padding: 0.8rem 0.9rem 0.9rem;
  background:
    linear-gradient(180deg, rgba(23, 50, 61, 0.9), rgba(16, 38, 47, 0.9));
  border: 1px solid var(--rope);
  border-left: 2px solid var(--verdigris);
  border-radius: var(--radius);
}

.watch[data-phase="before"] { border-left-color: var(--brass); }
.watch[data-phase="after"] { border-left-color: var(--rope-strong); }
.watch[data-phase="in-gap"],
.watch[data-phase="between-days"] { border-left-color: var(--fog); }

.watch-kicker {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  color: var(--brass);
  font-family: var(--font-log);
  font-size: var(--step--1);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
/* The label between the dot and the clock: it gives way rather than pushing
   the clock out of the bar. */
.watch-kicker > [data-watch-kicker] { min-width: 0; }

.watch-clock {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--chart);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}

/* The dot is decoration and must not be squeezed into an ellipse by a long
   kicker next to it. */
.watch-dot { flex: 0 0 auto; }

/* The live dot. It is the only thing on the page that blinks, and it stops
   blinking when nothing is running. */
.watch-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--signal);
  box-shadow: 0 0 0 0 rgba(226, 84, 59, 0.6);
  animation: pulse 2.4s ease-out infinite;
}
.watch:not([data-phase="in-block"]) .watch-dot {
  background: var(--fog);
  animation: none;
  box-shadow: none;
}

@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(226, 84, 59, 0.55); }
  70% { box-shadow: 0 0 0 0.5rem rgba(226, 84, 59, 0); }
  100% { box-shadow: 0 0 0 0 rgba(226, 84, 59, 0); }
}

.watch-title {
  margin: 0.35rem 0 0.15rem;
  font-family: var(--font-log);
  font-size: var(--step-1);
}

.watch-when {
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

/* The separator lives in CSS so that a status appearing or disappearing on a
   live tick needs a text update and nothing else. */
.watch-when [data-watch-status]:not(:empty)::before { content: " · "; }

.watch-next {
  margin-top: 0.7rem;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--rope);
  color: var(--fog);
  font-size: var(--step--1);
}
.watch-next strong {
  color: var(--chart);
  font-weight: 500;
}
.watch-next .mono { font-family: var(--font-log); font-variant-numeric: tabular-nums; }

/* A depth sounding: ticks along a track, filled to --p (0..1). */
.sounding {
  --p: 0;
  position: relative;
  height: 0.5rem;
  margin: 0.6rem 0 0.15rem;
  background:
    repeating-linear-gradient(90deg, var(--rope) 0 1px, transparent 1px 12.5%),
    rgba(6, 17, 22, 0.7);
  border: 1px solid var(--rope);
  border-radius: 999px;
  overflow: hidden;
}

.sounding-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--p) * 100%);
  background: linear-gradient(90deg, var(--verdigris-dim), var(--verdigris));
  transition: width 900ms linear;
}

.sounding-bead {
  position: absolute;
  top: 50%;
  left: calc(var(--p) * 100%);
  width: 0.42rem;
  height: 0.42rem;
  margin: -0.21rem 0 0 -0.21rem;
  border-radius: 50%;
  background: var(--brass);
  transition: left 900ms linear;
}

/* --------------------------------------------------------------------------
   Navigation
   -------------------------------------------------------------------------- */

.tabbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 30;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  padding-bottom: var(--safe-b);
  background: rgba(6, 17, 22, 0.94);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--rope);
}

/* `position: relative` so the badge below is placed against the tab it belongs
   to. Without it the badge is positioned against the fixed tab bar and lands
   wherever the flex static position happens to fall — which is on top of the
   label as soon as the label is more than one short word. */
.tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  min-height: var(--tabbar-h);
  padding: 0.4rem 0.2rem;
  color: var(--fog);
  font-family: var(--font-log);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-decoration: none;
  text-transform: uppercase;
}
.tab-icon { font-size: 1.1rem; line-height: 1; }
.tab[aria-current="page"] {
  color: var(--chart);
  box-shadow: inset 0 2px 0 0 var(--verdigris);
}
/* Pinned to the top-right of the icon rather than offset from wherever it would
   otherwise sit, so it clears the label at every label length. */
.tab .badge {
  position: absolute;
  top: 0.5rem;
  left: 50%;
  margin-left: 0.5rem;
  padding: 0 0.28rem;
  border-radius: 999px;
  background: var(--signal);
  color: var(--chart);
  font-size: 0.6rem;
  line-height: 1.35;
}

.rail { display: none; }

/* --------------------------------------------------------------------------
   The log: one day as a typed list of blocks, crossed by the position line.
   -------------------------------------------------------------------------- */

.dayrail {
  display: flex;
  gap: 0.4rem;
  margin: 0 0 var(--gap);
  padding-bottom: 0.25rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.dayrail::-webkit-scrollbar { display: none; }

.daychip {
  flex: 0 0 auto;
  padding: 0.45rem 0.7rem;
  background: rgba(23, 50, 61, 0.55);
  border: 1px solid var(--rope);
  border-radius: var(--radius);
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.daychip[aria-pressed="true"] {
  background: var(--hull-2);
  border-color: var(--verdigris);
  color: var(--chart);
}
.daychip-date { display: block; font-variant-numeric: tabular-nums; }
.daychip-note {
  display: block;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--brass);
}

.log {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The time rail. Its width is set by the longest string it has to hold —
   "10:00 – 10:30", thirteen monospace characters — because .log-time cannot
   wrap without breaking the row's alignment with the position line. Too narrow
   and the time runs under the title's icon. Keep --rail-time and the two grids
   below in step. */
.log-row {
  display: grid;
  grid-template-columns: var(--rail-time) 1fr;
  gap: 0 0.75rem;
  padding: 0.7rem 0;
  border-top: 1px solid var(--rope);
}
.log-row:last-child { border-bottom: 1px solid var(--rope); }

.log-time {
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--fog);
  white-space: nowrap;
}
.log-dur {
  display: block;
  font-size: 0.66rem;
  color: rgba(236, 228, 211, 0.38);
}

.log-title {
  min-width: 0;
  font-family: var(--font-log);
  font-size: var(--step-0);
  font-weight: 600;
}

.log-kind {
  margin-left: 0.4rem;
  font-family: var(--font-ui);
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fog);
}

.log-notes {
  margin-top: 0.3rem;
  font-family: var(--font-hand);
  font-size: var(--step-0);
  line-height: 1.45;
  color: rgba(236, 228, 211, 0.78);
  white-space: pre-line;
}

.log-tbd {
  display: inline-block;
  margin-top: 0.3rem;
  padding: 0 0.35rem;
  border: 1px dashed var(--rope-strong);
  border-radius: 2px;
  color: var(--brass);
  font-family: var(--font-log);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.log-row[data-status="done"] .log-title { color: var(--fog); font-weight: 400; }
.log-row[data-status="done"] .log-notes { color: rgba(236, 228, 211, 0.45); }

.log-row[data-status="active"] {
  margin: 0 -0.6rem;
  padding: 0.7rem 0.6rem;
  background: linear-gradient(90deg, rgba(92, 184, 163, 0.12), transparent 70%);
  border-top-color: var(--verdigris);
}
.log-row[data-status="active"] .log-time { color: var(--verdigris); }

.log-live {
  margin-top: 0.45rem;
  color: var(--verdigris);
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

/* The position line. It sits in the flow between two rows rather than floating
   over them, so it can never cover a title on a narrow screen. */
.nowline {
  display: grid;
  grid-template-columns: var(--rail-time) 1fr;
  gap: 0 0.75rem;
  align-items: center;
  margin: 0;
  padding: 0.15rem 0;
  color: var(--signal);
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}
.nowline-time { text-align: right; letter-spacing: 0.04em; }
.nowline-rule {
  height: 1px;
  background: linear-gradient(90deg, var(--signal), rgba(226, 84, 59, 0.05));
  position: relative;
}
.nowline-rule::before {
  content: "";
  position: absolute;
  left: 0;
  top: -0.19rem;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--signal);
}

/* --------------------------------------------------------------------------
   Cards, prose, empty states
   -------------------------------------------------------------------------- */

.card {
  margin: 0 0 var(--gap);
  padding: var(--pad);
  background: rgba(16, 38, 47, 0.62);
  border: 1px solid var(--rope);
  border-radius: var(--radius);
}

.card-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

.card-title {
  min-width: 0;
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fog);
}

/* Dates and counts, which are short — but a day subtitle also lands here, and
   an admin can type anything into that. `0 1 auto` keeps a short aside at its
   natural width and lets a long one give way instead of shoving the title. */
.card-aside {
  flex: 0 1 auto;
  min-width: 0;
  margin-left: auto;
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

.page-title {
  margin: 0.25rem 0 0.15rem;
  font-size: var(--step-2);
}

.page-sub {
  margin: 0 0 var(--gap);
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
}

.prose {
  font-family: var(--font-hand);
  font-size: var(--step-1);
  line-height: 1.55;
  white-space: pre-line;
}

/* What someone wishes their teammates, set apart with a hanging quote mark. */
.wishes {
  position: relative;
  margin: 0;
  padding-left: 1.1rem;
  font-family: var(--font-hand);
  font-size: var(--step-1);
  font-style: italic;
  line-height: 1.5;
  white-space: pre-line;
  color: var(--chart);
}
.wishes::before {
  content: "“";
  position: absolute;
  left: 0;
  top: -0.15em;
  color: var(--brass);
  font-size: 1.6em;
  line-height: 1;
}

.empty {
  padding: 1.1rem 0.9rem;
  border: 1px dashed var(--rope-strong);
  border-radius: var(--radius);
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  text-align: center;
}

.muted { color: var(--fog); }
.mono { font-family: var(--font-log); font-variant-numeric: tabular-nums; }

.spaced { margin-top: var(--gap); }
.stack > * + * { margin-top: var(--gap); }
/* A list used as layout rather than as prose keeps the semantics and loses the
   bullet: these are rows of controls, not things being enumerated. */
ul.stack, ol.stack { list-style: none; margin: 0; padding: 0; }
.row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   The muster roll — the sticker board.

   Crew order by default, not a ranking: among eight colleagues a leaderboard
   would turn a thank-you into a score. Sorting by count is available, and it
   is a choice the reader makes.
   -------------------------------------------------------------------------- */

.roll {
  list-style: none;
  margin: 0;
  padding: 0;
}

.roll-row {
  display: grid;
  grid-template-columns: 2.6rem 1fr auto;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--rope);
  color: inherit;
  text-decoration: none;
}
.roll-row:last-child { border-bottom: 1px solid var(--rope); }
.roll-row:hover { background: rgba(92, 184, 163, 0.06); }

/* The middle column of `.roll-row`. `min-width: 0` because an auto-sized grid
   track is at least as wide as its longest unbreakable word: without it a long
   name widens the row and pushes the pips off the right-hand edge. */
.roll-name {
  min-width: 0;
  font-family: var(--font-log);
  font-size: var(--step-0);
}
.roll-you {
  margin-left: 0.4rem;
  color: var(--brass);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.avatar {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--hull-2);
  border: 1px solid var(--rope-strong);
  object-fit: cover;
  display: grid;
  place-items: center;
  color: var(--fog);
  font-family: var(--font-log);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  overflow: hidden;
}
.avatar-lg {
  width: 4.6rem;
  height: 4.6rem;
  font-size: var(--step-1);
}

/* Sticker counts, as pips. A number appears only when a count needs it. */
.pips {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-log);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}
.pip {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  color: var(--fog);
}
.pip[data-zero="true"] { opacity: 0.32; }
.pip-emoji { font-size: 0.95rem; line-height: 1; }
.roll-total {
  min-width: 1.6rem;
  text-align: right;
  color: var(--brass);
  font-family: var(--font-log);
  font-variant-numeric: tabular-nums;
}

.sortbar {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
}

/* --------------------------------------------------------------------------
   Person page and the sticker exchange
   -------------------------------------------------------------------------- */

.person-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: center;
  margin-bottom: var(--gap);
}
/* The text beside the photo has to fold inside its column rather than run past
   the edge of the card. */
.person-head > :not(.avatar) { min-width: 0; }

.sticker-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sticker {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 0.15rem 0.6rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--rope);
}
.sticker:last-child { border-bottom: 1px solid var(--rope); }
.sticker-emoji { font-size: 1.3rem; line-height: 1.2; grid-row: span 2; }
.sticker-who {
  min-width: 0;
  font-family: var(--font-log);
  font-size: var(--step--1);
  color: var(--verdigris);
}
.sticker-day {
  color: var(--fog);
  font-family: var(--font-log);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sticker-note {
  grid-column: 2 / span 2;
  font-family: var(--font-hand);
  font-size: var(--step-0);
  line-height: 1.45;
}
.sticker-tools {
  grid-column: 2 / span 2;
  margin: 0.35rem 0 0;
}

.exchange { display: grid; gap: 0.7rem; }

.picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.4rem;
}

.chip {
  display: grid;
  /* Title, description, remaining count. The middle row takes the slack so the
     counts sit on one line across a row of chips whose descriptions differ in
     length. */
  grid-template-rows: auto 1fr auto;
  gap: 0.1rem;
  padding: 0.55rem 0.6rem;
  background: rgba(23, 50, 61, 0.5);
  border: 1px solid var(--rope);
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
}
.chip[aria-pressed="true"] {
  border-color: var(--verdigris);
  background: rgba(92, 184, 163, 0.12);
}
.chip:disabled { cursor: not-allowed; opacity: 0.45; }
.chip-top { display: flex; align-items: center; gap: 0.35rem; }
.chip-name {
  min-width: 0;
  font-family: var(--font-log);
  font-size: var(--step--1);
}
.chip-left {
  justify-self: end;
  margin-top: 0.15rem;
  color: var(--brass);
  font-family: var(--font-log);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.chip-what {
  color: var(--fog);
  font-size: 0.7rem;
  line-height: 1.3;
}

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.field { display: grid; gap: 0.3rem; margin-bottom: 0.7rem; }

.label {
  font-family: var(--font-log);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fog);
}

.hint {
  color: var(--fog);
  font-size: var(--step--1);
  line-height: 1.4;
}

.input, .textarea, .select {
  width: 100%;
  padding: 0.55rem 0.65rem;
  background: rgba(6, 17, 22, 0.65);
  border: 1px solid var(--rope-strong);
  border-radius: var(--radius);
  color: var(--chart);
}
.input, .select { font-family: var(--font-log); }
.textarea {
  font-family: var(--font-hand);
  font-size: var(--step-1);
  line-height: 1.5;
  min-height: 6.5rem;
  resize: vertical;
}
.input:focus, .textarea:focus, .select:focus { border-color: var(--verdigris); }

/* A sign-in code being typed. Wide tracking and upper case because it is being
   copied character by character off another screen, and a code you have to
   squint at gets typed wrong. */
.input-code {
  font-size: var(--step-1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.input-code::placeholder { letter-spacing: 0.14em; opacity: 0.4; }

/* --------------------------------------------------------------------------
   The sign-in code, as shown on your own page.
   -------------------------------------------------------------------------- */

.codebox {
  margin: 0 0 0.6rem;
  padding: 0.7rem 0.8rem;
  background: rgba(6, 17, 22, 0.7);
  border: 1px solid var(--rope-strong);
  border-radius: var(--radius);
  text-align: center;
}

/* Sized to fit three groups of four plus their tracking inside a card on a
   320px screen — the narrowest phone anyone is bringing — because a code that
   wraps mid-group is a code somebody types wrong. `user-select: all` makes one
   tap select the whole thing where the clipboard button is not available. */
.code-value {
  display: inline-block;
  color: var(--brass);
  font-family: var(--font-log);
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: 0.12em;
  /* Tracking is added after the last character too, which would sit the string
     half a space right of centre. */
  margin-right: -0.12em;
  user-select: all;
  -webkit-user-select: all;
}

.counter {
  color: var(--fog);
  font-family: var(--font-log);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.counter[data-over="true"] { color: var(--signal); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.6rem;
  padding: 0.5rem 1rem;
  background: transparent;
  border: 1px solid var(--rope-strong);
  border-radius: var(--radius);
  color: var(--chart);
  font-family: var(--font-log);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
}
.btn:hover:not(:disabled) { border-color: var(--verdigris); color: var(--verdigris); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary {
  background: var(--verdigris);
  border-color: var(--verdigris);
  color: var(--ink-2);
  font-weight: 600;
}
.btn-primary:hover:not(:disabled) { background: var(--chart); border-color: var(--chart); color: var(--ink-2); }

.btn-quiet { border-color: transparent; color: var(--fog); }
.btn-quiet:hover:not(:disabled) { color: var(--chart); border-color: var(--rope); }

.btn-danger { color: var(--signal); border-color: rgba(226, 84, 59, 0.4); }
.btn-danger:hover:not(:disabled) { background: rgba(226, 84, 59, 0.12); color: var(--signal); border-color: var(--signal); }

.btn-sm { min-height: 2rem; padding: 0.25rem 0.6rem; font-size: 0.68rem; }

.notice {
  margin: 0 0 var(--gap);
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--rope-strong);
  border-left-width: 2px;
  border-radius: var(--radius);
  font-size: var(--step--1);
}
.notice[data-kind="ok"] { border-left-color: var(--verdigris); background: rgba(92, 184, 163, 0.1); }
.notice[data-kind="error"] { border-left-color: var(--signal); background: rgba(226, 84, 59, 0.1); }
.notice[data-kind="info"] { border-left-color: var(--brass); background: rgba(201, 162, 39, 0.08); }

/* --------------------------------------------------------------------------
   The gate (sign-in)
   -------------------------------------------------------------------------- */

.gate {
  display: grid;
  align-content: center;
  min-height: 100dvh;
  padding: calc(2rem + var(--safe-t)) var(--pad) calc(2rem + var(--safe-b));
  max-width: 26rem;
  margin: 0 auto;
}
.gate-mark { font-size: 2.4rem; line-height: 1; }
.gate-title {
  margin: 0.6rem 0 0.2rem;
  font-size: var(--step-3);
  letter-spacing: -0.02em;
}
.gate-dates {
  color: var(--brass);
  font-family: var(--font-log);
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.gate-copy {
  margin: 1rem 0 1.2rem;
  color: var(--fog);
  font-family: var(--font-hand);
  font-size: var(--step-1);
  line-height: 1.5;
}
/* The code form under the email form. Separated by a rule so it reads as a
   second way in rather than as more of the first one. */
.gate-alt {
  margin-top: 1.3rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rope);
}

.gate-crew {
  margin-top: 1.6rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rope);
  color: var(--fog);
  font-family: var(--font-log);
  font-size: 0.7rem;
  line-height: 1.7;
}

/* --------------------------------------------------------------------------
   Admin
   -------------------------------------------------------------------------- */

.tablist {
  display: flex;
  gap: 0.3rem;
  margin-bottom: var(--gap);
  overflow-x: auto;
  scrollbar-width: none;
}
.tablist::-webkit-scrollbar { display: none; }

.tablist .btn { flex: 0 0 auto; }
.tablist .btn[aria-pressed="true"] {
  border-color: var(--verdigris);
  color: var(--verdigris);
}

.admin-day {
  margin-bottom: var(--gap);
  border: 1px solid var(--rope);
  border-radius: var(--radius);
  background: rgba(16, 38, 47, 0.5);
}
.admin-day > summary {
  padding: 0.7rem 0.8rem;
  cursor: pointer;
  font-family: var(--font-log);
  font-size: var(--step-0);
  list-style: none;
}
.admin-day > summary::-webkit-details-marker { display: none; }
.admin-day > summary::before { content: "▸ "; color: var(--verdigris); }
.admin-day[open] > summary::before { content: "▾ "; }
.admin-day-body { padding: 0 0.8rem 0.8rem; }

.blockrow {
  display: grid;
  grid-template-columns: 4.5rem 4.5rem 1fr;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px dashed var(--rope);
}
.blockrow .input { padding: 0.35rem 0.4rem; font-size: var(--step--1); }
.blockrow-wide { grid-column: 1 / -1; }
.blockrow-tools { grid-column: 1 / -1; display: flex; gap: 0.3rem; align-items: center; }

.kv {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.2rem 0.7rem;
  font-family: var(--font-log);
  font-size: var(--step--1);
}
.kv dt { color: var(--fog); }
.kv dd { margin: 0; min-width: 0; font-variant-numeric: tabular-nums; }

.linkbox {
  display: grid;
  gap: 0.35rem;
  margin-top: 0.5rem;
  padding: 0.5rem 0.6rem;
  background: rgba(6, 17, 22, 0.7);
  border: 1px solid var(--rope-strong);
  border-radius: var(--radius);
}
.linkbox code {
  font-family: var(--font-log);
  font-size: 0.7rem;
  word-break: break-all;
  color: var(--verdigris);
}

.feedback-item {
  padding: 0.7rem 0;
  border-top: 1px solid var(--rope);
  font-family: var(--font-hand);
  font-size: var(--step-1);
  line-height: 1.5;
  white-space: pre-line;
}
.feedback-item:last-child { border-bottom: 1px solid var(--rope); }
/* The note itself is `pre-line`, so its controls opt back out of that. */
.feedback-tools { margin-top: 0.45rem; white-space: normal; }
.feedback-day {
  display: block;
  margin-bottom: 0.2rem;
  color: var(--fog);
  font-family: var(--font-log);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.photo-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--rope);
}
.photo-row:last-of-type { border-bottom: 1px solid var(--rope); }
/* Middle column of `.photo-row`: an address with no break opportunities in it
   would otherwise widen the grid and push the buttons off the card. */
.photo-row > :not(.avatar) { min-width: 0; }
.photo-row-name { font-family: var(--font-log); font-size: var(--step--1); }
.photo-row-mail { color: var(--fog); font-size: 0.68rem; }

/* Hide the file input itself; its label is the control. */
.file-input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Wide screens: the tab bar becomes a rail, and the log gets room for notes.
   -------------------------------------------------------------------------- */

@media (min-width: 900px) {
  .shell { grid-template-columns: var(--rail) 1fr; }

  /* No rail to make room for: the read-only page is one column at every width. */
  .shell-bare { grid-template-columns: 1fr; }

  .tabbar { display: none; }

  .rail {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    position: sticky;
    top: 0;
    align-self: start;
    height: 100dvh;
    padding: calc(1.2rem + var(--safe-t)) 0.75rem 1.2rem;
    border-right: 1px solid var(--rope);
    background: rgba(6, 17, 22, 0.5);
  }

  .rail .masthead {
    position: static;
    display: block;
    padding: 0 0.25rem 1rem;
    background: none;
    backdrop-filter: none;
  }
  .rail .masthead-mark { display: block; font-size: 1.6rem; margin-bottom: 0.3rem; }
  .rail .masthead-where { margin: 0.2rem 0 0; display: block; }

  .rail .tab {
    flex-direction: row;
    justify-content: flex-start;
    gap: 0.6rem;
    min-height: 2.5rem;
    padding: 0.35rem 0.6rem;
    border-radius: var(--radius);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
  }
  .rail .tab[aria-current="page"] {
    background: rgba(92, 184, 163, 0.1);
    box-shadow: inset 2px 0 0 0 var(--verdigris);
  }
  .rail .tab .badge { position: static; transform: none; margin-left: auto; }
  .rail-spacer { flex: 1; }

  .main {
    padding: 1.6rem 2rem 3rem;
    padding-bottom: 3rem;
    max-width: calc(var(--measure) + 6rem);
    margin: 0;
  }

  .masthead-top { display: none; }

  /* Room to breathe once the rail is not competing with the title. */
  :root { --rail-time: 7.4rem; }
  .page-title { font-size: var(--step-3); }
  .watch { padding: 1rem 1.1rem 1.1rem; }
  .watch-title { font-size: var(--step-2); }
  /* Read across a desk, not off a phone in your hand. */
  .code-value { font-size: var(--step-2); }

  /* The rail has vertical room the top strip does not, so a long name wraps
     here instead of being clipped. */
  .rail .masthead-name {
    display: block;
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

@media (min-width: 1240px) {
  .main { max-width: calc(var(--measure) + 12rem); }
}

/* --------------------------------------------------------------------------
   Preferences and print
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .watch-dot { animation: none; }
}

@media print {
  body { background: #fff; color: #000; }
  .tabbar, .rail, .watch, .dayrail, .btn, .skip-link { display: none !important; }
  .main { padding: 0; max-width: none; }
  .log-row { border-color: #ccc; page-break-inside: avoid; }
  .log-notes, .prose, .wishes { color: #222; }
}
