:root {
  --bg: #F3F6F5; --surface: #FFFFFF; --ink: #10292C; --muted: #56706F;
  --line: #DDE6E4; --line-soft: #EDF2F1; --card-line: #D5E0DE;
  --brand: #0B7F8C; --brand-dark: #086570; --brand-soft: #E0F3F5; --on-brand-soft: #D6F1F4;
  --orange: #C4541A; --orange-ink: #A8440F; --orange-soft: #FDEBDD; --orange-line: #E9A77C;
  --scrim: rgba(16, 41, 44, .55);
  --band: #E8EEED; /* the roll call's "Raramente vêm" group */
  --display: 'Bricolage Grotesque', Figtree, system-ui, sans-serif;
}
/* Type scale: the Calendário's sizes, used on every screen. A font-size is always one
   of these tokens; a size that fits none is a new token, not a raw px. The only raw
   sizes left are emoji and the demo strip. */
:root {
  --fs-title: 30px;  /* page title: h1.display, event and aula headers */
  --fs-h2: 26px;     /* h2.display, day numbers, the big counts */
  --fs-h3: 22px;     /* a card's headline: next class, empty state */
  --fs-body: 16px;   /* names, lessons, rows, inputs: the default */
  --fs-sec: 14px;    /* the second line: teams, dates, notes, .small */
  --fs-label: 13px;  /* section labels (eyebrow, month, A–Z letters), status lines */
  --fs-pill: 12px;   /* pills, tags, badges, the tab bar */
  --fs-btn: 17px;    /* big buttons */
  --fs-btn-sm: 15px; /* soft and inline buttons */
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: Figtree, system-ui, sans-serif; font-size: var(--fs-body); background: var(--bg); color: var(--ink);
  display: flex; flex-direction: column; height: 100dvh; overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}
button { font: inherit; color: inherit; }
a { color: var(--brand); }
#view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.display { font-family: var(--display); font-weight: 800; margin: 0; line-height: 1.05; }
h1.display { font-size: var(--fs-title); }
h2.display { font-size: var(--fs-h2); }
.muted { color: var(--muted); }
.small { font-size: var(--fs-sec); }
.eyebrow { font-size: var(--fs-label); font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin: 0; }
.loading { padding: 24px; color: var(--muted); }

/* Header */
.top { flex-shrink: 0; background: var(--surface); border-bottom: 1px solid var(--line);
  padding: calc(18px + env(safe-area-inset-top)) 16px 14px; display: flex; flex-direction: column; gap: 12px; }
.top-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.top h1.display { font-size: var(--fs-title); }
.top .back { min-height: 44px; font-size: var(--fs-body); }
/* Presenças: one row (date · service, search, ⋯); the header is short enough not to collapse. */
.top.roll { position: relative; padding-top: calc(10px + env(safe-area-inset-top)); padding-bottom: 10px; gap: 8px; }
.top.roll .top-row { min-height: 44px; }
.top.roll h1.display { font-size: var(--fs-h2); }
.top-title .svc { font-family: Figtree, system-ui, sans-serif; font-size: var(--fs-body); font-weight: 600; color: var(--muted); }
.top-title { min-width: 0; }
/* The day's lesson under the date, one line. */
.top-sub { margin: 2px 0 0; font-size: var(--fs-sec); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-actions { display: flex; gap: 2px; margin-right: -8px; flex-shrink: 0; }
.icon-btn { position: relative; width: 44px; height: 44px; display: grid; place-items: center; border: 0; border-radius: 12px;
  background: transparent; color: var(--ink); cursor: pointer; }
.icon-btn:active, .icon-btn[aria-expanded="true"] { background: var(--bg); }
/* The other service has work not saved yet: an orange dot on ⋯. */
.icon-btn .dot { position: absolute; top: 9px; right: 8px; width: 9px; height: 9px; border-radius: 50%; background: #E36414; }
.menu { position: absolute; z-index: 1; top: calc(100% - 6px); right: 12px; min-width: 220px; max-width: calc(100% - 24px);
  display: flex; flex-direction: column; padding: 6px; background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: 0 12px 30px rgba(16, 41, 44, .18); animation: fade .15s ease; } /* z: under .scrim */
.menu[hidden] { display: none; }
@keyframes fade { from { opacity: 0; } }
.menu-item { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 12px; border: 0; border-radius: 10px;
  background: transparent; color: var(--ink); font-size: var(--fs-body); text-align: left; text-decoration: none; cursor: pointer; }
.menu-item:active { background: var(--bg); }
.menu-item > svg { flex-shrink: 0; color: var(--muted); }
.menu-item .menu-text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.menu-note { font-size: var(--fs-sec); font-weight: 600; color: var(--muted); }
.menu-note.draft { color: var(--orange-ink); }
/* Search, under the header row: always on Prés, behind the icon on Presenças. */
.search { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 12px; border-radius: 12px;
  background: var(--bg); color: var(--muted); cursor: text; }
.search[hidden] { display: none; }
.search input { flex: 1; min-width: 0; height: 100%; border: 0; background: transparent; font: inherit; font-size: var(--fs-body); color: var(--ink); outline: none; -webkit-appearance: none; appearance: none; }
.search:focus-within { box-shadow: 0 0 0 2px var(--brand); }
/* Searching: one flat list of the matches, no section titles. */
.scroll.searching .sec { display: none; }
.scroll.searching .grid.grid-sec { padding-top: 14px; }
.scroll.searching .grp:not([hidden]) ~ .grp .grid { margin-top: -6px; padding-top: 0; }
.head { flex-shrink: 0; display: flex; flex-direction: column; }
.tag.past { margin-top: 8px; font-size: var(--fs-pill); }

/* Grid (concept B) */
.scroll { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding: 14px; }
.card { position: relative; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px;
  min-height: 70px; padding: 10px 34px 10px 14px; border-radius: 16px; border: 1.5px solid var(--card-line);
  background: var(--surface); text-align: left; cursor: pointer; touch-action: manipulation; }
.card .first { font-size: var(--fs-body); font-weight: 700; line-height: 1.15; }
.card .rest { max-width: 100%; font-size: var(--fs-sec); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card .tick { position: absolute; top: 10px; right: 10px; width: 22px; height: 22px; border-radius: 50%; background: #fff;
  display: flex; align-items: center; justify-content: center; opacity: 0; }
.card[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: #fff; }
.card[aria-pressed="true"] .rest { color: var(--on-brand-soft); }
.card[aria-pressed="true"] .tick { opacity: 1; }
/* The roll call's cards: ~50 px, first name and surname on one line, tags on the line
   below. Top-aligned so names line up across a row; the tick stays centred. */
.card.compact { justify-content: flex-start; gap: 3px; min-height: 50px; padding: 13px 34px 8px 12px; }
.card .name { display: flex; align-items: baseline; gap: 5px; max-width: 100%; min-width: 0; }
.card.compact .name { display: block; line-height: 1.2; }
.card.compact .rest { white-space: normal; overflow: visible; } /* the surname, smaller; wraps when long */
.card.compact .tick { top: 50%; margin-top: -11px; }
.card .tags { display: flex; flex-wrap: wrap; gap: 0 8px; }
/* Birthday and missed Sundays: a small line under the name, no pills. */
.meta { display: inline-flex; align-items: center; gap: 3px; margin-left: -6px; padding: 1px 6px; border-radius: 6px;
  font-size: var(--fs-label); font-weight: 600; line-height: 1.2; color: var(--muted); transition: background-color .2s ease, color .2s ease; }
/* Grey until the pré is marked; then the birthday and the missed Sundays light up (and pop
   once, on the tap), so the teacher notices who to greet. */
.card[aria-pressed="true"] .meta.bday { background: #FFE58F; color: #5C4300; }
.card[aria-pressed="true"] .meta.late { background: #FFD6BD; color: #8A3309; }
.card.pop .meta.bday, .card.pop .meta.late { animation: meta-pop .5s var(--spring); }
@keyframes meta-pop { 0% { transform: scale(.85); } 45% { transform: scale(1.18); } 100% { transform: scale(1); } }
.card.visit .meta { margin-left: 0; padding: 0; }
.card[hidden], .grp[hidden] { display: none; }
/* A visitor: orange tint, always present, tapping edits it. */
.card.visit { background: #FFF6EE; border-color: var(--orange-line); color: var(--ink); }
.card.visit .tick { opacity: 1; transform: scale(1); }
.tag { margin-top: 4px; padding: 2px 7px; border-radius: 7px; background: var(--orange-soft); color: var(--orange-ink); font-size: var(--fs-pill); font-weight: 700; }
.visitors { padding: 0 16px 16px; margin: 0; }
/* A visitor: orange, in the grid's visitor row and in the Guardar sheet. */
.chip.visitor, button.chip.visitor { background: var(--orange-soft); border-color: var(--orange-line); color: var(--orange-ink); font-weight: 600; }
.chip-tag { margin-left: 2px; font-size: var(--fs-pill); font-weight: 700; opacity: .8; }

/* Footer bar: one button, Guardar with the count, or why there is nothing to save. */
.bar { flex-shrink: 0; padding: 10px 16px; background: var(--surface); border-top: 1px solid var(--line); }
.bar .save { width: 100%; min-height: 54px; }
.count { display: inline-block; font-family: var(--display); font-size: var(--fs-h3); font-weight: 800; line-height: 1; }

/* Buttons */
.btn { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 52px; padding: 0 24px; border: 0;
  border-radius: 14px; font-size: var(--fs-btn); font-weight: 700; text-decoration: none; cursor: pointer; }
.btn.primary { background: var(--brand); color: #fff; }
.btn.orange { background: var(--orange); color: #fff; }
.btn.ghost { background: var(--bg); color: var(--ink); font-weight: 600; }
.btn.ghost.danger { color: var(--orange-ink); }
.btn.orange-soft { flex-shrink: 0; min-height: 44px; padding: 0 14px 0 10px; gap: 4px; font-size: var(--fs-btn-sm); background: var(--orange-soft); color: var(--orange-ink); }
.btn.soft { align-self: flex-start; min-height: 44px; padding: 0 14px; font-size: var(--fs-btn-sm); background: var(--brand-soft); color: var(--brand-dark); }
.btn:disabled { opacity: .6; }
.btn.primary:disabled { background: #EAF0EF; color: #8FA3A1; opacity: 1; }
.link { align-self: center; min-height: 44px; padding: 0 12px; border: 0; background: none; color: var(--brand); font-weight: 600; cursor: pointer; }

/* Tabs */
.tabs { flex-shrink: 0; display: flex; background: var(--surface); border-top: 1px solid var(--line); padding: 4px 8px calc(10px + env(safe-area-inset-bottom)); }
.tabs[hidden] { display: none; }
.tabs a { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 0; text-decoration: none; color: var(--muted); font-size: var(--fs-pill); font-weight: 600; }
.tabs a[aria-current="page"] { color: var(--brand); font-weight: 700; }

/* Bottom sheet */
.scrim { position: fixed; inset: 0; z-index: 2; background: var(--scrim); } /* z: over the floating header */
.sheet { position: fixed; z-index: 2; left: 0; right: 0; bottom: 0; max-height: 92dvh; overflow-y: auto; display: flex; flex-direction: column; gap: 16px;
  padding: 12px 20px calc(24px + env(safe-area-inset-bottom)); background: var(--surface); border-radius: 26px 26px 0 0; }
.handle { align-self: center; width: 44px; height: 5px; border-radius: 3px; background: var(--card-line); }
.sheet-head { display: flex; flex-direction: column; gap: 4px; }
.sheet-head p { margin: 0; }
/* The Guardar sheet's one count line: big number, "presentes", muted prés + visitas. */
.sum { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 6px; margin: 0; font-size: var(--fs-body); font-weight: 600; }
.sum strong { font-family: var(--display); font-size: var(--fs-h2); font-weight: 800; color: var(--brand); line-height: 1; }
.sum .muted { font-size: var(--fs-sec); font-weight: 500; }
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.stats.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stats.one { grid-template-columns: minmax(0, 1fr); }
.stat { display: flex; flex-direction: column; gap: 2px; padding: 12px; border-radius: 14px; background: var(--bg); font-size: var(--fs-sec); font-weight: 600; }
.stat strong { font-family: var(--display); font-size: var(--fs-h2); font-weight: 800; line-height: 1; }
.stat.brand { background: var(--brand-soft); }
.stat.brand strong { color: var(--brand); }
.stat.orange { background: var(--orange-soft); }
.stat.orange strong { color: var(--orange-ink); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; max-height: 190px; overflow-y: auto; }
.chip { padding: 6px 10px; border-radius: 9px; background: var(--bg); font-size: var(--fs-sec); }
button.chip { border: 1.5px solid var(--card-line); background: var(--surface); cursor: pointer; min-height: 36px; }
.label { font-size: var(--fs-sec); font-weight: 700; }
.input { height: 54px; padding: 0 16px; border: 2px solid var(--card-line); border-radius: 14px; font: inherit; font-size: var(--fs-body); color: var(--ink); }
.input:focus { outline: 3px solid #9ADCE5; outline-offset: 1px; }
.preview { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 12px; background: var(--bg); font-weight: 600; }
.error { margin: 0; padding: 10px 12px; border-radius: 12px; background: var(--orange-soft); color: var(--orange-ink); font-weight: 600; }
.error[hidden] { display: none; }
.warn { color: var(--orange-ink); }

/* Full-screen states */
.empty, .login, .done { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 24px; text-align: center; }
.done-mark { width: 96px; height: 96px; border-radius: 50%; background: var(--brand); display: flex; align-items: center; justify-content: center; }
.done-mark.pending { background: var(--orange); }
.done-actions { display: flex; flex-direction: column; gap: 10px; padding: 0 20px calc(20px + env(safe-area-inset-bottom)); }

/* Prés list: A–Z, one sticky letter per group, a strip of the last 8 Sundays per row */
/* "A faltar" beside the search: only who has missed 3+ Sundays in a row. A quiet control,
   not a warning - there is nearly always someone on that list. */
.search-row { display: flex; gap: 8px; }
.search-row .search { flex: 1; min-width: 0; }
.filter-chip { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; height: 44px; padding: 0 12px;
  border: 1.5px solid var(--card-line); border-radius: 12px; background: var(--surface); color: var(--ink);
  font: inherit; font-size: var(--fs-btn-sm); font-weight: 600; cursor: pointer; }
.filter-count { min-width: 20px; padding: 1px 6px; border-radius: 7px; background: var(--orange-soft); color: var(--orange-ink);
  font-size: var(--fs-pill); font-weight: 700; text-align: center; }
.filter-chip[aria-pressed="true"] { background: var(--orange); border-color: var(--orange); color: #fff; }
.filter-chip[aria-pressed="true"] .filter-count { background: rgba(255, 255, 255, .25); color: #fff; }
.strip-legend { display: flex; justify-content: space-between; gap: 12px; margin: 0; padding: 12px 16px 6px; }
.strip-legend .key { display: inline-block; width: 10px; height: 8px; margin-left: 6px; border-radius: 2px; vertical-align: 0; box-shadow: inset 0 0 0 1.5px #9FB3B1; }
.strip-legend .key.on { background: var(--brand); box-shadow: none; }
.scroll.searching .strip-legend, .scroll.searching .az-letter { display: none; }
.scroll.searching .list { border-top: 0; } /* one flat list of matches under the header */
.az-letter { position: sticky; top: 0; z-index: 1; margin: 0; padding: 8px 16px 4px; background: var(--bg);
  font-family: var(--display); font-size: var(--fs-label); font-weight: 800; color: var(--brand); }
.list { list-style: none; margin: 0; padding: 0; background: var(--surface); border-top: 1px solid var(--line); }
.list li[hidden] { display: none; }
.row { display: flex; align-items: center; gap: 12px; min-height: 60px; padding: 8px 16px; border-bottom: 1px solid var(--line-soft); color: var(--ink); text-decoration: none; }
.crow { display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 6px 16px; border-bottom: 1px solid var(--line-soft); color: var(--ink); text-decoration: none; }
.crow-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.crow.alert .name strong { color: var(--orange-ink); }
.name { font-size: var(--fs-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.strip { display: grid; grid-template-columns: repeat(8, 1fr); gap: 3px; width: 88px; flex-shrink: 0; }
/* came = solid brand, missed = hollow, no class that Sunday = pale fill */
.strip i { height: 8px; border-radius: 2px; box-shadow: inset 0 0 0 1.5px #9FB3B1; }
.strip i.on { background: var(--brand); box-shadow: none; }
.strip i.none { background: var(--line-soft); box-shadow: none; }
.crow.alert .strip i:not(.on):not(.none) { background: var(--orange-soft); box-shadow: inset 0 0 0 1.5px var(--orange-line); }

/* Pré detail */
.back { align-self: flex-start; display: flex; align-items: center; gap: 4px; min-height: 44px; font-weight: 600; text-decoration: none; }
.day { width: 52px; flex-shrink: 0; font-weight: 700; }
.lesson-cell { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.day-pill { flex-shrink: 0; padding: 4px 10px; border-radius: 8px; font-size: var(--fs-pill); font-weight: 700; white-space: nowrap; }
.day-pill.came { background: var(--brand); color: #fff; }
.day-pill.missed { background: var(--orange-soft); color: var(--orange-ink); }
.day-pill.unmarked { background: #EAF0EF; color: var(--muted); }
.split { display: flex; justify-content: space-between; align-items: baseline; }
.split .svc { text-transform: none; letter-spacing: 0; font-weight: 600; }
.pad { padding: 14px 16px 6px; }

/* Calendário: Sundays */
.pad-x { padding: 8px 14px 20px; display: flex; flex-direction: column; gap: 8px; }
.month { margin: 10px 6px 2px; font-size: var(--fs-label); font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.week { display: flex; flex-direction: column; gap: 6px; padding: 12px 16px; border-radius: 16px; background: var(--surface); border: 2px solid var(--surface); }
.week.current { border-color: var(--brand); }
.week.off { flex-direction: row; align-items: center; gap: 14px; background: #EAF0EF; border-color: #EAF0EF; color: var(--muted); font-weight: 600; }
.week-top { display: flex; gap: 14px; align-items: flex-start; }
.day-num { width: 44px; flex-shrink: 0; display: flex; flex-direction: column; gap: 2px; font-family: var(--display); font-size: var(--fs-h2); font-weight: 800; line-height: 1; }
.badge { align-self: flex-start; padding: 2px 6px; border-radius: 6px; background: var(--brand); color: #fff; font-family: Figtree, sans-serif; font-size: var(--fs-pill); }
.week-lesson { flex: 1; min-width: 0; font-weight: 600; line-height: 1.35; }
.week .btn.soft { margin-left: 58px; }

.week-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.teams-line { display: flex; flex-wrap: wrap; column-gap: 6px; row-gap: 2px; margin: 0; padding-left: 58px; font-size: var(--fs-sec); }
.teams-line b { color: var(--muted); }
.teams-line .sep { color: var(--muted); }

/* Calendário: events. Each card sets --ev-bg / --ev-ink from its Cor (web/logic.js EVENT_COLORS). */
.ev-strip { display: flex; gap: 10px; margin: 0 -14px; padding: 2px 14px 6px; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-padding-inline: 14px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.ev-strip::-webkit-scrollbar { display: none; }
.ev-card { flex: 0 0 168px; scroll-snap-align: start; display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 18px;
  background: var(--ev-bg); color: var(--ev-ink); text-decoration: none; }
.ev-card-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 6px; }
.ev-card-emoji { font-size: 28px; line-height: 1; }
.ev-pill { flex-shrink: 0; padding: 3px 8px; border-radius: 999px; background: rgba(255, 255, 255, .7); color: var(--ev-ink);
  font-size: var(--fs-pill); font-weight: 700; white-space: nowrap; }
.ev-card-title { font-family: var(--display); font-size: var(--fs-body); font-weight: 800; line-height: 1.15; }
.ev-dates { font-size: var(--fs-pill); font-weight: 600; }
.ev-row { display: flex; align-items: flex-start; gap: 14px; padding: 12px 16px; border-radius: 16px; background: var(--ev-bg); color: var(--ev-ink); text-decoration: none; }
.ev-row .day-num { color: var(--ev-ink); }
.ev-body { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.ev-title { font-size: var(--fs-body); font-weight: 700; line-height: 1.3; }
.ev-sub { font-size: var(--fs-sec); opacity: .85; line-height: 1.3; }

/* Event detail */
.ev-head { flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: calc(10px + env(safe-area-inset-top)) 16px 20px; background: var(--ev-bg); color: var(--ev-ink); }
.ev-head .back { color: inherit; }
.ev-big-emoji { font-size: 56px; line-height: 1; }
.ev-head-dates { margin: 0; font-weight: 600; }
.info { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border-radius: 16px; background: var(--surface); }
.info-text { margin: 0; line-height: 1.4; white-space: pre-line; overflow-wrap: anywhere; }

@media (min-width: 640px) {
  body { max-width: 720px; margin: 0 auto; border-inline: 1px solid var(--line); }
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Motion ("suave"). Short on things that happen 40 times a Sunday, a bit longer on the
   one-off payoff. Everything is CSS; prefers-reduced-motion switches it all off, so every
   animation's resting state must be the visible one (keyframes carry the "from" state). */
:root { --spring: cubic-bezier(.34, 1.56, .64, 1); --ease-out: cubic-bezier(.2, .9, .25, 1); }
.card { transition: transform .12s ease, background-color .2s ease, border-color .2s ease, color .2s ease; -webkit-tap-highlight-color: transparent; }
.card:active { transform: scale(.95); }
.card .rest { transition: color .2s ease; }
.card .tick { transform: scale(0); transition: transform .3s var(--spring), opacity .12s ease; }
.card[aria-pressed="true"] .tick { transform: scale(1); }
.count { display: inline-block; transform-origin: 50% 60%; }
.count.bump { animation: bump .3s var(--spring); }
@keyframes bump { 45% { transform: scale(1.3); } }

.scrim { opacity: 0; transition: opacity .22s ease; }
.scrim.open { opacity: 1; }
.sheet { transform: translateY(105%); transition: transform .2s cubic-bezier(.4, 0, 1, 1); }
.sheet.open { transform: none; transition: transform .38s var(--ease-out); }
.sheet .sum { animation: rise .35s var(--ease-out) .14s both; }

.done-mark { position: relative; animation: pop .45s var(--spring) both; }
.done-mark::after { content: ''; position: absolute; inset: 0; border-radius: 50%; border: 3px solid var(--brand);
  opacity: 0; animation: ring .8s ease-out .2s both; }
.done-mark.pending::after { border-color: var(--orange); }
.done-mark .draw { stroke-dasharray: 22; animation: draw .32s ease-out .25s both; }
.done > h1, .done > p { animation: rise .35s var(--ease-out) both; }
.done > h1 { animation-delay: .38s; }
.done > p { animation-delay: .46s; }
.done > p + p { animation-delay: .52s; }
@keyframes pop { from { transform: scale(.3); opacity: 0; } }
@keyframes ring { from { transform: scale(.9); opacity: .45; } to { transform: scale(1.8); opacity: 0; } }
@keyframes draw { from { stroke-dashoffset: 22; } to { stroke-dashoffset: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(12px) scale(.98); } }

/* First visit to a tab: its items cascade in, 25 ms apart (--i set per item). */
.enter > * { animation: rise .34s var(--ease-out) both; animation-delay: calc(var(--i, 0) * 25ms); }
.tabs a { position: relative; }
.tabs a::before { content: ''; position: absolute; top: 0; left: 50%; width: 28px; height: 3px; margin-left: -14px; border-radius: 2px;
  background: var(--brand); transform: scaleX(0); transition: transform .25s var(--ease-out); }
.tabs a[aria-current="page"]::before { transform: scaleX(1); }

/* Pressing a button gives a little, as the cards do; Guardar and the filters change
   colour over 200 ms instead of flipping. */
.btn, .pill, .filter-chip, .link { transition: transform .1s ease, background-color .2s ease, border-color .2s ease, color .2s ease, opacity .2s ease; }
.btn:active:not(:disabled), .pill:active, .icon-btn:active, .filter-chip:active, .link:active { transform: scale(.97); }
/* Things that appear: the outbox pill, a visitor just added, the Prés list after a filter. */
.outbox:not([hidden]) { animation: rise .25s var(--ease-out); }
.card.just { animation: rise .3s var(--ease-out); }
.fade-in { animation: fade .18s ease; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* Past Sunday being corrected: never confusable with today's roll call. */
.tag.past { display: inline-block; }
.week-actions { display: flex; flex-wrap: wrap; gap: 8px; padding-left: 58px; }
.week-actions .btn.soft { margin-left: 0; }

/* Regulars first: two sections when some pre-teens rarely come to this service.
   A thin divider label: LABEL ──── N. The rarely group sits on a grey band. */
.sec { display: flex; align-items: center; gap: 10px; margin: 0; padding: 16px 16px 0; font-size: var(--fs-label);
  font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.sec::after { content: ""; flex: 1; order: 1; height: 1px; background: var(--card-line); }
.sec > span + span { order: 2; font-weight: 600; letter-spacing: 0; }
.grid.grid-sec { padding-top: 8px; }
.grp + .grp > .sec { padding-top: 6px; }
.grp[data-grp="rare"] { background: var(--band); }
.grp[data-grp="rare"] > .sec { padding-top: 16px; }
.grp[data-grp="rare"] .sec::after { background: #D3DDDB; }
.grp[data-grp="rare"] .card.rare:not([aria-pressed="true"]) { background: rgba(255, 255, 255, .5); }
.card.rare { background: transparent; border-color: var(--line); }
.card.rare[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); }

.login-logo { width: 96px; height: 96px; border-radius: 22px; box-shadow: 0 10px 30px rgba(16, 41, 44, .12); animation: pop .45s var(--spring) both; }

/* Loading between screens: the launch splash's dots on their own (styles inline in index.html). */
.splash.splash-small { background: transparent; }
/* Most screens answer in well under half a second: show the dots only if it takes longer. */
.splash.splash-small { animation: splash-late .01s linear .4s both; }
@keyframes splash-late { from { opacity: 0; } }

/* Items of a scrolling column never shrink: an overflow-x row (the events strip) would
   otherwise be squashed to nothing once the agenda is taller than the screen. */
.pad-x > * { flex-shrink: 0; }

/* DEMO=on only (app.js adds body.demo): a thin strip above every screen. It takes the
   top safe area, so the headers under it drop theirs. */
body.demo::before { content: 'Demonstração · dados fictícios'; flex-shrink: 0; display: block;
  padding: calc(2px + env(safe-area-inset-top)) 12px 2px; background: var(--orange); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 14px; letter-spacing: .02em; text-align: center; }
body.demo .top { padding-top: 18px; }
body.demo .top.roll { padding-top: 10px; }
body.demo .ev-head { padding-top: 10px; }

/* A class Sunday's page: event-page layout; the card's top links to it. */
.week-link { color: inherit; text-decoration: none; }
.info-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 0; }
.info-row + .info-row { border-top: 1px solid var(--line-soft); }
.info-btn { min-height: 40px; padding: 0 14px; font-size: var(--fs-btn-sm); }

/* Visitor sheet: a label sits close to its input; "(opcional)" is quieter. */
.field { display: flex; flex-direction: column; gap: 6px; }
.label .opt { font-weight: 500; color: var(--muted); }
.info-line { margin: 0; display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-body); }
.info-line .label { color: var(--muted); font-size: var(--fs-sec); }

/* Presenças: a Sunday with no column (no class, or not prepared yet). */
.nc { display: flex; flex-direction: column; gap: 12px; padding: 16px 14px 24px; }
.nc > * { flex-shrink: 0; }
.nc-card { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px; border-radius: 16px; background: var(--surface); color: var(--ink); text-decoration: none; }
.nc-empty-title { margin: 0; font-family: var(--display); font-size: var(--fs-h3); font-weight: 800; line-height: 1.2; }
.nc-empty .muted { margin: 0; }
.nc-event { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: 18px 16px; border-radius: 18px; background: var(--ev-bg); color: var(--ev-ink); }
.nc-eyebrow { margin: 0; font-size: var(--fs-label); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
.nc-ev-place { margin: 0; font-weight: 600; }
.nc-ev-btn { align-self: stretch; min-height: 48px; margin-top: 4px; background: var(--ev-ink); color: #fff; }
.nc-row { display: flex; align-items: center; gap: 10px; min-height: 48px; }
.nc-row + .nc-row { border-top: 1px solid var(--line-soft); }
.nc-when { flex: 1; min-width: 0; font-weight: 700; }
.nc-btn { align-self: center; min-width: 88px; }
.nc-next-line { margin: 0; line-height: 1.35; }
.nc-next .muted { margin: 0; }

/* Calendário: the teacher's own name in a teams line. */
mark.me { padding: 0 3px; border-radius: 4px; background: var(--brand-soft); color: var(--brand-dark); font-weight: 700; }

/* "A tua próxima aula": brand card at the top of the Calendário. */
.next-class { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; padding: 14px 16px; border-radius: 16px; background: var(--brand); color: #fff; }
.next-class .eyebrow { color: var(--on-brand-soft); }
.next-class-link { display: flex; flex-direction: column; gap: 4px; color: inherit; text-decoration: none; }
.next-class-when { font-family: var(--display); font-size: var(--fs-h3); font-weight: 800; line-height: 1.1; }
.next-class-lesson { font-size: var(--fs-body); line-height: 1.4; }
.next-class-teams { display: flex; flex-wrap: wrap; column-gap: 6px; font-size: var(--fs-sec); opacity: .85; }
.next-class-teams b { font-weight: 600; }
.next-class mark.me { background: rgba(255, 255, 255, .22); color: #fff; }
.next-class-btn { min-height: 44px; font-size: var(--fs-btn-sm); background: #fff; color: var(--brand-dark); }

/* "Aniversários este mês". */
.bday-row { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: 16px; background: var(--surface); font-size: var(--fs-body); }
.bday-pill { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; padding: 4px 10px; border-radius: 8px;
  background: #FFF1BF; color: #6B4E00; font-size: var(--fs-pill); font-weight: 700; white-space: nowrap; }
.bday-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A month header; the first carries "Ver domingos anteriores" on its right. */
.month-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.month-row .month { flex: 1; }
.link.month-link { align-self: auto; min-height: 32px; margin: 8px 0 0; padding: 0 6px; font-size: var(--fs-sec); }

/* Past class Sunday with a service not marked yet. */
.todo-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 0; padding-left: 58px; }
.todo-pill { display: inline-flex; align-items: center; min-height: 28px; padding: 4px 10px; border-radius: 8px;
  background: var(--orange-soft); color: var(--orange-ink); font-size: var(--fs-pill); font-weight: 700; text-decoration: none; white-space: nowrap; }

/* Guardado: what to say to whom, the "add to home screen" card, the other service. */
.done { overflow-y: auto; }
.done-sum { margin: 0; font-size: var(--fs-body); }
.done-notes { align-self: stretch; margin-top: 8px; gap: 10px; text-align: left; line-height: 1.35; }
.done-notes p { margin: 0; }
.install { align-self: stretch; gap: 8px; text-align: left; border: 1.5px dashed #C4D2D0; }
.install-text { margin: 0; font-size: var(--fs-sec); line-height: 1.4; }
.install-actions { display: flex; gap: 8px; }
.install-actions .btn { min-height: 40px; padding: 0 14px; font-size: var(--fs-btn-sm); }
.install-no { background: var(--bg); }
.done-other { margin: 0; padding: 14px 0; text-align: center; font-weight: 600; }
.done > .done-notes, .done > .install { animation: rise .35s var(--ease-out) .56s both; }

/* Offline (board 9). The pill above the tabs while a roll call waits for the network (or
   was refused for good); the grey line when the screen shows the phone's cached copy. */
.outbox { flex-shrink: 0; display: flex; align-items: center; gap: 8px; margin: 8px 14px; padding: 6px 6px 6px 14px;
  border-radius: 12px; background: var(--ink); color: #fff; font-size: var(--fs-sec); font-weight: 600; }
.outbox[hidden], .net[hidden] { display: none; }
.outbox-text { flex: 1; min-width: 0; }
.outbox-go { flex-shrink: 0; min-height: 36px; padding: 0 10px; border: 0; border-radius: 8px; background: transparent;
  color: #9ED1D8; font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; cursor: pointer; }
.outbox-go:disabled { opacity: .6; }
.net { flex-shrink: 0; margin: 0; padding: 5px 14px; background: #EAF0EF; color: var(--muted); font-size: var(--fs-label); font-weight: 600; text-align: center; }
/* The grid from the last known list (a first open with no network). */
.strip-amber { flex-shrink: 0; margin: 0; padding: 10px 14px; background: #FFF1BF; color: #6B4E00; font-size: var(--fs-sec); font-weight: 600; line-height: 1.3; }
/* The amber strip already says "Sem rede": no second grey line under it. */
body:has(.strip-amber) .net { display: none; }
