/* LineUp — iOS-feeling PWA styles. Light + dark via prefers-color-scheme. */

/* ---------- colour schemes ----------
   A scheme only sets four values: the two accent hues for light and for
   dark. Everything else derives from them. Green stays green in every
   scheme — "free time" is semantic, not decorative. */

:root {
  --s-a: #ff4d6d; --s-b: #7a4dff;        /* sunset (default) */
  --s-a-d: #ff6b85; --s-b-d: #9b7bff;
}
:root[data-scheme="ocean"]  { --s-a: #0ea5e9; --s-b: #4f46e5; --s-a-d: #38bdf8; --s-b-d: #818cf8; }
:root[data-scheme="citrus"] { --s-a: #f59e0b; --s-b: #ef4444; --s-a-d: #fbbf24; --s-b-d: #f87171; }
:root[data-scheme="berry"]  { --s-a: #ec4899; --s-b: #8b5cf6; --s-a-d: #f472b6; --s-b-d: #a78bfa; }
:root[data-scheme="slate"]  { --s-a: #64748b; --s-b: #334155; --s-a-d: #94a3b8; --s-b-d: #64748b; }

/* ---------- structural tokens ----------
   Type and radius had drifted to 26 font sizes and 15 radii — including
   half-pixel steps — doing about nine jobs between them, because each screen
   got nudged on its own. These are the jobs. Reach for an existing step; add
   one only when a genuinely new role turns up, never to split a difference.
   Unlike the colours above, none of these change with theme or scheme. */
:root {
  --fs-3xs: 9.5px;    /* marks inside calendar cells and chips */
  --fs-2xs: 11px;     /* tab bar, pills, smallest meta */
  --fs-xs:  12px;     /* secondary meta, hints */
  --fs-sm:  13px;     /* dense body — statuses, field labels, small buttons */
  --fs-md:  14px;     /* body copy */
  --fs-lg:  15px;     /* card and row titles */
  --fs-input: 16px;   /* NEVER below 16px. iOS Safari zooms the whole page when
                         you focus an input with a smaller font, and it does
                         not zoom back out afterwards. */
  --fs-xl:  17px;     /* sheet and page titles */
  --fs-xl2: 18px;     /* the one oversized input */
  --fs-2xl: 19px;     /* screen headers */
  --fs-3xl: 22px;     /* hero figures */

  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-pill: 999px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  /* One curve for everything that moves, so the whole app shares a feel.
     A decelerating ease reads as responsive; anything springier starts to
     feel slow by the third tap, and this is an app people open daily. */
  --ease: cubic-bezier(0.2, 0.8, 0.25, 1);
  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 320ms;
}

:root {
  /* every surface carries a little of the scheme's hue, so switching schemes
     changes the whole app rather than a few buttons (plain values first as a
     fallback for browsers without color-mix) */
  --bg: #f2f2f7;
  --bg: color-mix(in srgb, var(--s-b) 7%, #f2f2f7);
  --card: #ffffff;
  --card: color-mix(in srgb, var(--s-b) 3%, #ffffff);
  --card2: #f7f7fa;
  --card2: color-mix(in srgb, var(--s-b) 7%, #f7f7fa);
  --text: #101013;
  --muted: #75757c;
  --line: rgba(0, 0, 0, 0.08);
  --line: color-mix(in srgb, var(--s-b) 14%, rgba(0, 0, 0, 0.08));
  --accent: var(--s-b);
  --accent-2: var(--s-a);
  --accent-soft: color-mix(in srgb, var(--s-b) 13%, transparent);
  --grad: linear-gradient(135deg, var(--s-a), var(--s-b));
  --danger: #e0442f;
  --good: #12c46a;
  --good-2: #06a75a;
  --good-grad: linear-gradient(150deg, #12c46a, #06a75a);
  --good-soft: rgba(18, 196, 106, 0.18);
  --good-soft-dot: rgba(18, 196, 106, 0.5);
  --sheet-shadow: 0 -8px 40px rgba(0, 0, 0, 0.18);
  --lift: 0 10px 22px -14px color-mix(in srgb, var(--s-b) 55%, transparent);
}

/* dark tokens, applied by system preference unless Light is forced… */
@media (prefers-color-scheme: dark) {
  :root:not([data-appearance="light"]) {
    --bg: #0b0b0f;
    --bg: color-mix(in srgb, var(--s-b-d) 10%, #0b0b0f);
    --card: #1b1b20;
    --card: color-mix(in srgb, var(--s-b-d) 9%, #1b1b20);
    --card2: #242429;
    --card2: color-mix(in srgb, var(--s-b-d) 12%, #242429);
    --text: #f2f2f6;
    --muted: #9a9aa2;
    --line: rgba(255, 255, 255, 0.1);
    --line: color-mix(in srgb, var(--s-b-d) 22%, rgba(255, 255, 255, 0.1));
    --accent: var(--s-b-d);
    --accent-2: var(--s-a-d);
    --accent-soft: color-mix(in srgb, var(--s-b-d) 20%, transparent);
    --grad: linear-gradient(135deg, var(--s-a-d), var(--s-b-d));
    --danger: #ff6a55;
    --good: #2ad97f;
    --good-2: #12c46a;
    --good-grad: linear-gradient(150deg, #2ad97f, #0fae5f);
    --good-soft: rgba(42, 217, 127, 0.2);
    --good-soft-dot: rgba(42, 217, 127, 0.5);
    --sheet-shadow: 0 -8px 40px rgba(0, 0, 0, 0.6);
    --lift: 0 10px 24px -14px rgba(0, 0, 0, 0.8);
  }
}

/* …and by explicit choice, which must win over the system in both directions */
:root[data-appearance="dark"] {
  --bg: #0b0b0f;
  --bg: color-mix(in srgb, var(--s-b-d) 10%, #0b0b0f);
  --card: #1b1b20;
  --card: color-mix(in srgb, var(--s-b-d) 9%, #1b1b20);
  --card2: #242429;
  --card2: color-mix(in srgb, var(--s-b-d) 12%, #242429);
  --text: #f2f2f6;
  --muted: #9a9aa2;
  --line: rgba(255, 255, 255, 0.1);
  --line: color-mix(in srgb, var(--s-b-d) 22%, rgba(255, 255, 255, 0.1));
  --accent: var(--s-b-d);
  --accent-2: var(--s-a-d);
  --accent-soft: color-mix(in srgb, var(--s-b-d) 20%, transparent);
  --grad: linear-gradient(135deg, var(--s-a-d), var(--s-b-d));
  --danger: #ff6a55;
  --good: #2ad97f;
  --good-2: #12c46a;
  --good-grad: linear-gradient(150deg, #2ad97f, #0fae5f);
  --good-soft: rgba(42, 217, 127, 0.2);
  --good-soft-dot: rgba(42, 217, 127, 0.5);
  --sheet-shadow: 0 -8px 40px rgba(0, 0, 0, 0.6);
  --lift: 0 10px 24px -14px rgba(0, 0, 0, 0.8);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, select { font: inherit; color: inherit; }

#app {
  display: flex; flex-direction: column;
  height: 100vh; height: 100dvh;
  position: relative;
}

/* scheme wash behind everything — the single biggest "the theme changed" cue */
#app::before {
  content: "";
  position: absolute; inset: 0 0 auto 0;
  height: 260px;
  background: radial-gradient(120% 100% at 50% 0%,
    color-mix(in srgb, var(--s-a) 30%, transparent) 0%,
    color-mix(in srgb, var(--s-b) 14%, transparent) 45%,
    transparent 100%);
  pointer-events: none;
  z-index: 0;
}
#view, .tabbar { position: relative; z-index: 1; }

#view {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: calc(env(safe-area-inset-top) + 14px) 14px 24px;
  max-width: 560px;
  width: 100%;
  margin: 0 auto;
}

/* ---------- tab bar ---------- */

.tabbar {
  display: flex;
  border-top: 0.5px solid var(--line);
  background: var(--card);
  background: color-mix(in srgb, var(--card) 82%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  padding-bottom: env(safe-area-inset-bottom);
}

.tabbar button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 0 6px;
  font-size: var(--fs-2xs);
  color: var(--muted);
}

.tabbar button.active { color: var(--accent-2); }
.tabbar button { transition: transform var(--dur-fast) var(--ease); position: relative; }
.tabbar button:active { transform: scale(0.92); }
.tab-ico { width: 22px; height: 22px; display: block; }

/* Something in Groups is waiting on an answer. Plans stopped living on the
   Friends tab, so the tab bar has to carry the news. */
.tabbar button.has-badge .tab-ico::after { content: none; }
.tabbar button.has-badge::after {
  content: ""; position: absolute; top: 6px; left: 50%; margin-left: 7px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--danger); box-shadow: 0 0 0 2px var(--card);
}

/* the install-first steps on the very first screen (iOS Safari only) */
.install-steps {
  margin: 14px 0 0; padding-left: 22px;
  display: flex; flex-direction: column; gap: 9px;
  font-size: var(--fs-md); line-height: 1.45; color: var(--text);
}
.install-steps li::marker { color: var(--accent); font-weight: 800; }

/* a fixed value where a field would otherwise be — the "With Jim" on a 1:1
   plan isn't a choice, it's decided by whose calendar you came from */
.input-static {
  display: flex; align-items: center;
  color: var(--muted); background: var(--card2);
}

/* ---------- groups tab ---------- */

.group-head { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
.group-head-title { flex: 1; font-size: var(--fs-2xl); font-weight: 750; letter-spacing: -0.02em; text-align: center; }
.group-who { font-size: var(--fs-xs); color: var(--muted); margin: -4px 0 12px; text-align: center; }

.group-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; margin-bottom: 9px; }
.group-row-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; text-align: left; }
.group-row-title { font-size: var(--fs-lg); font-weight: 700; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.group-row-sub { font-size: var(--fs-xs); color: var(--muted); }
.group-row-next { font-size: var(--fs-xs); font-weight: 600; color: var(--good); margin-top: 2px; }
.group-row-next.muted { color: var(--muted); font-weight: 500; }
.needs-answer {
  font-size: var(--fs-3xs); font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
  color: #fff; background: var(--danger); border-radius: 999px; padding: 2px 7px;
}

/* ---------- calendar ---------- */

.cal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.cal-title { font-size: var(--fs-2xl); font-weight: 700; padding: 6px 10px; border-radius: var(--r-sm); }
.cal-title:active { background: var(--accent-soft); }

.icon-btn {
  width: 40px; height: 40px;
  border-radius: var(--r-md);
  font-size: 24px;
  color: var(--accent);
  display: grid; place-items: center;
}
.icon-btn:active { background: var(--accent-soft); }

.cal-weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr);
  text-align: center; font-size: var(--fs-2xs); font-weight: 600; color: var(--muted);
  margin-bottom: 4px;
}

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }

.cal-cell {
  position: relative;
  aspect-ratio: 1 / 1.08;
  border-radius: var(--r-md);
  background: var(--card);
  border: 0.5px solid var(--line);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 2px; padding-top: 5px;
  min-width: 0;
  transition: transform var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease);
}
.cal-cell:active { transform: scale(0.94); filter: brightness(0.95); }
.cal-cell.dim { opacity: 0.32; }
/* Today.
   This used to be a ring in var(--accent-2) and nothing else — which is the
   scheme's own hue, drawn around a cell filled with a SHIFT colour the user
   picked. On the default sunset scheme that's a #ff4d6d ring around a pink
   work day: the marker and the fill were nearly the same colour, so on any
   day you were rostered it effectively vanished. Reported as "there's nothing
   showing what day it is".
   The date number now carries it instead: a filled pill in --text, which
   contrasts with every possible fill because it isn't derived from the theme
   accent at all. Inside the cell, so it can't crowd its neighbours through
   the 4px grid gap the way a thicker ring would. */
.cal-cell.today { box-shadow: 0 0 0 2px var(--accent-2); border-color: transparent; }
/* The extra selectors are not decoration — they are the whole point.
   `.cal-cell.tinted .cal-daynum` and `.ov-cell.ov-off .cal-daynum` both force
   color:#fff and both appear LATER in this file, so a plain
   `.cal-cell.today .cal-daynum` ties on specificity and loses. That put white
   text on a near-white pill: 1.12:1, i.e. invisible, on exactly the tinted
   work days this fix exists for. Caught by measuring the contrast rather than
   looking at it. */
.cal-cell.today .cal-daynum,
.cal-cell.tinted.today .cal-daynum,
.ov-cell.ov-off.today .cal-daynum {
  background: var(--text);
  color: var(--bg);
  border-radius: var(--r-pill);
  padding: 1px 6px;
  min-width: 20px;
  text-align: center;
}
.cal-daynum { font-size: var(--fs-xs); font-weight: 700; }

/* work days wear their shift's colour; --c is set per cell */
.cal-cell.tinted {
  background: linear-gradient(155deg, var(--c), color-mix(in srgb, var(--c) 72%, #000));
  border-color: transparent;
  color: #fff;
  box-shadow: 0 4px 12px -8px var(--c);
}
.cal-cell.tinted .cal-daynum { color: #fff; }
.cal-cell.tinted .chip { background: rgba(255, 255, 255, 0.22) !important; color: #fff; }

.chip {
  font-size: var(--fs-3xs); font-weight: 800; color: #fff;
  border-radius: var(--r-xs); padding: 1px 6px;
  letter-spacing: -0.2px;
  max-width: 92%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.off-mark { font-size: var(--fs-3xs); color: var(--muted); }

.chip-custom { background: var(--accent); font-size: var(--fs-3xs); letter-spacing: -0.3px; padding: 2px 5px; }

.custom-hours { display: flex; flex-direction: column; gap: 8px; }
.custom-block-row { display: flex; align-items: center; gap: 8px; }
.custom-block-row .input-time { flex: 1; }
.custom-actions { display: flex; gap: 8px; margin-top: 4px; }
.custom-actions .btn { flex: 1; }

.week-entry-row { margin-bottom: 9px; display: flex; flex-direction: column; gap: 9px; }
.week-entry-head { display: flex; justify-content: space-between; align-items: center; }
.week-entry-date { font-weight: 700; font-size: var(--fs-md); }

.ovr-dot {
  position: absolute; top: 4px; right: 5px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
}

.cal-legend {
  display: flex; flex-wrap: wrap; gap: 10px 14px;
  margin-top: 12px; font-size: var(--fs-xs); color: var(--muted);
  align-items: center;
}
.legend-item { display: inline-flex; align-items: center; gap: 5px; }
.dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex: none; }
.dot-off { background: var(--card2); border: 1px solid var(--line); }

.cal-tools { display: flex; gap: 8px; margin-top: 14px; }

/* paint mode */
.paint-bar {
  display: none;
  flex-wrap: wrap; gap: 6px; align-items: center;
  margin-top: 10px; padding: 10px; border-radius: var(--r-md);
  background: var(--card); border: 0.5px solid var(--line);
}
.paint-bar.show { display: flex; }
.paint-label { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }

.brush {
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card2);
  font-size: var(--fs-sm); font-weight: 600;
}
.brush { transition: transform var(--dur-fast) var(--ease); }
.brush:active { transform: scale(0.94); }
.brush.active { background: var(--grad); border-color: transparent; color: #fff; }
.brush.brush-off.active { background: var(--muted); border-color: var(--muted); }

/* ---------- overlap ---------- */

.friend-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 14px; }

.friend-chip {
  padding: 7px 14px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card);
  font-size: var(--fs-sm); font-weight: 600; color: var(--muted);
  display: inline-flex; align-items: center; gap: 6px;
}

/* per-day friend dots retired in favour of .ov-count — colours still carry
   identity on the chips and in the day sheet, where there's room to read them */
.friend-chip { transition: transform var(--dur-fast) var(--ease); }
.friend-chip:active { transform: scale(0.94); }
.friend-chip.active { border-color: transparent; color: #fff; font-weight: 700; }
.friend-chip.add { color: var(--accent); font-size: var(--fs-xl); padding: 5px 13px; font-weight: 700; }

.ov-cell { justify-content: center; gap: 2px; padding-top: 0; }
.ov-cell.ov-off {
  background: var(--good-grad);
  border-color: transparent;
  box-shadow: 0 4px 12px -8px var(--good);
}
.ov-cell.ov-off .cal-daynum, .ov-cell.ov-off .ov-label { color: #fff; }
.ov-cell.ov-partial { background: color-mix(in srgb, var(--good) 20%, var(--card)); border-color: transparent; }
.ov-cell.ov-partial .ov-label { color: color-mix(in srgb, var(--good) 62%, var(--text)); }
.ov-label { font-size: var(--fs-3xs); font-weight: 800; color: var(--good); letter-spacing: -0.2px; }

/* How many of us are off, in place of one dot per person. Both the number
   and the fill sit above .ov-fill, hence the explicit z-index on each. */
.ov-count {
  position: relative; z-index: 1;
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: -0.3px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.ov-cell .cal-daynum { position: relative; z-index: 1; }
.ov-cell.ov-partial .ov-count { color: color-mix(in srgb, var(--good) 62%, var(--text)); }
.ov-cell.ov-off .ov-count { color: #fff; }

/* Fill height = share of people off, so a 5-of-6 near-miss has a shape.
   Never drawn on an all-off cell — that one is already solid green. */
.ov-fill {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 0;
  background: color-mix(in srgb, var(--good) 30%, transparent);
  border-radius: 0 0 12px 12px;
  pointer-events: none;
}

/* Someone flagged something important on a day you're rostered on. Used by
   BOTH grids — the overlap view and your own month — hence .cal-cell.
   Drawn as a ring on ::after rather than a box-shadow, so it composes with
   .today's outer ring instead of overwriting it. */
.cal-cell.ov-clash::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  border: 2px solid var(--danger); border-radius: var(--r-md);
  pointer-events: none;
}
/* not colour alone — the mark carries it for anyone who can't see the ring */
.ov-clash-mark {
  position: absolute; top: 2px; right: 5px; z-index: 3;
  font-size: var(--fs-2xs); font-weight: 900; line-height: 1; color: var(--danger);
}
/* "Something's on this day" — one solid dot per plan, on BOTH grids. An
   outlined glyph turned to mush at cell size, worst of all on the green
   fill where it was violet on green. The ring is the cell's own background,
   so the dot separates from whatever sits behind it. */
.plan-mark {
  position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%);
  z-index: 3; display: flex; gap: 3px; pointer-events: none;
}
/* the dots need the bottom of the cell to themselves — nudge the centred
   day number and count up so a 7px dot can't sit on the digits */
.cal-cell:has(.plan-mark) { padding-bottom: 9px; }
.plan-mark i {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--accent);
  box-shadow: 0 0 0 1.5px var(--card);
}
.ov-cell.ov-partial .plan-mark i { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--good) 20%, var(--card)); }
/* on solid colour the dot goes white and the ring goes dark */
.cal-cell.tinted .plan-mark i,
.ov-cell.ov-off .plan-mark i { background: #fff; box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.16); }

/* important plans in the lists */
.important-tag {
  display: inline-block; margin-right: 5px;
  min-width: 14px; height: 14px; border-radius: var(--r-xs);
  background: var(--danger); color: #fff;
  font-size: var(--fs-2xs); font-weight: 900; line-height: 14px; text-align: center;
}
.plan-row.plan-important { border-left: 3px solid var(--danger); }

/* Answered plans: a line, not a card. No shadow, no fill — the loud version
   is reserved for plans still waiting on an answer. */
.plan-quiet {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 7px 0 7px 10px; margin-bottom: 2px;
  border-left: 2px solid color-mix(in srgb, var(--good) 55%, transparent);
}
.plan-quiet.plan-important { border-left-color: var(--danger); }
.plan-quiet-main { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.plan-quiet-title { font-size: var(--fs-sm); font-weight: 650; }
.plan-quiet-meta { font-size: var(--fs-xs); color: var(--muted); }
.rsvp-pill {
  flex: none; font-size: var(--fs-2xs); font-weight: 700; padding: 4px 10px;
  border-radius: 999px; border: 0.5px solid var(--line); background: var(--card);
}
.rsvp-pill.is-in { color: var(--good); }
.rsvp-pill.is-out { color: var(--muted); }
.plans-later { margin-top: 18px; opacity: 0.9; }

/* ---------- shared-day hero ---------- */

.hero {
  display: block; width: 100%; text-align: left;
  border: 0; border-radius: var(--r-lg);
  padding: 15px 17px;
  margin-bottom: 14px;
  background: var(--grad);
  color: #fff;
  box-shadow: var(--lift);
  transition: transform var(--dur-fast) var(--ease);
}
.hero:active { transform: scale(0.985); }
.hero-off { background: var(--good-grad); box-shadow: 0 10px 24px -14px var(--good); }
.hero-none { background: var(--card); border: 0.5px solid var(--line); color: var(--muted); box-shadow: none; }
.hero-k {
  font-size: var(--fs-3xs); font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; opacity: 0.9;
}
.hero-big { font-size: var(--fs-3xl); font-weight: 850; letter-spacing: -0.035em; margin-top: 3px; }
.hero-sub { font-size: var(--fs-xs); margin-top: 4px; opacity: 0.92; line-height: 1.35; }
.hero-none .hero-big { color: var(--text); }

.upcoming { margin-top: 18px; }
.upcoming-row { display: flex; justify-content: space-between; align-items: center; width: 100%; }
.upcoming-date { font-weight: 600; font-size: var(--fs-md); }
.upcoming-kind { font-size: var(--fs-sm); font-weight: 600; }
.k-off { color: var(--good); }
.k-partial { color: var(--good); opacity: 0.85; }

.invite-code {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: var(--fs-3xl); font-weight: 700; letter-spacing: 2px;
  text-align: center; padding: 14px;
  background: var(--card2); border: 1px dashed var(--line); border-radius: var(--r-md);
  user-select: all; -webkit-user-select: all;
  margin-bottom: 4px;
}

.manage-row {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 10px 2px; border-bottom: 0.5px solid var(--line);
}

.detail-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 2px; border-bottom: 0.5px solid var(--line);
}
.detail-name { font-weight: 600; }
.detail-status { font-size: var(--fs-sm); color: var(--muted); }
.detail-status.s-off { color: var(--good); font-weight: 600; }
.verdict { margin-top: 12px; font-weight: 600; }

/* ---------- cards / lists ---------- */

.card {
  background: var(--card);
  border: 0.5px solid var(--line);
  border-radius: var(--r-lg);
  padding: 14px;
  width: 100%;
  text-align: left;
}
button.card { transition: transform var(--dur-fast) var(--ease); }
button.card:active { transform: scale(0.985); }
.card-list { display: flex; flex-direction: column; gap: 9px; margin: 12px 0; }

.mode-card:active { background: var(--card2); }
.mode-card.mode-current { border-color: var(--accent); }
.current-pill {
  display: inline-block; margin-left: 8px; padding: 2px 8px;
  border-radius: 999px; background: var(--accent-soft); color: var(--accent);
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  vertical-align: middle;
}
.mode-title { font-weight: 700; font-size: var(--fs-lg); margin-bottom: 3px; }
.mode-sub { font-size: var(--fs-sm); color: var(--muted); line-height: 1.35; }
.disabled-card { opacity: 0.55; }

.info-card { margin-bottom: 10px; }
.info-title { font-weight: 700; font-size: var(--fs-lg); margin-bottom: 4px; }
.info-sub { font-size: var(--fs-sm); color: var(--muted); line-height: 1.45; }

/* ---------- buttons / inputs ---------- */

.btn {
  border-radius: var(--r-lg);
  padding: 13px 18px;
  font-weight: 750;
  font-size: var(--fs-lg);
  text-align: center;
  transition: transform var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease);
}
.btn:active { filter: brightness(0.94); transform: scale(0.97); }
.btn-primary { background: var(--grad); color: #fff; box-shadow: var(--lift); }
.btn-ghost { background: var(--card); border: 0.5px solid var(--line); color: var(--accent); }
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger-ghost { background: var(--card); border: 0.5px solid var(--line); color: var(--danger); }
.btn-block { display: block; width: 100%; margin-top: 9px; }
.btn-small { padding: 9px 14px; font-size: var(--fs-sm); border-radius: var(--r-sm); }
.btn-tiny { padding: 5px 10px; font-size: var(--fs-xs); border-radius: var(--r-sm); }

.input {
  width: 100%;
  background: var(--card);
  border: 0.5px solid var(--line);
  border-radius: var(--r-md);
  padding: 13px 14px;
  font-size: var(--fs-input); /* prevents iOS zoom-on-focus */
  outline: none;
}
.input:focus { border-color: var(--accent); }
.input-big { font-size: var(--fs-xl2); padding: 15px 16px; }
.input-time { width: auto; }

.field-label { display: block; font-size: var(--fs-sm); color: var(--muted); font-weight: 600; margin: 0 0 6px 2px; }

.input-code {
  font-size: 30px; font-weight: 750; text-align: center;
  letter-spacing: 0.34em; text-indent: 0.34em;
  font-variant-numeric: tabular-nums;
  padding: 16px 14px;
}
/* the field is huge so the digits read at a glance; the hint inside it must
   not be, or it overflows the box on a narrow phone */
.input-code::placeholder {
  font-size: var(--fs-md); font-weight: 500; letter-spacing: 0; text-indent: 0;
}

/* ---------- onboarding / editor pages ---------- */

.page-modal {
  position: fixed; inset: 0; z-index: 40;
  background: var(--bg);
  display: flex; flex-direction: column;
  animation: pageIn var(--dur-slow) var(--ease);
}
@keyframes pageIn { from { transform: translateY(28px); opacity: 0; } to { transform: none; opacity: 1; } }

.page-header {
  display: flex; align-items: center; gap: 6px;
  padding: calc(env(safe-area-inset-top) + 10px) 12px 10px;
}
.page-title { font-size: var(--fs-xl); font-weight: 700; }
.page-close { font-size: var(--fs-input); color: var(--muted); }

.page-body {
  flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 8px 18px calc(env(safe-area-inset-bottom) + 28px);
  max-width: 560px; width: 100%; margin: 0 auto;
}

.step-heading { font-size: var(--fs-3xl); font-weight: 800; margin: 14px 0 6px; letter-spacing: -0.3px; }
.step-heading-sm { font-size: var(--fs-lg); font-weight: 700; margin: 18px 0 6px; }
.step-sub { font-size: var(--fs-md); color: var(--muted); line-height: 1.45; margin-bottom: 14px; }
.step-actions { margin-top: 22px; }
.center { text-align: center; }

.welcome-hero { text-align: center; padding: 26px 0 6px; }
.welcome-logo { font-size: 52px; }
.welcome-title { font-size: 34px; font-weight: 800; letter-spacing: -0.5px; margin: 6px 0 8px; }

.page-h1 { font-size: 28px; font-weight: 800; letter-spacing: -0.4px; margin: 4px 0 16px; }

/* shift rows */
.shift-row { display: flex; align-items: center; gap: 10px; }
.shift-row-name { font-weight: 700; flex: 1; }
.shift-row-time { color: var(--muted); font-size: var(--fs-sm); }
.shift-row-edit { color: var(--accent); font-size: var(--fs-sm); font-weight: 600; }

.shift-edit { display: flex; flex-direction: column; gap: 11px; }
.time-row { display: flex; gap: 12px; }
.time-row label { display: flex; flex-direction: column; gap: 5px; font-size: var(--fs-xs); color: var(--muted); font-weight: 600; flex: 1; }
.row-actions { display: flex; gap: 8px; }

.swatches { display: flex; gap: 9px; }
.swatch { width: 30px; height: 30px; border-radius: 50%; border: 2.5px solid transparent; }
.swatch.active { border-color: var(--text); }

/* rotation builder */
.token-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.token-build { min-height: 42px; padding: 8px; border-radius: var(--r-md); background: var(--card); border: 0.5px dashed var(--line); align-items: center; }

.token {
  min-width: 36px; height: 36px; padding: 0 8px;
  border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--card2);
  font-weight: 700; font-size: var(--fs-sm);
  display: inline-flex; align-items: center; justify-content: center; gap: 2px;
}
.token small { font-size: var(--fs-3xs); font-weight: 600; opacity: 0.75; }
.token-pick { flex-direction: column; height: 46px; gap: 0; }
.token-today { outline: 2.5px solid var(--accent); outline-offset: 1px; }

.brush-row { display: flex; flex-wrap: wrap; gap: 7px; margin: 10px 0; }
.preset-row { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; margin: 6px 0 2px; }

.preview-row { display: flex; gap: 4px; overflow-x: auto; padding: 6px 0; }
.preview-day { display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 30px; }
.preview-day small { font-size: var(--fs-2xs); color: var(--muted); }
.preview-chip {
  width: 26px; height: 26px; border-radius: var(--r-sm);
  background: var(--card2); border: 0.5px solid var(--line);
  color: #fff; font-size: var(--fs-2xs); font-weight: 700;
  display: grid; place-items: center;
}

.week-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px; }
.week-name { font-weight: 600; font-size: var(--fs-md); }
.select-day { width: 58%; padding: 9px 10px; border-radius: var(--r-sm); background: var(--card2); border: 0.5px solid var(--line); }

/* ---------- toggles / notifications ---------- */

.switch { position: relative; display: inline-block; width: 46px; height: 28px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch .slider {
  position: absolute; inset: 0;
  background: var(--card2);
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: background var(--dur), border-color var(--dur);
}
.switch .slider::before {
  content: ""; position: absolute;
  width: 22px; height: 22px; left: 2px; top: 2px;
  background: #fff; border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28);
  transition: transform var(--dur);
}
.switch input:checked + .slider { background: var(--good); border-color: var(--good); }
.switch input:checked + .slider::before { transform: translateX(18px); }

.notify-kind-row {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 9px 0;
}
.notify-kind-row + .notify-kind-row { border-top: 0.5px solid var(--line); }
.notify-kind-label { font-weight: 600; font-size: var(--fs-md); }
.notify-kind-desc { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; line-height: 1.35; }
.notify-friend-name { font-weight: 700; font-size: var(--fs-lg); margin-bottom: 4px; }

/* ---------- groups & plans ---------- */

.group-chip { font-weight: 700; }
.group-chip.active { background: var(--grad); border-color: transparent; color: #fff; }
.group-glyph { font-size: var(--fs-sm); line-height: 1; }
.chip-empty { opacity: 0.5; }
.chip-badge {
  font-size: var(--fs-2xs); font-weight: 700; opacity: 0.8;
  margin-left: 5px; font-variant-numeric: tabular-nums;
}
.partial-note { margin: -6px 2px 12px; }

.plans { margin-bottom: 14px; }
.plan-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.plan-main { min-width: 0; }
.plan-title { font-weight: 700; font-size: var(--fs-md); }
.plan-meta { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
.plan-actions { display: flex; gap: 5px; flex: none; }

.rsvp-line {
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  margin-top: 5px; font-size: var(--fs-xs); font-weight: 600;
}
.rsvp-in { color: var(--good); }
.rsvp-out { color: var(--danger); opacity: 0.85; }
.rsvp-quiet { color: var(--muted); }
.day-plans { margin-top: 14px; }
/* same dot as the grid, so the row and the cell that led you here match */
.plan-dot-inline {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); margin-right: 7px; vertical-align: middle;
}

/* ---------- scheme picker ---------- */

.scheme-row { display: flex; gap: 11px; flex-wrap: wrap; }
.scheme-dot {
  width: 40px; height: 40px; border-radius: 50%;
  border: 2.5px solid transparent;
  box-shadow: 0 3px 10px -6px rgba(0, 0, 0, 0.6);
  transition: transform var(--dur-fast) var(--ease);
}
.scheme-dot:active { transform: scale(0.9); }
.scheme-dot.active {
  border-color: var(--text);
  transform: scale(1.06);
}

.seg-row {
  display: flex; gap: 3px; padding: 3px;
  background: var(--card2); border: 0.5px solid var(--line);
  border-radius: 999px;
}
.seg-btn {
  flex: 1; padding: 9px 0; border-radius: 999px;
  font-size: var(--fs-sm); font-weight: 650; color: var(--muted);
  transition: transform var(--dur-fast) var(--ease);
}
.seg-btn:active { transform: scale(0.96); }
.seg-btn.active { background: var(--grad); color: #fff; }

/* ---------- settings ---------- */

.settings-section { margin-bottom: 24px; }
.section-title { font-size: var(--fs-sm); font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; margin: 0 0 8px 2px; }
.about { text-align: center; color: var(--muted); font-size: var(--fs-xs); margin-top: 30px; }

/* ---------- sheet ---------- */

.sheet-backdrop {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(0, 0, 0, 0.35);
  opacity: 0; transition: opacity var(--dur);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet-backdrop.show { opacity: 1; }

.sheet {
  width: 100%; max-width: 560px;
  background: var(--card);
  border-radius: var(--r-xl) 20px 0 0;
  box-shadow: var(--sheet-shadow);
  padding: 8px 18px calc(env(safe-area-inset-bottom) + 20px);
  transform: translateY(100%);
  transition: transform var(--dur-slow) var(--ease);
  max-height: 82vh; max-height: 82dvh; overflow-y: auto;
}
.sheet-backdrop.show .sheet { transform: none; }

.sheet-handle { width: 38px; height: 4.5px; border-radius: var(--r-xs); background: var(--line); margin: 4px auto 12px; }
.sheet-title { font-size: var(--fs-xl); font-weight: 700; margin-bottom: 10px; }
.sheet-message { font-size: var(--fs-md); color: var(--muted); line-height: 1.45; margin-bottom: 12px; }
.sheet-actions { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
body.sheet-open { overflow: hidden; }

.shift-pick { display: flex; flex-direction: column; gap: 8px; }
.shift-pick-btn {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px; border-radius: var(--r-md);
  background: var(--card2); border: 1px solid var(--line);
  font-weight: 600; font-size: var(--fs-lg);
}
.shift-pick-btn.current { border-color: var(--accent); background: var(--accent-soft); }

/* ---------- misc ---------- */

.empty-state { text-align: center; padding: 60px 20px; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.empty-icon { font-size: 46px; margin-bottom: 6px; }

.hint { font-size: var(--fs-xs); color: var(--muted); }

.toast {
  position: fixed; left: 50%; transform: translateX(-50%) translateY(16px);
  bottom: calc(env(safe-area-inset-bottom) + 74px);
  background: var(--text); color: var(--bg);
  padding: 11px 18px; border-radius: 999px;
  font-size: var(--fs-sm); font-weight: 600;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur), transform var(--dur);
  z-index: 60; max-width: 86vw; text-align: center;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- the good news should feel like good news ----------
   Everyone being off is the whole point of the app, and it was announced in
   exactly the same voice as "no usable shared free time". The green fill is
   settled and deliberately untouched — this adds one sweep of light as the
   card appears, and then stops.
   It does NOT loop on purpose: a permanent animation on the first thing you
   see every morning stops reading as celebration and starts reading as a
   notification you can't dismiss. */
.hero { position: relative; overflow: hidden; }
.hero-off::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(105deg,
    transparent 35%, rgba(255, 255, 255, 0.28) 50%, transparent 65%);
  transform: translateX(-120%);
  animation: sheen 1100ms var(--ease) 250ms 1;
  pointer-events: none;
}
@keyframes sheen { to { transform: translateX(120%); } }

/* ---------- focus, for people who don't tap ----------
   Every bit of interaction feedback in this file is :active, which never
   fires for keyboard or switch-control users — so they had no indication of
   where they were at all. :focus-visible keeps it invisible for touch. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* ---------- respect the OS motion setting ----------
   Every animation here is decoration over a resting state that is already
   correct, so honouring this costs nothing and vestibular disorders are not
   rare. Must come last to win on specificity ties. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- empty states ----------
   These are the barest screens in the app and the FIRST thing a new tester
   sees, before there is any data to look at. The writing was already fine;
   they just weren't designed. A bare emoji on a flat background reads as a
   missing image rather than an intentional state. */
.empty-state {
  padding: 52px var(--space-5) var(--space-5);
  gap: var(--space-2);
  animation: emptyIn var(--dur-slow) var(--ease) both;
}
.empty-state .step-sub {
  max-width: 34ch;      /* measured, not guessed — past ~40ch centred text
                           becomes noticeably harder to scan back through */
  margin-inline: auto;
}
.empty-state .btn { margin-top: var(--space-3); min-width: 210px; }

.empty-icon {
  font-size: 38px;
  width: 92px; height: 92px;
  display: grid; place-items: center;
  margin-bottom: var(--space-2);
  border-radius: var(--r-pill);
  background: radial-gradient(circle at 50% 45%,
    color-mix(in srgb, var(--accent) 20%, transparent),
    color-mix(in srgb, var(--accent) 5%, transparent) 70%);
}
@keyframes emptyIn { from { opacity: 0; transform: translateY(10px); } }

/* ---------- cards ----------
   A 0.5px hairline was doing all the work of separating a card from the page,
   which on a phone in daylight is very nearly nothing. Tinted with the
   accent so it survives dark mode, where a black shadow is invisible. */
.card {
  box-shadow: 0 2px 12px -8px color-mix(in srgb, var(--accent) 45%, transparent);
}

/* ---------- everyone said yes ----------
   The outcome the entire app exists to produce, previously rendered as a
   roster you had to read and compare against the member list yourself. */
.rsvp-all-in {
  color: var(--good-2);
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* ---------- arriving on a tab ----------
   This was a per-child stagger, 26ms apart, each row rising 8px. Reported as
   feeling BUGGY, and the report is right: rows appearing in sequence is the
   visual grammar of content still loading. On a tab whose data is already in
   memory, that reads as the app struggling rather than responding — and the
   more content a tab has, the worse it looked, which is backwards.

   One fade on the whole view instead. No stagger, no movement: nothing
   arrives after anything else, so there is nothing to mistake for loading.
   Short enough to soften the cut without ever being waited on.

   If this still reads as anything at all, delete these three rules — a hard
   cut is a perfectly good answer and the app shipped that way for weeks. */
#view.tab-in { animation: tabIn var(--dur-fast) var(--ease) both; }
@keyframes tabIn { from { opacity: 0; } }

/* The toast is the app's main speaking voice and it arrived by sliding
   flatly upward. A little scale on entry makes it read as arriving rather
   than as a div appearing. */
.toast { transform: translateX(-50%) translateY(16px) scale(0.96); }
.toast.show { transform: translateX(-50%) translateY(0) scale(1); }

/* ---------- a plan row you can open ----------
   These are <button>s now, not divs, so they have to be told to fill the
   width and align left — the global button reset clears font and colour but
   not layout. The chevron is the only thing distinguishing them from the
   person rows directly above, which are NOT tappable, so it earns its space. */
.detail-row-tap {
  width: 100%;
  text-align: left;
  gap: 8px;
  border-radius: var(--r-xs);
  transition: background var(--dur-fast) var(--ease);
}
.detail-row-tap:active { background: var(--accent-soft); }
.row-chev { color: var(--muted); font-size: var(--fs-lg); line-height: 1; flex: 0 0 auto; }
.detail-row-tap .detail-status { text-align: right; }
