/* acte-server/public/design-system.css
   Shared design system for ACTE App pages. Scoped to `.acte` (a class every
   page root also carries alongside its own #acte-app/#acte-staff/#acte-vol ID)
   -- see docs/superpowers/specs/2026-08-07-visual-design-system-design.md for
   why a plain unscoped selector would silently lose to every existing
   #acte-app-scoped rule and do nothing.

   Phase 1 covers attendee.html only. staff.html/volunteer.html link this same
   file in their own later phases. */

/* ---------- Fonts: self-hosted Montserrat (SIL OFL, see fonts/OFL.txt) ---------- */
/* Each subset file is a variable font containing the full weight axis, so one
   file per subset backs all three declared weights below. */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/montserrat-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/montserrat-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/montserrat-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/montserrat-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/montserrat-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/montserrat-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* spacing, 4px base */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px;

  /* radius */
  --radius-sm: 6px;    /* controls: inputs, buttons */
  --radius-md: 10px;   /* cards, panels */
  --radius-pill: 999px;

  /* shadow */
  --shadow-resting: 0 1px 2px rgba(20,30,50,.06), 0 8px 24px -12px rgba(20,30,50,.18);
  --shadow-raised: 0 4px 8px rgba(20,30,50,.10), 0 24px 48px -16px rgba(20,30,50,.30);

  /* type scale, px */
  --text-2xl: 28px; --text-xl: 22px; --text-lg: 17px; --text-md: 15px;
  --text-sm: 13.5px; --text-xs: 12px; --text-2xs: 11px;

  /* brand colors -- verified against docs/Manual de Marca Domininco Americano.pdf,
     values unchanged from what the app already used. Overridden per-page-root at
     runtime by the Appearance panel via element.style.setProperty() on
     #acte-app/#acte-staff/#acte-vol, which sits nearer in the cascade than :root
     for everything inside that page -- so the panel's value keeps winning. */
  --blue: #0055b8; --blue-ink: #003d87; --red: #ea0029;
  --black-100: #231f20; --black-50: #929497;

  /* neutrals -- --text aligned to brand Black 100%. --text-dim is deliberately NOT
     set to brand Black 50% (#929497): that swatch is ~2.9:1 contrast on white,
     below WCAG AA's 4.5:1 for body text, so it stays at the app's existing value. */
  --text: #231f20; --text-dim: #5b6472;
  --bg: #f3f7f8; --surface: #fff; --surface-2: #eef2f4; --border: #dde3e7; --tint: #eaf1fb;
  --teal-1: #0d3947; --navy-1: #0a1a38; --ring: rgba(120,225,255,.24);

  /* semantic colors -- independent of --red/--blue on purpose, so the Appearance
     panel's brand-color pickers can never change what "error" or "success" means.
     Not exposed in the Appearance panel. */
  --success: #1e8e5a;  /* was --good */
  --danger: #b42318;   /* fixed, independent of --red */
  --warning: #b45309;
  --info: var(--blue);
}

/* ---------- Buttons ---------- */
/* button-qualified (not just .primary): staff.html also uses class="panel primary" on
   several <div>s for a "primary/hero" panel variant -- an unqualified .primary here would
   collide with .panel's text-color-less card styling (white text stays unset on a white
   card) and its :hover would flood the panel dark blue. Verified every class="primary" in
   attendee.html/staff.html is on a <button> before this was element-qualified. */
/* Accent color (spec 2026-10-23): primary buttons take --accent (set per page from Appearance), falling back to the primary blue. */
.acte button.primary{ background:var(--accent, var(--blue)); color:#fff; border:none; font:inherit; font-weight:700; font-size:var(--text-md); padding:12px 20px; border-radius:var(--radius-sm); cursor:pointer; }
.acte button.primary.wide{ width:100%; }
.acte button.primary:disabled{ opacity:.6; cursor:default; }
.acte button.primary:not(:disabled):hover{ background:var(--blue-ink); }
@supports (background: color-mix(in srgb, red 50%, black)){ .acte button.primary:not(:disabled):hover{ background:color-mix(in srgb, var(--accent, var(--blue)) 82%, black); } }
.acte .schedbtn{ appearance:none; border:1px solid var(--border); background:var(--surface); font:inherit; font-size:var(--text-2xs); font-weight:800; padding:6px 10px; border-radius:var(--radius-pill); cursor:pointer; flex:none; }
/* icon-only booking button: same visual language as .schedbtn, but sized as a real
   touch target since it no longer carries a text label. */
.acte .schedbtn.icon{ min-width:38px; min-height:38px; display:inline-flex; align-items:center; justify-content:center; font-size:15px; padding:0; }
.acte button.ghost{ background:none; border:1px solid var(--border); font:inherit; font-weight:700; font-size:12.5px; padding:7px 12px; border-radius:8px; cursor:pointer; }
.acte button.ghost:hover{ border-color:var(--blue); color:var(--blue-ink); }
.acte button.ghost.on{ background:var(--tint); border-color:var(--blue); color:var(--blue-ink); }

/* ---------- Program card (attendee schedule) ----------
   Faithful reproduction of docs/mockups/program-card-mockup.html, Option A (the approved
   direction). Colors/spacing map 1:1 onto this file's tokens (--a-border -> --border,
   --a-surface -> --surface, --a-blue-ink -> --blue-ink, --a-dim -> --text-dim,
   --a-tint -> --tint, --a-text -> --text, --a-blue -> --blue). */
.acte .daybar{ display:flex; align-items:baseline; gap:8px; margin:0 0 9px; padding-bottom:6px; border-bottom:1px solid var(--border); }
.acte .daybar .d{ font-size:12px; font-weight:800; color:var(--blue-ink); letter-spacing:.02em; }
.acte .daybar .n{ font-size:10.5px; color:var(--text-dim); }

.acte .sched-card{ display:flex; gap:10px; padding:12px; border:1px solid var(--border); border-radius:8px; background:var(--surface); align-items:flex-start; }
.acte .sched-card + .sched-card{ margin-top:8px; }
.acte .slot-time{ font-size:11px; font-weight:800; color:var(--blue-ink); width:52px; flex:none; }
.acte .slot-time .to{ display:block; font-weight:700; color:var(--text-dim); }
.acte .slot-body{ flex:1; min-width:0; }
.acte .slot-title{ font-weight:700; font-size:13.5px; line-height:1.3; }
.acte .slot-meta{ font-size:11px; color:var(--text-dim); margin-top:2px; }
.acte .slot-count{ font-size:11px; color:var(--text-dim); margin-top:4px; }

.acte .abstract{ font-size:11.5px; color:var(--text-dim); line-height:1.5; margin:6px 0 0; }
.acte .clamp2{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.acte .clamp3{ display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }

.acte .avatar{ width:22px; height:22px; border-radius:999px; flex:none; background:var(--tint); color:var(--blue-ink); font-size:9px; font-weight:800; display:flex; align-items:center; justify-content:center; border:1px solid var(--border); object-fit:cover; }
.acte .avatar.lg{ width:38px; height:38px; font-size:12px; }
/* .xl is the full-profile hero size (attendee Presenters directory detail view) -- deliberately
   much larger than .lg, which is sized for a schedule chip's inline expand pane. margin:0 auto
   centers it: .avatar's own `display:flex` makes it a block-level box (outer display is block per
   the flex spec), so the parent's text-align:center has no effect on it -- only auto margins do. */
.acte .avatar.xl{ width:220px; height:220px; font-size:56px; margin:0 auto 14px; }

.acte .presenter-row{ display:flex; flex-wrap:wrap; }
.acte .presenter-chip{ display:inline-flex; align-items:center; gap:6px; padding:3px 9px 3px 3px; border:1px solid var(--border); border-radius:999px; background:var(--surface); font:inherit; font-size:10.5px; font-weight:600; color:var(--text); cursor:pointer; margin:5px 5px 0 0; }
.acte .presenter-chip[aria-expanded="true"]{ background:var(--tint); border-color:var(--blue); }

/* inline bio, revealed by tapping a presenter chip; see the presenter-chip click handler
   in attendee.html's renderSchedule(). */
.acte .bio-slot{ margin-top:8px; padding-top:8px; border-top:1px dashed var(--border); }
.acte .bio-slot[hidden]{ display:none; }
.acte .bio-row{ display:flex; gap:9px; align-items:flex-start; }
.acte .bio-row + .bio-row{ margin-top:9px; }
.acte .bio-name{ font-size:11.5px; font-weight:700; }
.acte .bio-cred{ font-size:10px; color:var(--blue-ink); font-weight:600; margin-top:1px; }
.acte .bio-text{ font-size:10.5px; color:var(--text-dim); line-height:1.45; margin:3px 0 0; }

.acte .expander{ appearance:none; background:none; border:0; padding:0; margin-top:6px; font:inherit; font-size:10.5px; font-weight:700; color:var(--blue); cursor:pointer; text-align:left; }

/* attendee-facing popularity nudge: fires at >=80% of capacity, never shows raw numbers.
   Warm, not alarming -- it is advice, not a warning that a seat is already gone. */
.acte .pop-flag{ display:inline-flex; align-items:flex-start; gap:5px; margin-top:6px; font-size:10px; font-weight:700; line-height:1.35; color:var(--blue-ink); background:var(--tint); border-radius:6px; padding:4px 8px; }

.acte .zoom-hint{ font-size:11px; color:var(--text-dim); margin-top:6px; font-style:italic; }

.acte .schedbtn:focus-visible, .acte .presenter-chip:focus-visible, .acte .expander:focus-visible{
  outline:2px solid var(--blue); outline-offset:2px;
}

/* ---------- Cards / panels ---------- */
.acte .card{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:var(--space-5); box-shadow:var(--shadow-resting); }
.acte .panel{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:var(--space-5); box-shadow:var(--shadow-resting); }
.acte .panel + .panel{ margin-top:18px; }
.acte .shell{ max-width:760px; margin:0 auto; padding:26px 16px 60px; }
.acte .shell.narrow{ max-width:380px; }
.acte .panelwrap{ background:var(--surface-2); border:1px solid var(--border); border-radius:0 var(--radius-md) var(--radius-md) var(--radius-md); max-width:672px; margin:0 auto; padding:var(--space-5) var(--space-4) 60px; }
.acte .schedbtn.on{ background:var(--success); border-color:var(--success); color:#fff; }

/* "Register on Zoom" on a virtual session card: the text pill as a link, shown once the attendee
   has marked interest. Blue rather than the booking button's green so it reads as "go somewhere",
   not "done". */
.acte a.schedbtn.zoom{ display:inline-block; margin-top:8px; background:var(--blue); border-color:var(--blue); color:#fff; text-decoration:none; }

/* ---------- Tabs ---------- */
.acte .tabs{ display:flex; gap:var(--space-1); max-width:640px; margin:var(--space-4) auto 0; padding:0 var(--space-4); overflow-x:auto; }
.acte .tab{ appearance:none; border:1px solid var(--border); background:var(--surface); color:var(--text-dim); font:inherit; font-size:var(--text-sm); font-weight:700; padding:9px 13px; border-radius:9px 9px 0 0; cursor:pointer; border-bottom:none; white-space:nowrap; flex:none; }
.acte .tab[aria-selected="true"]{ background:var(--surface-2); color:var(--blue-ink); }

/* staff.html's own tab bar -- a different visual language than .tabs/.tab above (underline-active
   vs rounded pill-tab), used by neither attendee.html nor volunteer.html. Kept as its own named
   component per the plan's "don't unify names nobody asked to unify" rule. */
.acte .tabbar{ display:flex; gap:4px; margin-bottom:18px; border-bottom:1px solid var(--border); overflow-x:auto; -webkit-overflow-scrolling:touch; }
.acte .tabbar button{ font:inherit; font-size:13px; font-weight:700; color:var(--text-dim); background:none; border:none;
  padding:10px 4px 12px; margin-right:20px; cursor:pointer; border-bottom:2px solid transparent; }
.acte .tabbar button:hover{ color:var(--text); }
.acte .tabbar button.active{ color:var(--blue); border-bottom-color:var(--blue); }

/* ---------- Form inputs ---------- */
.acte label{ display:block; font-size:var(--text-2xs); font-weight:700; color:var(--text-dim); margin:0 0 5px; }
.acte .field{ margin-bottom:var(--space-4); }
.acte input, .acte select{ width:100%; font:inherit; font-size:var(--text-md); padding:10px var(--space-3); border-radius:var(--radius-sm); border:1px solid var(--border); background:var(--surface); color:var(--text); }
.acte .input-wrap{ position:relative; }
.acte .input-wrap input{ padding-right:30px; }
.acte .input-clear{ display:none; position:absolute; right:4px; top:50%; transform:translateY(-50%);
  background:none; border:none; color:var(--text-dim); font-size:15px; line-height:1; cursor:pointer; padding:6px; }
.acte .input-clear:hover{ color:var(--text); }
.acte .error{ display:none; color:var(--danger); font-size:var(--text-2xs); font-weight:700; margin-top:6px; }
.acte .error.show{ display:block; }
.acte input.bad{ border-color:var(--danger); }

/* ---------- Tables ---------- */
/* .table-wrap: a table's un-shrinkable content (long emails, paired action buttons) can need
   more width than a narrow phone's panel has. Without this, the table spills past its card's
   edge onto the page background instead of scrolling -- see commit 19fc9f1, confirmed live on
   a real device at 492px (table needed 546px, panel had 459px). */
.acte .table-wrap{ overflow-x:auto; -webkit-overflow-scrolling:touch; }
.acte table{ width:100%; border-collapse:collapse; font-size:var(--text-sm); margin-top:6px; }
.acte th{ text-align:left; font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--text-dim); padding:0 8px 8px; border-bottom:1px solid var(--border); }
.acte td{ padding:10px 8px; border-bottom:1px solid var(--border); vertical-align:middle; }
.acte tr:last-child td{ border-bottom:none; }
.acte tr.clickable{ cursor:pointer; }
.acte tr.clickable:hover td{ background:var(--tint); }
.acte .chev{ color:var(--text-dim); font-size:15px; text-align:right; }
.acte .edit-col{ width:76px; }
.acte .edit-col button + button{ margin-left:4px; }
.acte .edit-only{ display:none; }
.acte .panel.editing .edit-only{ display:inline-block; }

/* ---------- Pills / status badges ---------- */
.acte .pill{ font-size:10.5px; font-weight:800; padding:2px 7px; border-radius:var(--radius-pill); background:var(--tint); color:var(--blue-ink); }
.acte .pill.good{ background:#e7f7ef; color:#0f5132; }
.acte .pill.warn{ background:#fdf3e7; color:var(--warning); }

/* ---------- Progress bar ---------- */
.acte .bar{ background:var(--surface-2); border-radius:var(--radius-pill); height:6px; width:100%; overflow:hidden; }
.acte .bar > span{ display:block; height:100%; background:var(--blue); border-radius:var(--radius-pill); }

/* ---------- Notices / banners ---------- */
.acte .notice{ display:none; border-radius:var(--radius-sm); padding:14px var(--space-4); font-size:var(--text-sm); margin-top:var(--space-4); }
.acte .notice.show{ display:block; }
.acte .notice.ok{ background:#e7f7ef; border:1px solid #bfe6cf; color:#0f5132; }
.acte .notice.err{ background:#fdeceb; border:1px solid #f3c2bd; color:#7a271a; }
.acte .quota-banner{ display:flex; justify-content:space-between; background:var(--tint); border:1px solid var(--border); border-radius:var(--radius-sm); padding:var(--space-3) var(--space-4); margin-bottom:var(--space-4); gap:10px; flex-wrap:wrap; }
.acte .quota-banner .n{ font-size:var(--text-2xs); color:var(--text-dim); }
.acte .quota-banner .v{ font-size:var(--text-lg); font-weight:800; color:var(--blue-ink); }
.acte .empty-note{ font-size:var(--text-xs); color:var(--text-dim); background:var(--surface-2); border:1px solid var(--border); border-radius:var(--radius-sm); padding:var(--space-3) 14px; }

/* ---------- Typography ---------- */
.acte{ font-family: 'Montserrat', Arial, "Helvetica Neue", Helvetica, sans-serif; }
.acte h1{ font-size:var(--text-2xl); margin:0 0 4px; }
.acte h2{ font-size:16px; margin:0 0 4px; }
.acte h3{ font-size:13px; font-weight:800; margin:22px 0 12px; padding-top:18px; border-top:1px solid var(--border); }
.acte h3:first-child{ margin-top:0; padding-top:0; border-top:none; }
.acte .sub{ color:var(--text-dim); font-size:var(--text-sm); margin:0 0 18px; }

/* ---------- Icons ---------- */
/* Self-hosted SVG sprite (icons.svg, Lucide, ISC License — see icons-LICENSE.txt). Size and
   stroke color both inherit from context: 1em ties icon size to the surrounding text size,
   currentColor ties icon color to the surrounding text/button color, so no caller needs its
   own icon-sizing rule and a brand-color change (Appearance panel) recolors icons for free. */
.acte .acte-icon{ width:1em; height:1em; stroke:currentColor; stroke-width:2; fill:none;
  vertical-align:-0.125em; flex-shrink:0; }

/* ---------- Skeleton loaders ---------- */
/* Applied only to panels that wait on a fetch — never to static, already-rendered
   content. Dimensions must match what replaces them or the swap produces a layout
   jump, which reads worse than the empty state it's covering for. */
/* border-radius is deliberately NOT !important here: shapes like .photo-tile (10px) and
   .sched-card (8px) must win over this default so their skeleton matches their own corner
   radius instead of a generic one. Do not add !important to this property. */
.acte .skeleton{ position:relative; overflow:hidden; background:var(--surface-2) !important; border-radius:var(--radius-sm); color:transparent !important; }
.acte .skeleton::after{ content:''; position:absolute; inset:0; background:linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent); transform:translateX(-100%); animation:acte-shimmer 1.4s infinite; }
@keyframes acte-shimmer{ 100%{ transform:translateX(100%); } }
@media (prefers-reduced-motion: reduce){
  .acte .skeleton::after{ animation:none; display:none; }
}

/* ---------- Stat bar ---------- */
.acte .statbar{ display:flex; margin-bottom:22px; border:1px solid var(--border); border-radius:var(--radius-md); overflow:hidden; }
.acte .stat{ flex:1; padding:14px 16px; }
.acte .stat + .stat{ border-left:1px solid var(--border); }
.acte .stat .v{ font-size:24px; font-weight:800; line-height:1.1; }
.acte .stat .l{ font-size:10.5px; color:var(--text-dim); margin-top:3px; }
@media (max-width:640px){
  .acte .statbar{ flex-direction:column; }
  .acte .stat + .stat{ border-left:none; border-top:1px solid var(--border); }
}

/* ---------- Roster rows, link cards, back links ---------- */
.acte .roster-row{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:10px 0; border-bottom:1px solid var(--border); }
.acte .roster-row:last-child{ border-bottom:none; }
/* Selection column. The row checkboxes and the "select all" control share one fixed-width cell at
   the right edge, so every checkbox lands on the same vertical line however wide the name block
   beside it is. Previously the bare <input> was itself the flex child and picked up .print-only's
   display:inline-flex -- a replaced element as a flex container, which browsers lay out
   inconsistently, so the checkboxes drifted instead of pinning to the right edge. */
.acte .roster-check{ flex:0 0 40px; justify-content:flex-end; align-items:center; }
/* The element selector is load-bearing, not stylistic: this label also carries .print-only, which
   is declared later in this file, so at equal specificity its display:inline-flex would win and the
   label would shrink-wrap -- leaving justify-content:space-between nothing to spread across, and the
   checkbox stranded next to the text instead of out in the selection column. Adding `label` raises
   specificity above .print-only so the cascade no longer depends on source order. */
.acte label.roster-select-all{ display:flex; width:100%; align-items:center; justify-content:space-between;
  gap:6px; font-weight:400; font-size:var(--text-xs); color:var(--text-dim); margin-bottom:8px; }
.acte .backlink{ background:none; border:none; color:var(--blue-ink); font:inherit; font-weight:700; font-size:12.5px; cursor:pointer; padding:0 0 14px; }
.acte tr.link-row td{ padding:0 8px 14px; border-bottom:1px solid var(--border); }
.acte .link-card{ background:var(--tint); border:1px solid #b5d4f4; border-radius:var(--radius-md); padding:12px; }
.acte .link-card .cap{ display:block; font-size:11.5px; color:var(--blue-ink); margin-bottom:8px; }
.acte .link-card .row2{ display:flex; align-items:center; gap:8px; }
.acte .link-card input{ flex:1; font-size:12.5px; background:#fff; padding:7px 9px; border-radius:var(--radius-sm); border:1px solid var(--border); }
.acte .link-card button.primary{ padding:6px 12px; font-size:12px; white-space:nowrap; }

/* ---------- Print bar / print-only visibility ---------- */
.acte .print-bar{ display:flex; align-items:center; gap:12px; margin-top:10px; padding:10px 12px; background:var(--tint); border-radius:var(--radius-sm); }
.acte .print-bar-hint{ font-size:11px; color:var(--text-dim); flex:1; }
.acte .print-only{ display:none; }
@media (min-width:860px){ .acte .print-only{ display:inline-flex; } }

/* ---------- Preview banner (staff "View as" mode) ---------- */
.acte .preview-banner{ display:none; background:#fdf3e7; border-bottom:1px solid #f0d9b5; color:var(--warning);
  padding:10px 20px; text-align:center; font-size:12.5px; font-weight:700; }
.acte .preview-banner button{ margin-left:8px; }

/* ---------- Registrant detail view ---------- */
.acte .detail-pills{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:8px; }
.acte .detail-meta{ font-size:11.5px; color:var(--text-dim); margin-bottom:20px; }
.acte .detail-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:16px 20px; }

/* ---------- Dashboard ---------- */
.acte .dash-shell{ display:flex; gap:14px; }
.acte .dash-rail{ width:96px; flex-shrink:0; display:flex; flex-direction:column; gap:6px; }
.acte .dash-rail button{ font:inherit; font-size:11px; font-weight:700; text-align:center; color:var(--text-dim);
  background:var(--surface); border:1px solid var(--border); border-radius:7px; padding:9px 6px; cursor:pointer; }
.acte .dash-rail button.active{ background:var(--blue); color:#fff; border-color:var(--blue); }
.acte .dash-main{ flex:1; min-width:0; }
.acte .dash-grid{ display:grid; grid-template-columns:1.2fr .8fr 1fr; grid-auto-rows:auto; gap:8px; }
.acte .dash-tile{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:12px; }
.acte .dash-tile.hero{ grid-row:span 2; background:linear-gradient(160deg, var(--blue), var(--blue-ink)); color:#fff; border:none; display:flex; flex-direction:column; justify-content:center; }
.acte .dash-tile.hero .dash-bignum{ font-size:30px; color:#fff; }
.acte .dash-tile.hero .dash-label{ color:#cfe0f5; }
.acte .dash-tile.hero .dash-sub{ font-size:11px; color:#cfe0f5; margin-top:2px; }
.acte .dash-tile.becas .dash-bignum{ color:var(--red); font-size:22px; }
.acte .dash-tile.becas .dash-label{ color:var(--red); }
.acte .dash-tile.wide{ grid-column:span 2; }
.acte .dash-label{ font-size:9.5px; text-transform:uppercase; letter-spacing:.06em; font-weight:800; }
.acte .dash-label.dim{ color:var(--text-dim); }
.acte .dash-bignum{ font-weight:800; font-size:18px; }
.acte .dash-bignum.small{ font-size:13px; }
.acte .dash-role{ display:flex; gap:12px; align-items:center; }
.acte .dash-donut{ width:56px; height:56px; border-radius:50%; flex-shrink:0; display:flex; align-items:center; justify-content:center; }
.acte .dash-donut span{ width:36px; height:36px; border-radius:50%; background:var(--surface); display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:800; }
.acte .dash-legend{ font-size:10px; flex:1; }
.acte .dash-legend div{ display:flex; align-items:center; gap:5px; margin:3px 0; }
.acte .dash-legend i{ width:8px; height:8px; border-radius:2px; display:inline-block; }
.acte .dash-row{ display:flex; align-items:center; gap:8px; font-size:11px; margin:6px 0; }
.acte .dash-rname{ width:100px; flex-shrink:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.acte .dash-row .bar{ flex:1; }
.acte .dash-rval{ width:34px; text-align:right; font-weight:700; }
.acte .dash-hourbar{ display:flex; align-items:flex-end; gap:3px; height:44px; margin-top:8px; }
.acte .dash-hourbar div{ flex:1; background:var(--blue); border-radius:2px 2px 0 0; min-width:4px; }
@media (max-width:640px){
  .acte .dash-grid{ grid-template-columns:1fr 1fr; }
  .acte .dash-tile.hero{ grid-column:span 2; grid-row:span 1; }
}

/* ---------- Usher assignment + My Schedule (2026-11-06) ----------
   Shared by staff.html (staff My Schedule tab, the Usher section of the presenter detail) and
   presenter.html (presenter My Schedule tab). Mockup: https://claude.ai/artifact/WhGksccj43pDoAuNtdp7La */
.acte .avatar.md{ width:56px; height:56px; font-size:17px; }
.acte .avatar.sm{ width:40px; height:40px; font-size:13px; }
.acte .pin{ background:var(--tint); border:1px solid #b9d0f0; border-radius:12px; padding:16px; margin-bottom:14px; }
.acte .pin .pin-label{ display:flex; align-items:center; gap:6px; font-size:10.5px; font-weight:800; letter-spacing:.09em; text-transform:uppercase; color:var(--blue-ink); margin:0 0 10px; }
.acte .pin .pin-title{ margin:0 0 6px; font-size:16px; line-height:1.25; font-weight:800; }
.acte .pin .pin-meta{ display:flex; flex-wrap:wrap; gap:4px 12px; color:var(--text-dim); font-size:12.5px; font-weight:500; margin:0; }
.acte .pin .pin-sep{ height:1px; background:#b9d0f0; margin:14px 0; }
.acte .pin .pin-item + .pin-item{ margin-top:12px; }
.acte .person{ display:flex; gap:12px; align-items:center; min-width:0; }
.acte .person > div{ min-width:0; }
.acte .person .k{ font-size:11px; font-weight:700; color:var(--text-dim); text-transform:uppercase; letter-spacing:.06em; margin:0 0 1px; }
.acte .person b{ display:block; font-size:16px; line-height:1.2; overflow-wrap:anywhere; }
.acte .person .s{ font-size:12.5px; color:var(--text-dim); }
.acte .soft-note{ border:1.5px dashed #9db8dc; border-radius:10px; padding:12px; font-size:13px; color:var(--blue-ink); background:rgba(255,255,255,.55); }
.acte .sched-section-title{ margin:18px 2px 8px; font-size:12px; font-weight:800; letter-spacing:.07em; text-transform:uppercase; color:var(--text-dim); }
.acte .sched-day{ margin-top:14px; }
.acte .sched-day:first-child{ margin-top:0; }
/* staff: the Usher section of a presenter's detail */
.acte .usher-box{ border:1px solid var(--border); border-radius:10px; padding:14px; background:var(--bg); margin-top:16px; }
.acte .usher-box h4{ margin:0 0 2px; font-size:15px; font-weight:800; }
.acte .usher-day{ margin-top:12px; }
.acte .usher-day .daybar{ margin-bottom:6px; }
.acte .usher-day ul.usher-sessions{ margin:0 0 8px; padding-left:18px; font-size:12.5px; color:var(--text-dim); }
.acte .usher-empty{ border:1.5px dashed #b9c4cc; border-radius:10px; padding:12px; display:flex; gap:12px; align-items:center; justify-content:space-between; flex-wrap:wrap; background:var(--surface); }
.acte .usher-assigned{ display:flex; gap:12px; align-items:center; flex-wrap:wrap; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:10px 12px; }
.acte .usher-assigned .who{ flex:1 1 160px; min-width:0; }
.acte .usher-assigned .who b{ display:block; font-size:14px; overflow-wrap:anywhere; }
.acte .usher-search{ width:100%; border:1px solid var(--border); border-radius:var(--radius-sm); padding:11px 12px; font:inherit; font-size:14px; background:var(--surface); box-sizing:border-box; }
.acte .usher-list{ margin:10px 0 0; padding:0; list-style:none; display:grid; gap:8px; max-height:260px; overflow:auto; }
.acte .usher-list li{ display:flex; gap:10px; align-items:center; background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:8px 10px; }
.acte .usher-list li.taken{ opacity:.65; }
.acte .usher-list .nm{ flex:1; min-width:0; }
.acte .usher-list .nm b{ display:block; font-size:13.5px; overflow-wrap:anywhere; }
.acte .usher-list .nm span{ font-size:11.5px; color:var(--text-dim); }
.acte .pill.off{ background:var(--surface-2); color:var(--text-dim); }
.acte button.ghost.danger{ color:var(--danger); border-color:#e7b9b3; }

/* ---------- Loading skeletons, style A (Kelvin, 2026-11-06) ----------
   The shimmer is the .skeleton rule above; skeleton.js builds the shapes. .skel-group is invisible for the
   first 200 ms (a zero-length animation whose delay holds it at visibility:hidden), so a load that finishes
   quickly never flashes a skeleton, with no timer to cancel: the real content just replaces it. */
@keyframes acte-skel-reveal{ from{ visibility:hidden; } }
.acte .skel-group{ animation:acte-skel-reveal 0s linear .2s backwards; }
.acte .skel-sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
.acte .skel-lines{ display:grid; gap:8px; }
/* inputs cannot hold the ::after shimmer: same colours as a background sweep (acteSkel.fields adds the class after 200 ms) */
@keyframes acte-skel-field{ 100%{ background-position:-100% 0; } }
.acte input.skel-field, .acte select.skel-field{ background:linear-gradient(90deg, var(--surface-2) 30%, #fff 50%, var(--surface-2) 70%) 100% 0 / 200% 100% !important; color:transparent !important; border-color:var(--surface-2) !important; animation:acte-skel-field 1.4s linear infinite; }
.acte input.skel-field::placeholder{ color:transparent !important; }
@media (prefers-reduced-motion: reduce){
  .acte input.skel-field, .acte select.skel-field{ animation:none; background:var(--surface-2) !important; }
}
.acte .is-loading :is(.flow-kpi, .flow-chart){ background:linear-gradient(90deg, var(--surface-2) 30%, #fff 50%, var(--surface-2) 70%) 100% 0 / 200% 100%; color:transparent !important; border-radius:6px; animation:acte-skel-field 1.4s linear infinite; }
.acte .is-loading .flow-kpi{ width:55%; }
.acte .is-loading .flow-chart{ min-height:110px; }
@media (prefers-reduced-motion: reduce){ .acte .is-loading :is(.flow-kpi, .flow-chart){ animation:none; background:var(--surface-2); } }
