:root {
  color-scheme: dark light;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --font-size-0: 0.875rem;
  --font-size-1: 1rem;
  --font-size-2: 1.25rem;
  --font-size-3: 1.5rem;
  --font-size-4: 2rem;
  --r-l: 26px;
  --r-m: 18px;
  --r-s: 12px;
  --r-pill: 999px;
  --radius: var(--r-s);
  --blur: 18px;
  --motion-feedback: 120ms;
  --motion-panel: 180ms;
  --motion-max: 240ms;
  --motion-ambient-shimmer: 1600ms;
  --motion-ambient-drift: 18s;
  --bg: #0f1226;
  --bg2: #141833;
  --surf: #232845;
  --surf2: #2a2f52;
  --glass: rgba(255,255,255,.06);
  --glass2: rgba(255,255,255,.1);
  --veil: rgba(35,40,69,.82);
  --line: rgba(255,255,255,.12);
  --line2: rgba(255,255,255,.22);
  --edge: #7c80a8;
  --ink: #f6f4ff;
  --ink2: #cfd0ea;
  --ink3: #a2a6c8;
  --gold: #f7d774;
  --gold-t: #f7d774;
  --gold-fill-from: #fbe29a;
  --gold-fill-to: #f5c451;
  --on-gold: #1a1630;
  --focus: #f7d774;
  --song: #ff8cc0;
  --sermon: #b39bff;
  --bible: #5fe3b8;
  --media: #6fd0ff;
  --group: #ffa877;
  --danger: #ff8a8a;
  --warning: #fbbf24;
  --complete: #4ade80;
  --offline: #fbbf24;
  --offline-bg: rgba(251,191,36,.16);
  --glow: rgba(247,215,116,.16);
  --glow2: rgba(247,215,116,.5);
  --hi: rgba(255,255,255,.14);
  --b1: rgba(124,92,255,.5);
  --b2: rgba(40,200,170,.36);
  --b3: rgba(255,110,170,.36);
  --b4: rgba(247,200,90,.3);
  --season-advent: #a78bfa;
  --season-christmas: #fff0b3;
  --season-lent: #a78bfa;
  --season-easter: #fff0b3;
  --season-pentecost: #fb7185;
  --ring1: rgba(255,255,255,.34);
  --ring2: rgba(255,255,255,.06);
  --ring3: rgba(247,215,116,.45);
  --shadow: 0 24px 60px -24px rgba(5,6,20,.7);
  --gold-fill: linear-gradient(135deg, var(--gold-fill-from), var(--gold-fill-to));
  --color-surface: var(--bg);
  --color-surface-raised: var(--surf);
  --color-text: var(--ink);
  --color-text-muted: var(--ink2);
  --color-accent: var(--gold);
  --color-accent-text: var(--on-gold);
  --color-danger: var(--danger);
  --color-border: var(--line2);
  --color-warning: var(--warning);
  --color-complete: var(--complete);
  --color-offline: var(--offline);
  --font-tamil: "Noto Sans Tamil", "Tamil MN", "Tamil Sangam MN", "Latha", "Nirmala UI", sans-serif;
  --font-latin: system-ui, sans-serif;
  --font-display: "Bricolage Grotesque", "Catamaran", system-ui, sans-serif;
  --font-body: "Catamaran", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --focus-ring: 2px solid var(--focus);
  --canvas-guide: rgb(255 255 255 / 40%);
  --canvas-handle: #fff;
  --brand-ground: #171b2e;
  --brand-cross: #f5d98a;
  --church-plate: #fff;
  --screen-ground: #0f1226;
  --screen-ink: #f6f4ff;
  --screen-light: rgba(247,215,116,.5);
  --mask-fill: #000;
  --canvas-ink: #111;
  --canvas-paper: #fff;
  --canvas-checker: #d0d0d0;
  --canvas-safe-area: #c62828;
  --canvas-box-edge: rgb(0 0 0 / 55%);
  --canvas-box-fill: rgb(255 255 255 / 45%);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --bg: #f7f3ea; --bg2: #efe8f3; --surf: #ffffff; --surf2: #ece6f2;
    --glass: rgba(255,255,255,.62); --glass2: rgba(255,255,255,.8); --veil: rgba(255,255,255,.82);
    --line: rgba(30,34,64,.12); --line2: rgba(30,34,64,.2); --edge: #7a7f9c;
    --ink: #1e2240; --ink2: #474c6e; --ink3: #5d6285;
    --gold: #d9a93a; --gold-t: #7a5a10; --gold-fill-from: #f0cf6e; --gold-fill-to: #e0b44a; --on-gold: #1e2240; --focus: #7a5a10;
    --song: #a01f60; --sermon: #5b3fd6; --bible: #0a6449; --media: #09598c; --group: #963e0e;
    --danger: #b3261e; --warning: #92400e; --complete: #166534; --offline: #92400e; --offline-bg: rgba(146,64,14,.12);
    --glow: rgba(217,169,58,.2); --glow2: rgba(217,169,58,.5); --hi: rgba(255,255,255,.9);
    --b1: rgba(150,120,255,.3); --b2: rgba(60,200,170,.24); --b3: rgba(255,140,180,.26); --b4: rgba(247,200,90,.32);
    --season-advent: #6d28d9; --season-christmas: #a16207; --season-lent: #6d28d9; --season-easter: #a16207;
    --season-pentecost: #be123c;
    --ring1: rgba(30,34,64,.16); --ring2: rgba(30,34,64,.06); --ring3: rgba(217,169,58,.55); --shadow: 0 24px 50px -28px rgba(60,40,120,.35);
  }
}
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f7f3ea; --bg2: #efe8f3; --surf: #ffffff; --surf2: #ece6f2;
  --glass: rgba(255,255,255,.62); --glass2: rgba(255,255,255,.8); --veil: rgba(255,255,255,.82);
  --line: rgba(30,34,64,.12); --line2: rgba(30,34,64,.2); --edge: #7a7f9c;
  --ink: #1e2240; --ink2: #474c6e; --ink3: #5d6285;
  --gold: #d9a93a; --gold-t: #7a5a10; --gold-fill-from: #f0cf6e; --gold-fill-to: #e0b44a; --on-gold: #1e2240; --focus: #7a5a10;
  --song: #a01f60; --sermon: #5b3fd6; --bible: #0a6449; --media: #09598c; --group: #963e0e;
  --danger: #b3261e; --warning: #92400e; --complete: #166534; --offline: #92400e; --offline-bg: rgba(146,64,14,.12);
  --glow: rgba(217,169,58,.2); --glow2: rgba(217,169,58,.5); --hi: rgba(255,255,255,.9);
  --b1: rgba(150,120,255,.3); --b2: rgba(60,200,170,.24); --b3: rgba(255,140,180,.26); --b4: rgba(247,200,90,.32);
  --season-advent: #6d28d9; --season-christmas: #a16207; --season-lent: #6d28d9; --season-easter: #a16207;
  --season-pentecost: #be123c;
  --ring1: rgba(30,34,64,.16); --ring2: rgba(30,34,64,.06); --ring3: rgba(217,169,58,.55); --shadow: 0 24px 50px -28px rgba(60,40,120,.35);
}
:root[data-theme="dark"] { color-scheme: dark; }
/* Aurora interface faces, served from this origin; OFL texts in fonts/. Slides keep the system's own faces. */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-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: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-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: "Catamaran";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/catamaran-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: "Catamaran";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/catamaran-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: "Catamaran";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/catamaran-tamil.woff2") format("woff2");
  unicode-range: U+0964-0965, U+0B82-0BFA, U+200C-200D, U+20B9, U+25CC;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font: 1rem/1.5 var(--font-body);
  display: block;
  overflow-wrap: anywhere;
  background: var(--color-surface);
  color: var(--color-text);
}
#app { display: flex; flex-direction: column; block-size: 100dvh; --sidebar-rail: 4.5rem; --sidebar-wide: 15rem; }
main { flex: 1; min-inline-size: 0; min-block-size: 0; max-inline-size: 40rem; padding: var(--space-6); overflow-y: auto; scrollbar-gutter: stable; }
button { font: inherit; max-inline-size: 100%; }
h1, h2, h3, .app-name { font-family: var(--font-display); letter-spacing: -0.01em; }
time, .tabular { font-variant-numeric: tabular-nums; }
.icon { inline-size: 1.25em; block-size: 1.25em; flex: none; fill: currentColor; vertical-align: -0.2em; }
.icon[data-tone="song"] { fill: var(--song); }
.icon[data-tone="sermon"] { fill: var(--sermon); }
.icon[data-tone="bible"] { fill: var(--bible); }
.icon[data-tone="media"] { fill: var(--media); }
.icon[data-tone="group"] { fill: var(--group); }
.brand-mark { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--ink); font-family: var(--font-display); font-weight: 700; }
.brand-mark-symbol { inline-size: 1.75em; block-size: 1.75em; flex: none; }
.brand-mark-ground { fill: var(--brand-ground); }
.brand-mark-cross { fill: var(--brand-cross); }
/* The church's mark (`church-mark.tsx`): its logo on a white plate in both themes, so a dark logo on a clear ground
   stays visible on navy, and its name in the display face. HolyDeck's colours never change for it. */
.church-mark { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-inline-size: 0; margin: 0; }
.church-mark-logo {
  box-sizing: border-box;
  block-size: 2.5rem;
  inline-size: auto;
  max-inline-size: 100%;
  min-inline-size: 0;
  padding: var(--space-1);
  object-fit: contain;
  background: var(--church-plate);
  border: 1px solid var(--line2);
  border-radius: var(--r-s);
}
.church-mark-name { min-inline-size: 0; color: var(--ink); font-family: var(--font-display); font-weight: 600; overflow-wrap: anywhere; }
/* The top of the sign-in card: the church's mark, then the HolyDeck mark; the Church section previews the card. */
.sign-in-marks { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); margin-block-end: var(--space-4); }
.church-mark-card .church-mark-logo { block-size: 4rem; }
.church-mark-card .church-mark-name { font-size: var(--font-size-2); }
.sign-in-preview { margin: var(--space-5) 0 0; }
.sign-in-preview-card { max-inline-size: 24rem; }
.sign-in-preview-title { margin: 0; font-family: var(--font-display); font-size: var(--font-size-3); font-weight: 700; }
/* The colour a logo suggests, drawn as a dot beside its value; the colour itself is the church's, not a design colour. */
.accent-swatch { display: inline-block; inline-size: 1em; block-size: 1em; margin-inline-end: var(--space-2); border: 1px solid var(--line2); border-radius: var(--r-pill); vertical-align: middle; }
:where(a) { color: currentColor; }
/* Aurora base elements. `:where()` keeps them at zero weight, so a component's own class rule wins. */
:where(button, .button) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding: 0 var(--space-4);
  border: 1px solid var(--line2);
  border-radius: var(--r-pill);
  background: var(--glass2);
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
:where(button[type="submit"], .button-primary) {
  border-color: transparent;
  background: var(--gold-fill);
  color: var(--on-gold);
  box-shadow: 0 8px 24px -10px var(--glow2);
}
:where(.button-danger) { border-color: var(--danger); color: var(--danger); }
:where(.button-quiet, .link-button) { border-color: transparent; background: transparent; }
:where(.icon-button) { padding: 0; aspect-ratio: 1; }
:where(button:disabled, button[aria-disabled="true"]) { cursor: not-allowed; opacity: 0.55; box-shadow: none; }
/* A main action that cannot be used yet drops its gold, so it reads as off rather than as a dim gold button. */
:where(button[type="submit"]:disabled, button[type="submit"][aria-disabled="true"], .button-primary:disabled, .button-primary[aria-disabled="true"]) {
  border-color: var(--line2);
  background: var(--glass);
  color: var(--ink2);
}
/* A field's edge is how it is found, so it takes the checked 3:1 `--edge`; 16px keeps a phone from zooming. */
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"]), select, textarea) {
  max-inline-size: 100%;
  min-block-size: 46px;
  padding: 0 var(--space-3);
  border: 1px solid var(--edge);
  border-radius: var(--r-m);
  background: var(--glass2);
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
}
:where(textarea) { padding-block: var(--space-2); }
:where(input, textarea)::placeholder { color: var(--ink3); opacity: 1; }
:where([aria-invalid="true"]) { border-color: var(--danger); }
/* A checkbox or radio button is drawn in a field's ground and edge; checked, it takes the main action's gold with a
   mark in the ink that reads on gold. The mark is clipped, not turned, so reduced motion leaves it whole. */
:where(input[type="checkbox"], input[type="radio"]) {
  appearance: none;
  display: inline-grid;
  place-content: center;
  flex-shrink: 0;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  border: 2px solid var(--edge);
  border-radius: calc(var(--r-s) / 2);
  background: var(--glass2);
  cursor: pointer;
}
:where(input[type="radio"]) { border-radius: 50%; }
:where(input[type="checkbox"]:checked, input[type="radio"]:checked) { border-color: var(--focus); background: var(--gold-fill); }
:where(input[type="checkbox"]:checked, input[type="radio"]:checked)::before { content: ""; inline-size: 0.75rem; block-size: 0.75rem; background: var(--on-gold); }
:where(input[type="checkbox"]:checked)::before { clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%); }
:where(input[type="radio"]:checked)::before { inline-size: 0.5rem; block-size: 0.5rem; border-radius: 50%; }
:where(input[type="checkbox"]:disabled, input[type="radio"]:disabled) { cursor: not-allowed; opacity: 0.55; }
/* Forced colours hand both back to the system's own drawing. */
@media (forced-colors: active) {
  :where(input[type="checkbox"], input[type="radio"]) { appearance: auto; }
  :where(input[type="checkbox"]:checked, input[type="radio"]:checked)::before { content: none; }
}
:where(input[type="range"]) { accent-color: var(--focus); }
:where(input, select, textarea):focus-visible { box-shadow: 0 0 0 4px var(--glow); }
/* A text field or list a pointer just pressed shows its focus in its edge only; Tab brings the ring back (see
   input-modality.ts). Checkboxes, radios and sliders keep theirs: arrow keys move them without a Tab, and a checked
   one already wears that edge. */
:root[data-input="pointer"] :where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"]), select, textarea):focus-visible {
  outline: none;
  box-shadow: none;
  border-color: var(--focus);
}
/* Tabs are glass pills; the chosen one is filled gold like the main action. */
:where([role="tablist"]) { display: flex; flex-wrap: wrap; gap: var(--space-2); }
:where([role="tab"]) { border-color: var(--line); background: var(--glass); color: var(--ink2); }
:where([role="tab"][aria-selected="true"]) {
  border-color: transparent;
  background: var(--gold-fill);
  color: var(--on-gold);
  box-shadow: 0 8px 22px -10px var(--glow2);
}
.glass-panel,
.card {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--glass);
  box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(140%);
  backdrop-filter: blur(var(--blur)) saturate(140%);
}
.card { padding: var(--space-5); border-color: transparent; }
/* The light ring is a 1px gradient border cut out of a mask, which reads only alpha (`--mask-fill`). */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(145deg, var(--ring1), var(--ring2) 45%, var(--ring3));
  -webkit-mask: linear-gradient(var(--mask-fill) 0 0) content-box, linear-gradient(var(--mask-fill) 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}
/* Pills use pairs in `CONTRAST_PAIRS`, so they are checked for AA. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px 10px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink2);
  font-size: var(--font-size-0);
  font-weight: 600;
  white-space: nowrap;
}
.pill[data-tone="gold"] { background: color-mix(in srgb, var(--gold) 16%, transparent); color: var(--gold-t); }
.pill[data-tone="song"] { background: color-mix(in srgb, var(--song) 14%, transparent); color: var(--song); }
.pill[data-tone="sermon"] { background: color-mix(in srgb, var(--sermon) 14%, transparent); color: var(--sermon); }
.pill[data-tone="bible"] { background: color-mix(in srgb, var(--bible) 14%, transparent); color: var(--bible); }
.pill[data-tone="media"] { background: color-mix(in srgb, var(--media) 14%, transparent); color: var(--media); }
.pill[data-tone="group"] { background: color-mix(in srgb, var(--group) 14%, transparent); color: var(--group); }
.pill[data-state="danger"] { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.pill[data-state="warning"] { background: color-mix(in srgb, var(--warning) 14%, transparent); color: var(--warning); }
.pill[data-state="complete"] { background: color-mix(in srgb, var(--complete) 14%, transparent); color: var(--complete); }
.pill[data-state="offline"] { background: var(--offline-bg); color: var(--offline); }
:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
/* A page change moves focus to main for screen readers, which is no reason for a ring round the whole page after a
   click; after keyboard use the router leaves main unmarked and the ring shows where focus went. */
#main[data-route-focus]:is(:focus, :focus-visible) { outline: none; box-shadow: none; }

.workspace { display: grid; gap: 16px; }
.workspace-panel { display: none; min-inline-size: 0; }
#order,
.workspace-panel:target,
.workspace-panel:has(:target) { display: block; }

.workspace-tabs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  position: sticky;
  inset-block-end: 0;
  background: var(--color-surface);
  padding: 4px;
  padding-block-end: max(4px, env(safe-area-inset-bottom));
}
.workspace-tabs a { display: flex; align-items: center; justify-content: center; text-align: center; }
body:not(:has(.workspace-panel:target, .workspace-panel :target)) .workspace-tabs a[href="#order"],
body:has(#order:target, #order :target) .workspace-tabs a[href="#order"],
body:has(#editor-preview:target, #editor-preview :target) .workspace-tabs a[href="#editor-preview"],
body:has(#library:target) .workspace-tabs a[href="#library"],
body:has(#properties:target, #properties :target) .workspace-tabs a[href="#properties"] {
  font-weight: bold;
}

#preview-row:not([hidden]),
.live-actions { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
#preview-row > span { min-inline-size: 0; }
/* The Next frame is a button to tap, but it is scaled to its pane like the Now frame, so the button spans the pane. */
.control-preview-next-button { display: block; inline-size: 100%; padding: 0; border-radius: var(--r-s); overflow: hidden; }
.skip-links ul { display: flex; flex-wrap: wrap; gap: 16px; list-style: none; padding: 0; }

.service-workspace { display: grid; gap: 16px; }
.service-workspace-tabs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  position: sticky;
  bottom: 0;
  background: var(--color-surface);
  padding: 4px;
  padding-bottom: max(4px, env(safe-area-inset-bottom));
}
/* On a phone the workspace tabs are set smaller and keep each name whole on one line; when a language's names are
   too wide for the screen the row scrolls sideways instead of breaking a name between its letters. */
@media (width < 600px) {
  :is(.workspace-tabs, .service-workspace-tabs) {
    grid-template-columns: repeat(4, minmax(max-content, 1fr));
    gap: var(--space-1);
    overflow-x: auto;
    scrollbar-width: thin;
  }
  .service-workspace-tabs > [role="tab"] { padding-inline: var(--space-3); font-size: var(--font-size-0); }
}

@media (min-width: 1280px) {
  .service-workspace { grid-template-columns: 264px minmax(480px, 1fr) 336px; align-items: start; }
}

.order-panel { display: grid; gap: var(--space-4); }
.order-panel-header { display: flex; justify-content: flex-end; }
.bulk-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  position: sticky;
  bottom: 0;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-2);
}
.order-section { display: grid; gap: var(--space-2); }
/* Rows wrap between their controls rather than squeezing each one letter by letter: `break-word` keeps a
   word's width as the smallest a control may get, where the body's `anywhere` would allow one letter. */
.order-section-header { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.order-item { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); position: relative; }
:is(.order-section-header, .order-item) > * { overflow-wrap: break-word; }
.order-item-actions { position: relative; margin-inline-start: auto; }
.is-disabled { color: var(--color-text-muted); }
.order-item-pending {
  inline-size: 12px;
  block-size: 12px;
  border-radius: 50%;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-accent);
  animation: order-item-pending-spin var(--motion-max) linear infinite;
}
@keyframes order-item-pending-spin {
  to { transform: rotate(360deg); }
}

@media (width < 1280px) {
  .workspace:has(> .workspace-panel:not(#order):target, > .workspace-panel:not(#order) :target) > #order {
    display: none;
  }
}

@media (min-width: 1280px) {
  #app { block-size: auto; }
  main { overflow: visible; }
  html:has(#main) { scrollbar-gutter: stable; }
  main:has(.workspace, .service-workspace) { max-inline-size: none; }
  .workspace { grid-template-columns: 264px minmax(480px, 1fr) 336px; align-items: start; }
  .workspace > :is(#order, #editor-preview, #properties) { display: block; }
  .workspace > #library,
  .workspace-tabs { display: none; }
  .live-actions { grid-template-columns: repeat(2, minmax(96px, 1fr)); }
}

.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.workspace-main { max-width: none; }
.form-field { display: grid; gap: var(--space-1); margin-block-end: var(--space-3); }
.form-field > label { color: var(--ink2); font-size: var(--font-size-0); font-weight: 600; }

/* JSX drops the space between a label's words and a control on the next line, so these keep them apart: a label that
   wraps its control lays both out with a gap, and one right before its control keeps its distance. A stacked form
   field and a class that lays out its own labels keep theirs. */
:where(label:has(> :is(select, textarea, input:not([type="checkbox"], [type="radio"], [type="hidden"])))) {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--space-2);
  row-gap: var(--space-1);
}
:where(label:has(> :is(input[type="checkbox"], input[type="radio"]))) {
  display: inline-flex;
  align-items: center;
  column-gap: var(--space-2);
}
@media (width < 600px) {
  :where(label:has(> :is(input[type="checkbox"], input[type="radio"]))) { min-block-size: 44px; }
}
:where(label[for]:has(+ :is(input, select, textarea)):not(.form-field > label)) { margin-inline-end: var(--space-2); }
.library-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }
.library-filter { display: inline-flex; align-items: center; }
.form-hint { margin: 0; color: var(--ink2); font-size: var(--font-size-0); }
.form-error { color: var(--color-danger); }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* The browser's own boxes: a fieldset loses its grooved frame and padding so a group of fields reads as part of the
   page, and the colour well and the file picker are drawn in the field ground, a fingertip high. */
:where(fieldset) { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
:where(legend) { padding: 0 0 var(--space-2); font-weight: 600; }
:where(input[type="color"]) {
  inline-size: 4rem;
  min-block-size: 44px;
  padding: var(--space-1);
  border: 1px solid var(--edge);
  border-radius: var(--r-m);
  background: var(--glass2);
  cursor: pointer;
}
:where(input[type="file"]) { max-inline-size: 100%; min-block-size: 44px; color: var(--ink2); }
:where(input[type="file"])::file-selector-button {
  min-block-size: 44px;
  margin-inline-end: var(--space-3);
  padding: 0 var(--space-4);
  border: 1px solid var(--line2);
  border-radius: var(--r-pill);
  background: var(--glass2);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

/* The account and administration pages (`main[data-page="settings"]`, app-shell.tsx): the page grows with the screen
   for its tables and lists, a paragraph kept to a readable line. Each form is a glass panel at a comfortable width,
   its groups under display-face legends; a form outside these pages takes the same panel with `.form-panel`. From
   1440px the panels sit side by side. */
main[data-page="settings"] { max-inline-size: 120rem; }
main[data-page="settings"] p { max-inline-size: 65ch; }
/* A page of records elsewhere (a readiness checklist, a revision history) grows with the screen too. */
main:has(.record-list) { max-inline-size: 120rem; }
:is(main[data-page="settings"] form, .form-panel) {
  display: grid;
  gap: var(--space-4);
  max-inline-size: 36rem;
  margin-block: var(--space-4) var(--space-6);
  padding: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--glass);
  box-shadow: var(--shadow);
}
:is(main[data-page="settings"] form, .form-panel) :is(h2, h3, p, .form-field) { margin: 0; }
:is(main[data-page="settings"] form, .form-panel) :is(.form-field, label) > :is(input:not([type="checkbox"], [type="radio"], [type="color"]), select, textarea) { inline-size: 100%; }
:is(main[data-page="settings"] form, .form-panel) :is(button, .button) { justify-self: start; }
@media (min-width: 1440px) {
  main[data-page="settings"] form {
    display: inline-grid;
    inline-size: min(100%, 36rem);
    margin-inline-end: var(--space-6);
    vertical-align: top;
  }
}
:is(main[data-page="settings"] form, .form-panel) fieldset { display: grid; gap: var(--space-3); }
:is(main[data-page="settings"] form, .form-panel) fieldset + fieldset { padding-block-start: var(--space-4); border-block-start: 1px solid var(--line); }
:is(main[data-page="settings"] form, .form-panel) fieldset fieldset { padding-inline-start: var(--space-4); border-inline-start: 2px solid var(--line); }
:is(main[data-page="settings"] form, .form-panel) legend {
  padding: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--font-size-2);
  font-weight: 600;
}
:is(main[data-page="settings"] form, .form-panel) fieldset fieldset > legend { color: var(--ink2); font-family: var(--font-body); font-size: var(--font-size-0); }
main[data-page="settings"] label:has(> input[type="checkbox"]) { display: flex; align-items: center; gap: var(--space-2); min-block-size: 44px; }
:is(main[data-page="settings"] form, .form-panel) label:has(> :is(select, textarea)) { display: grid; gap: var(--space-1); }
/* A summary on any page lines its names up beside their values in even figures. */
main dl {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  margin-block: var(--space-4);
}
main dt { color: var(--ink2); }
main dd { margin: 0; font-variant-numeric: tabular-nums; }
/* A page's filters sit in a row of even columns that wraps on a narrow screen. */
.filter-bar {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
  gap: var(--space-3) var(--space-4);
  max-inline-size: 48rem;
  margin-block: var(--space-4);
}
.filter-bar .form-field { margin: 0; }

/* The Security page's passkeys: each a glass row, its name over one quiet line of dates and its Rename and Remove at
   the end, wrapping under the words where the row is narrow. */
.passkey-list { display: grid; gap: var(--space-3); max-inline-size: 48rem; margin: var(--space-4) 0; padding: 0; list-style: none; }
.passkey-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--glass);
  box-shadow: var(--shadow);
}
.passkey-row-text { display: grid; flex: 1 1 16rem; gap: var(--space-1); min-inline-size: 0; }
.passkey-row-name { font-weight: 600; overflow-wrap: anywhere; }
.passkey-row-meta { color: var(--ink2); font-size: var(--font-size-0); }
.passkey-row-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.passkey-row-edit { display: grid; flex: 1 1 100%; gap: var(--space-3); max-inline-size: 36rem; }
.passkey-row-edit .form-field { margin: 0; }
.passkey-row-edit .form-field > input { inline-size: 100%; }
/* Recovery codes are read off one by one, so they sit in even columns of the system's fixed-width face. */
.recovery-codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: var(--space-2) var(--space-4);
  max-inline-size: 36rem;
  margin: var(--space-3) 0;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--glass);
  font-family: var(--font-mono);
  list-style: none;
}
.security-slots { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0; padding: 0; list-style: none; }
main[data-page="settings"] form .notification-categories {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 11rem), 1fr));
  gap: 0 var(--space-4);
}

/* A table on a glass panel that scrolls sideways on its own, so the page never does and no word is cut to fit; the
   long audit and job logs sit in compact rows. */
.table-scroll {
  overflow-x: auto;
  margin-block: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--glass);
}
.table-scroll > table { inline-size: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.table-scroll caption { padding: var(--space-3) var(--space-4) var(--space-2); font-weight: 600; text-align: start; }
.table-scroll :is(th, td) {
  padding: var(--space-2) var(--space-3);
  border-block-end: 1px solid var(--line);
  text-align: start;
  vertical-align: middle;
  overflow-wrap: normal;
  white-space: nowrap;
}
/* A cell stays on one line (a name, a time, an id), so the panel scrolls instead of breaking it; a cell of prose (an
   error, a detail) wraps between words at a readable width. */
.table-scroll .table-prose { min-inline-size: 16rem; white-space: normal; overflow-wrap: anywhere; }
.table-scroll .truncated-text { min-inline-size: 10rem; }
.table-scroll td > :is(a, button) + :is(a, button) { margin-inline-start: var(--space-2); }
/* The narrow screen lets a button break anywhere; in a table that would squeeze its column instead of scrolling. */
.table-scroll :is(th, td) button { overflow-wrap: normal; }
.table-scroll tbody tr:last-child > * { border-block-end: 0; }
.table-scroll thead th {
  color: var(--ink2);
  font-size: var(--font-size-0);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.table-scroll tbody th { font-weight: 600; }
.table-scroll fieldset { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
:is(.audit-table, .jobs-table) { font-size: var(--font-size-0); line-height: 1.35; }
:is(.audit-table, .jobs-table) :is(th, td) { padding: var(--space-1) var(--space-2); }
/* A handle is quiet and never splits. */
.audit-handle { color: var(--ink2); white-space: nowrap; }

/* A list of records (a readiness check, a revision, a scheduled job, the dashboard's recent services): glass rows
   without bullets, in as many columns as the screen has room for. A readiness check shows its severity on the
   row's start edge as well as in words. */
:is(.record-list, [aria-labelledby="dashboard-recent-heading"] > ul) {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: var(--space-2) var(--space-4);
  margin: var(--space-3) 0;
  padding: 0;
  list-style: none;
}
:is(.record-list, [aria-labelledby="dashboard-recent-heading"] > ul) > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  min-inline-size: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--glass);
}
.record-list > li > p { flex-basis: 100%; margin: 0; color: var(--ink2); font-size: var(--font-size-0); }
.record-list > li[data-severity="blocker"] { border-inline-start: 4px solid var(--danger); }
.record-list > li[data-severity="warning"] { border-inline-start: 4px solid var(--warning); }
.record-list > li[data-severity="complete"] { border-inline-start: 4px solid var(--complete); }
/* An alert says something went wrong, so it reads in the danger ink; the output screens keep their theme's colours. */
:where([role="alert"]:not(.output-surface *)) { color: var(--danger); }

/* Off-screen until focused, so a sighted keyboard user sees the link land exactly where Tab put it. */
.skip-link {
  position: absolute;
  inset-inline-start: -9999px;
  inset-block-start: 0;
}
.skip-link:focus {
  position: static;
  display: inline-block;
  z-index: 1;
}

/* WCAG-style touch target minimums: 44px generally, 56px for the live transport. */
button, a { min-inline-size: 44px; min-block-size: 44px; }
#live-controls button { min-inline-size: 96px; min-block-size: 56px; }

.app-content { display: flex; flex: 1; flex-direction: column; min-inline-size: 0; min-block-size: 0; }
#app > .skip-link:focus {
  position: absolute;
  inset-inline-start: var(--space-2);
  inset-block-start: var(--space-2);
  z-index: 30;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-3);
  border-radius: var(--r-pill);
  background: var(--surf);
  color: var(--ink);
}
.app-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-4);
  background: var(--bg2);
  border-block-end: 1px solid var(--line2);
}
.app-bar-head { display: flex; align-items: center; gap: var(--space-2); }
.app-name { margin: 0; font-weight: 700; font-size: var(--font-size-2); }
.sidebar-toggle { display: none; padding: 0; }
.qr-code { display: block; inline-size: min(16rem, 100%); block-size: auto; }
.app-version { color: var(--color-text-muted); font-size: var(--font-size-0); }
footer.app-version { margin-block: var(--space-2); }
.app-nav ul { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.app-nav a,
.app-admin-link,
.notification-bell > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding: 0 var(--space-3);
  border-radius: var(--r-s);
  color: var(--ink2);
  text-decoration: none;
}
.app-nav a[aria-current="page"],
.app-admin-link[aria-current="page"] { background: var(--gold-fill); color: var(--on-gold); }
.app-nav a[aria-disabled="true"] { color: var(--color-text-muted); cursor: not-allowed; }
.app-subnav ul { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: var(--space-4) var(--space-6) 0; list-style: none; }
.app-subnav a { display: inline-flex; align-items: center; padding: 0 var(--space-3); border: 1px solid var(--line2); border-radius: var(--r-pill); text-decoration: none; }
.app-subnav a[aria-current="page"] { border-color: transparent; background: var(--gold-fill); color: var(--on-gold); }
/* Below a laptop's width the section links stay on one row that scrolls sideways, so they never push the page down;
   the shell scrolls the current one into the middle of the row. */
@media (width < 1024px) {
  .app-subnav ul { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: thin; }
  .app-subnav li { flex: none; }
  .app-subnav a { white-space: nowrap; }
}
/* Search (`palette-opener.tsx`): a quiet pill under the mark with the shortcut's key cap at its far end; the
   magnifying glass alone in the rail and at the start of the phone's buttons. A key cap (`key-hint.tsx`) is
   decoration in the system monospace face; inside `.has-key-hint` it shows over the control's corner on hover
   and keyboard focus only: buttons show their key on hover. */
.palette-opener { justify-content: flex-start; padding: 0 var(--space-3); color: var(--ink2); font-weight: 400; }
.palette-opener .key-hint { margin-inline-start: auto; }
.key-hint {
  display: inline-block;
  padding: 0 var(--space-1);
  border: 1px solid var(--line2);
  border-radius: calc(var(--r-s) / 2);
  background: var(--surf);
  color: var(--ink2);
  font: 500 var(--font-size-0)/1.5 var(--font-mono);
}
.has-key-hint { position: relative; }
.has-key-hint > .key-hint {
  position: absolute;
  inset-block-start: calc(-1 * var(--space-2));
  inset-inline-end: calc(-1 * var(--space-1));
  display: none;
}
.has-key-hint:focus-visible > .key-hint { display: inline-block; }
.account-menu { position: relative; }
.account-menu > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line2);
  border-radius: var(--r-pill);
  background: var(--glass2);
  color: var(--ink);
  list-style: none;
  cursor: pointer;
}
.account-menu > summary::-webkit-details-marker { display: none; }
.account-menu-name { max-inline-size: 12rem; overflow-wrap: anywhere; }
.account-menu-panel {
  position: fixed;
  inset-inline: var(--space-3);
  z-index: 20;
  display: grid;
  gap: var(--space-4);
  max-block-size: calc(100dvh - 6rem);
  margin-block-start: var(--space-2);
  padding: var(--space-4);
  overflow-y: auto;
}
.account-menu-who { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; color: var(--ink2); }
.account-menu-theme { display: flex; flex-wrap: wrap; gap: var(--space-2); min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.account-menu-theme > legend,
.account-menu-heading { margin: 0 0 var(--space-2); padding: 0; color: var(--ink2); font-size: var(--font-size-0); font-weight: 600; }
.account-menu-theme > label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line2);
  border-radius: var(--r-pill);
  cursor: pointer;
}
.account-menu-theme > label:has(:checked) { border-color: transparent; background: var(--gold-fill); color: var(--on-gold); }
/* The chosen pill is gold already, so its radio button is drawn in the pill's ink rather than a second gold. */
.account-menu-theme > label > input:checked { border-color: var(--on-gold); background: transparent; }
.account-menu-links,
.account-menu-accounts > ul { display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.account-menu-links a,
.account-menu-accounts a {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding: 0 var(--space-3);
  border-radius: var(--r-s);
  text-decoration: none;
}
.account-menu-links a[aria-current="page"] { background: var(--gold-fill); color: var(--on-gold); }
.account-menu-accounts button,
.account-menu-sign-out { justify-content: flex-start; inline-size: 100%; }
.notification-bell { position: relative; }
.notification-bell > summary { list-style: none; cursor: pointer; }
.notification-bell-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 1.25rem;
  padding: 0 var(--space-1);
  margin-inline-start: var(--space-1);
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-text);
  font-size: var(--font-size-0);
}
.notification-bell-panel {
  position: absolute;
  inset-inline-end: 0;
  z-index: 10;
  display: grid;
  gap: var(--space-2);
  inline-size: min(24rem, calc(100vw - 2 * var(--space-3)));
  margin: var(--space-2) 0 0;
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.notification-bell-panel-header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.notification-mark-all-read {
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--gold-t);
  text-decoration: underline;
}
.notification-bell-panel ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.notification-card {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.notification-card-copy { display: grid; flex: 1; min-inline-size: 0; gap: var(--space-1); }
.notification-card-summary { overflow: hidden; color: var(--color-text-muted); text-overflow: ellipsis; white-space: nowrap; }
.notification-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); color: var(--color-text-muted); font-size: var(--font-size-0); }
.notification-outcome-refused { padding: 0 var(--space-1); border: 1px solid var(--color-danger); border-radius: var(--radius); color: var(--color-danger); }
.notification-card-actions { display: flex; flex-wrap: wrap; margin-inline-start: auto; }
.notification-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: calc(var(--space-5) + var(--space-4));
  min-block-size: calc(var(--space-5) + var(--space-4));
  padding: var(--space-2);
  border: 0;
  background: transparent;
  color: var(--color-text-muted);
}
.notification-icon-button svg { inline-size: var(--space-4); block-size: var(--space-4); }
@media (width < 600px) {
  .app-bar { column-gap: var(--space-2); }
  .app-nav { order: 1; flex-basis: 100%; }
  #app:has(> .bottom-tabs) :is(.app-nav, .app-admin-link) { display: none; }
  .app-bar:has(> .church-mark) > .app-bar-head { display: none; }
  .app-bar > .church-mark { flex: 1 1 0; flex-wrap: nowrap; }
  .church-mark-bar .church-mark-logo { block-size: 2rem; }
  .church-mark-bar .church-mark-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .app-bar > .palette-opener { margin-inline-start: auto; }
  .palette-opener,
  .notification-bell > summary,
  .account-menu > summary { justify-content: center; min-inline-size: 44px; padding: 0; }
  :is(.palette-opener, .notification-bell > summary) .shell-label,
  .app-bar .account-menu-name {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .palette-opener .key-hint { display: none; }
  .app-bar .account-menu-name + .icon { display: none; }
  .notification-bell-badge { position: absolute; inset-block-start: 0; inset-inline-end: 0; margin: 0; }
  .notification-bell-panel {
    position: fixed;
    inset-inline: var(--space-3);
    inline-size: auto;
    max-block-size: calc(100dvh - 6rem);
    overflow-y: auto;
  }
}
/* The narrowest phones keep the mark's symbol alone, so the top bar stays one row. */
@media (width < 360px) {
  .app-bar .brand-mark-word {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}
@media (min-width: 600px) {
  #app:has(> .app-bar) { flex-direction: row; }
  .app-bar {
    container: sidebar / inline-size;
    position: sticky;
    inset-block-start: 0;
    z-index: 5;
    flex: none;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    align-self: flex-start;
    gap: var(--space-3);
    inline-size: var(--sidebar-rail);
    block-size: 100dvh;
    padding: var(--space-4) var(--space-3);
    border-block-end: 0;
    border-inline-end: 1px solid var(--line2);
  }
  .app-nav ul { flex-direction: column; flex-wrap: nowrap; gap: var(--space-1); }
  .app-nav a,
  .app-admin-link,
  .notification-bell > summary,
  .account-menu > summary { display: flex; }
  .app-bar > .notification-bell { margin-block-start: auto; }
  .account-menu-panel,
  .notification-bell-panel {
    position: absolute;
    inset-inline: calc(100% + var(--space-3) + var(--space-2)) auto;
    inset-block: auto 0;
    max-block-size: calc(100dvh - 6rem);
    margin: 0;
    overflow-y: auto;
  }
  .account-menu-panel { inline-size: 20rem; }
  /* Administration sits between the bell and the account menu, so the bell's panel, which grows up from the bell's
     foot, has that row less room above it. */
  .app-bar > .notification-bell:has(+ .app-admin-link) > .notification-bell-panel { max-block-size: calc(100dvh - 6rem - 44px - var(--space-3)); }
}
@container sidebar (width < 12rem) {
  .app-bar-head { flex-direction: column; }
  .app-bar :is(.shell-label, .brand-mark-word, .account-menu-name, .church-mark-name) {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .account-menu-name + .icon { display: none; }
  .church-mark { justify-content: center; }
  .church-mark-logo { block-size: 2rem; }
  .app-nav a,
  .app-admin-link,
  .notification-bell > summary,
  .account-menu > summary,
  .palette-opener { justify-content: center; padding: 0; }
  .notification-bell-badge { position: absolute; inset-block-start: 0; inset-inline-end: 0; margin: 0; }
  .palette-opener .key-hint { display: none; }
}
@container sidebar (width >= 12rem) {
  .app-bar-head { justify-content: space-between; }
}
@media (min-width: 1024px) {
  .sidebar-toggle { display: inline-flex; }
  .app-bar[data-sidebar="expanded"] { inline-size: var(--sidebar-wide); }
}
@media (min-width: 1280px) and (width < 1440px) {
  #app:has(main :is(.workspace, .service-workspace, #live-controller)) > .app-bar { inline-size: var(--sidebar-rail); }
  #app:has(main :is(.workspace, .service-workspace, #live-controller)) .sidebar-toggle { display: none; }
}

/* The phone's tabs (`bottom-tabs.tsx`, below 600px only): a solid bar along the bottom edge, clear of the home
   indicator, whose height `--shell-bottom` lifts the toasts above it. More opens a glass sheet above the bar. */
#app:has(> .bottom-tabs) {
  --shell-bottom: calc(4.5rem + env(safe-area-inset-bottom));
  --shell-tab-height: 4.5rem;
}
.bottom-tabs {
  position: relative;
  z-index: 5;
  flex: none;
  padding-block-end: env(safe-area-inset-bottom);
  background: var(--bg2);
  border-block-start: 1px solid var(--line2);
}
.bottom-tabs > ul { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; margin: 0; padding: 0; list-style: none; }
.bottom-tabs > ul > li > a,
.bottom-tabs-more > summary {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  min-block-size: var(--shell-tab-height);
  padding-block: var(--space-1);
  padding-inline: 0;
  color: var(--ink2);
  text-align: center;
  text-decoration: none;
}
.bottom-tabs .icon { inline-size: 1.5rem; block-size: 1.5rem; }
/* Tab names may use two whole-word lines, never truncate, and stay readable on the narrowest phone. */
.bottom-tabs .shell-label {
  display: block;
  max-block-size: 2.4em;
  overflow: visible;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.2;
  overflow-wrap: normal;
  word-break: normal;
}
.bottom-tabs-more > summary { list-style: none; cursor: pointer; }
.bottom-tabs-more > summary::-webkit-details-marker { display: none; }
.bottom-tabs > ul > li > a[aria-current="page"],
.bottom-tabs-more > summary[aria-current="true"] { color: var(--gold-t); box-shadow: inset 0 3px 0 var(--gold); }
.bottom-tabs-sheet {
  position: absolute;
  inset-inline: var(--space-3);
  inset-block-end: calc(100% + var(--space-2));
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: var(--space-2);
  list-style: none;
}
.bottom-tabs-sheet a {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border-radius: var(--r-m);
  color: var(--ink);
  text-decoration: none;
}
.bottom-tabs-sheet a[aria-current="page"] { background: var(--gold-fill); color: var(--on-gold); }

/* An output window is a projector surface: the whole window, nothing else, in the theme the run names for
   it; `live/surface-theme.ts` sets the three colours, the surface's own default until the run names
   one). Only a screen with no live state (sign-in, offline, ended) carries none and falls back to light on black. */
.output-surface { position: fixed; inset: 0; background: var(--theme-background, #000); color: var(--theme-foreground, #fff); }
.output-surface :focus-visible { outline-color: var(--theme-accent, currentColor); }
/* A move between frames: the incoming frame on its own layer over the outgoing one, which only
   starts leaving once the incoming one is drawn. Reduced motion cuts (the rule below stops every animation). */
.audience-layer { position: absolute; inset: 0; }
.audience-output[data-transition="fade"] [data-transition-layer="incoming"],
.audience-output[data-transition="crossfade"] [data-transition-layer="incoming"] { animation: audience-fade-in var(--transition-ms) ease-out both; }
.audience-output[data-transition="crossfade"] [data-transition-layer="outgoing"] { animation: audience-fade-out var(--transition-ms) ease-in both; }
.audience-output[data-transition="push"] [data-transition-layer="incoming"] { animation: audience-push-in var(--transition-ms) ease-out both; }
.audience-output[data-transition="push"] [data-transition-layer="outgoing"] { animation: audience-push-out var(--transition-ms) ease-out both; }
@keyframes audience-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes audience-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes audience-push-in { from { transform: translateX(100%); } to { transform: none; } }
@keyframes audience-push-out { from { transform: none; } to { transform: translateX(-100%); } }
/* The built-in standby screen (`standby-screen.tsx`): navy with the dark theme's ink and gold light
   in both themes and whatever the run's surface theme, the church's mark in the middle, sized by the screen (a
   projector or a guest's phone) and never below a heading. */
.standby-screen {
  --ink: var(--screen-ink);
  --glow2: var(--screen-light);
  position: absolute;
  inset: 0;
  isolation: isolate;
  display: grid;
  place-items: center;
  padding: 8vmin;
  overflow: hidden;
  color-scheme: dark;
  background: var(--screen-ground);
  color: var(--screen-ink);
}
.church-mark-screen { flex-direction: column; justify-content: center; gap: 3vmin; text-align: center; }
.church-mark-screen .church-mark-logo { block-size: max(4rem, 28vmin); }
.church-mark-screen .church-mark-name { font-size: max(var(--font-size-3), 7vmin); line-height: 1.15; }
/* A cue keeps its own line breaks, and each box of one language starts its own line. */
.stage-current-text, .stage-next-text, .singer-current-text { white-space: pre-line; }
/* The picture a slide with no words shows on Stage and Singer: a glance, never the whole screen. */
.stage-still, .singer-still { display: block; max-inline-size: 100%; max-block-size: 40vh; object-fit: contain; }

/* Session and release interruptions sit above the current page without discarding its work. */
.expiry-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
}
.expiry-banner p { margin: 0; }
.maintenance-banner {
  padding: var(--space-3) var(--space-4);
  color: var(--color-text);
  background: color-mix(in srgb, var(--warning) 14%, var(--surf));
  border: 1px solid var(--warning);
}
.maintenance-banner p { margin: 0; }
.maintenance-banner p + p { margin-block-start: var(--space-2); }
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(var(--blur));
  backdrop-filter: blur(var(--blur));
}
/* Dialogs sit on a solid surface, never glass: what they ask must read over any page. */
:where([role="dialog"], [role="alertdialog"], dialog) {
  inline-size: 100%;
  max-inline-size: 32rem;
  max-block-size: calc(100dvh - 2 * var(--space-4));
  overflow-y: auto;
  padding: var(--space-5);
  border: 1px solid var(--line2);
  border-radius: var(--r-l);
  background: var(--surf);
  color: var(--ink);
  box-shadow: var(--shadow);
}
:where([role="dialog"], [role="alertdialog"], dialog) h2 { margin-block-start: 0; font-size: var(--font-size-3); }
dialog::backdrop {
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(var(--blur));
  backdrop-filter: blur(var(--blur));
}
/* Toasts float above the phone tab bar and never block a click. */
.toast-region {
  position: fixed;
  inset-inline: var(--space-4);
  inset-block-end: calc(var(--space-4) + var(--shell-bottom, 0px));
  z-index: 20;
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  pointer-events: none;
}
.toast-region > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  max-inline-size: min(32rem, 100%);
  padding-block: var(--space-2);
  padding-inline: var(--space-4) var(--space-2);
  border: 1px solid var(--line2);
  border-radius: var(--r-m);
  background: var(--veil);
  color: var(--ink);
  box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(var(--blur));
  backdrop-filter: blur(var(--blur));
  pointer-events: auto;
}
/* Skeletons stand in for loading content in its own shape; this is the still shape reduced motion keeps. */
.skeleton { display: grid; gap: var(--space-3); }
.skeleton[data-shape="card"] {
  grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
  gap: var(--space-4);
}
.skeleton-shape {
  display: block;
  block-size: 1rem;
  border-radius: var(--r-s);
  background: linear-gradient(100deg, var(--glass) 30%, var(--glow) 50%, var(--glass) 70%);
  background-size: 200% 100%;
}
.skeleton[data-shape="line"] > .skeleton-shape:last-child { inline-size: 60%; }
.skeleton[data-shape="row"] > .skeleton-shape { block-size: 3.25rem; border-radius: var(--r-m); }
.skeleton[data-shape="card"] > .skeleton-shape { block-size: 9rem; border-radius: var(--r-l); }
/* An empty page has a picture in a soft gold light, one friendly line, and one thing to do next. */
.empty-state {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  padding-block: var(--space-6);
  padding-inline: var(--space-4);
  text-align: center;
}
.empty-state-art {
  display: grid;
  place-items: center;
  inline-size: 5rem;
  aspect-ratio: 1;
  border-radius: var(--r-pill);
  background: radial-gradient(circle, var(--glow2), transparent 70%);
  color: var(--gold-t);
  font-size: 2.5rem;
}
.empty-state-message { max-inline-size: 36ch; margin: 0; color: var(--ink2); font-size: var(--font-size-2); }
/* Pages arrive with a short fade; controls ease their colour and glow, and cards that open something lift.
   What tracks the room never moves on its own. */
main > * { animation: page-in var(--motion-panel) ease-out; }
main:has(#live-controller) > * { animation: none; }
@keyframes page-in { from { opacity: 0; } }
/* A message that turns up rises a few pixels into place and then rests fully shown. */
@media (prefers-reduced-motion: no-preference) {
  :where(:is([role="alert"], [role="status"]):not(.output-surface *, #live-controller *)) {
    animation: message-in var(--motion-panel) ease-out;
  }
}
@keyframes message-in { from { opacity: 0; transform: translateY(4px); } }
:where(button, .button, [role="tab"]) {
  transition: background-color var(--motion-feedback) ease-out, border-color var(--motion-feedback) ease-out,
    box-shadow var(--motion-feedback) ease-out, filter var(--motion-feedback) ease-out, transform var(--motion-feedback) ease-out;
}
:where(button, .button, [role="tab"]):focus-visible { box-shadow: 0 0 0 4px var(--glow); }
@media (hover: hover) {
  :where(button, .button):hover:not(:disabled, [aria-disabled="true"]) { filter: brightness(1.08); }
  .has-key-hint:hover > .key-hint { display: inline-block; }
}
/* Only a mouse lifts a card or a record row that opens something: a finger's tap would leave it lifted. A row that
   holds an open dialog stays put, since a moved row would carry the dialog with it. */
@media (hover: hover) and (pointer: fine) {
  .card:has(.card-link) { transition: transform var(--motion-feedback) ease-out, box-shadow var(--motion-feedback) ease-out; }
  .card:has(.card-link):hover { transform: translateY(-3px); box-shadow: var(--shadow), 0 0 0 1px var(--line2); }
  :is(.record-list, [aria-labelledby="dashboard-recent-heading"] > ul) > li:has(a[href]) {
    transition: transform var(--motion-feedback) ease-out, border-color var(--motion-feedback) ease-out, box-shadow var(--motion-feedback) ease-out;
  }
  :is(.record-list, [aria-labelledby="dashboard-recent-heading"] > ul) > li:has(a[href]):not(:has(.modal-backdrop)):hover {
    transform: translateY(-2px);
    border-color: var(--line2);
    box-shadow: var(--shadow);
  }
}
/* A card that opens one thing is one click target: its link covers the card, and a keyboard ring goes round it. */
.card-link { color: inherit; text-decoration: none; }
.card-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.card:has(.card-link) :is(button, a:not(.card-link), input, select, textarea, summary) { position: relative; z-index: 1; }
.card:has(.card-link:focus-visible) { outline: var(--focus-ring); outline-offset: 2px; }
.card-link:focus-visible { outline: none; }
#live-controller,
#live-controller * { transition: none; animation: none; }

/* The preparing pages move, briefly and calmly, where motion is welcome. A page change fades the old page out and
   raises the new one (router.ts names the main column only while it runs, since a named column would dull the
   glass inside it); where the browser cannot, the page fades in as above. Panels, cards and rows then rise in one
   after another, each a quarter of a feedback beat after the one before, at most four beats. A pressed control
   sinks a little. The menus open and close with a short fade and scale, and so do the dialogs: motion.ts keeps a
   closed dialog on the page, out of reach, while it fades. The gold of a chosen tab or theme slides from the old
   choice to the new one on a pill motion.ts lays under the row. Nothing moves on the live controller, the remote
   or an output screen, and only opacity and transform move, so nothing shifts the page. */
@property --rise-step { syntax: "<integer>"; inherits: false; initial-value: 0; }
:where(main :nth-child(2)) { --rise-step: 1; }
:where(main :nth-child(3)) { --rise-step: 2; }
:where(main :nth-child(4)) { --rise-step: 3; }
:where(main :nth-child(n + 5)) { --rise-step: 4; }
:is(.modal-backdrop, dialog)[data-leaving] { pointer-events: none; }
dialog[data-leaving] { position: fixed; inset: 0; z-index: 30; margin: auto; }
:where([data-sliding]) { position: relative; isolation: isolate; }
@media (prefers-reduced-motion: no-preference) {
  :root[data-page-change] #main { view-transition-name: page; }
  ::view-transition-group(*) { animation-duration: var(--motion-panel); }
  ::view-transition-old(page) { animation: page-out var(--motion-feedback) ease-in both; }
  ::view-transition-new(page) { animation: page-rise var(--motion-panel) ease-out both; }
  :where(main:not(:has(#live-controller))) :is(.glass-panel, .card, .form-panel, .passkey-row, .recovery-codes, .table-scroll, .workspace-panel, .record-list > li, [aria-labelledby="dashboard-recent-heading"] > ul > li, .library-list > li, .media-list > li, main[data-page="settings"] form):not(:has(.modal-backdrop)) {
    animation: rise-in var(--motion-panel) ease-out backwards;
    animation-delay: calc(var(--rise-step) * var(--motion-feedback) / 4);
  }
  :where(:is(button, .button, [role="tab"]):active:not(:disabled, [aria-disabled="true"], main:has(#live-controller) *, .output-surface *, .output-chrome *, .join-surface *)) {
    transform: scale(0.97);
  }
  :where(.account-menu, .notification-bell, .bottom-tabs-more)::details-content {
    transition: content-visibility var(--motion-feedback) allow-discrete;
  }
  :where(.account-menu-panel, .notification-bell-panel, .bottom-tabs-sheet) {
    transition: opacity var(--motion-feedback) ease-in, transform var(--motion-feedback) ease-in;
  }
  :where(:not([open]) > :is(.account-menu-panel, .notification-bell-panel, .bottom-tabs-sheet)) {
    opacity: 0;
    transform: scale(0.97);
    pointer-events: none;
  }
  :where([open] > :is(.account-menu-panel, .notification-bell-panel, .bottom-tabs-sheet), .lifecycle-menu > [role="menu"], .order-item-actions > [id^="order-actions-list-"]) {
    animation: menu-in var(--motion-panel) ease-out;
  }
  .modal-backdrop:where(:not(main:has(#live-controller) *)) { animation: backdrop-in var(--motion-panel) ease-out; }
  :is(.modal-backdrop > :is([role="dialog"], [role="alertdialog"]), dialog[open]):where(:not(main:has(#live-controller) *)) {
    animation: dialog-in var(--motion-panel) ease-out;
  }
  dialog[open]::backdrop { animation: backdrop-in var(--motion-panel) ease-out; }
  .modal-backdrop[data-leaving] { animation: backdrop-out var(--motion-feedback) ease-in forwards; }
  :is(.modal-backdrop[data-leaving] > *, dialog[data-leaving]) { animation: dialog-out var(--motion-feedback) ease-in forwards; }
  [data-sliding] > :is([role="tab"][aria-selected="true"], label:has(> input:checked)) { background: transparent; box-shadow: none; }
  [data-sliding]::before {
    content: "";
    position: absolute;
    inset-block-start: var(--slide-y);
    inset-inline-start: var(--slide-x);
    z-index: -1;
    inline-size: var(--slide-w);
    block-size: var(--slide-h);
    border-radius: var(--r-pill);
    background: var(--gold-fill);
    transform-origin: 0 0;
    pointer-events: none;
    animation: indicator-slide var(--motion-panel) ease-out;
  }
}
@keyframes page-out { to { opacity: 0; } }
@keyframes page-rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes rise-in { from { opacity: 0; transform: translateY(6px); } }
@keyframes menu-in { from { opacity: 0; transform: scale(0.97); } }
@keyframes backdrop-in { from { opacity: 0; } }
@keyframes backdrop-out { to { opacity: 0; } }
@keyframes dialog-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
@keyframes dialog-out { to { opacity: 0; transform: translateY(4px) scale(0.98); } }
@keyframes indicator-slide { from { transform: var(--slide-from); } }
/* Ambient light loops slowly; reduced motion stops it and leaves the still shapes. */
.skeleton > .skeleton-shape {
  box-shadow: 0 0 14px -4px var(--glow2);
  animation: skeleton-shimmer var(--motion-ambient-shimmer) linear infinite;
}
@keyframes skeleton-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.aurora-light {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  /* No fallback on --aurora-tint: while it is unset these stay unset and the lights keep --b1 to --b4. */
  --aurora-b1: color-mix(in srgb, color-mix(in srgb, var(--aurora-tint) 40%, transparent) 60%, var(--b1));
  --aurora-b2: color-mix(in srgb, color-mix(in srgb, var(--aurora-tint) 40%, transparent) 60%, var(--b2));
  --aurora-b3: color-mix(in srgb, color-mix(in srgb, var(--aurora-tint) 40%, transparent) 60%, var(--b3));
  --aurora-b4: color-mix(in srgb, color-mix(in srgb, var(--aurora-tint) 40%, transparent) 60%, var(--b4));
}
.aurora-light::before,
.aurora-light::after {
  content: "";
  position: absolute;
  inset: -20%;
  animation: aurora-drift var(--motion-ambient-drift) ease-in-out infinite alternate;
}
.aurora-light::before {
  background:
    radial-gradient(circle at 20% 20%, var(--aurora-b1, var(--b1)), transparent 40%),
    radial-gradient(circle at 30% 80%, var(--aurora-b3, var(--b3)), transparent 40%);
}
.aurora-light::after {
  background:
    radial-gradient(circle at 80% 25%, var(--aurora-b2, var(--b2)), transparent 38%),
    radial-gradient(circle at 75% 85%, var(--aurora-b4, var(--b4)), transparent 36%);
  animation-direction: alternate-reverse;
}
.aurora-light[data-tone="gold"]::before { background: radial-gradient(circle at 50% 40%, var(--glow2), transparent 55%); }
.aurora-light[data-tone="gold"]::after { background: none; }
@keyframes aurora-drift { to { transform: translate(4%, 3%) scale(1.08); } }

/* A clipped label always travels with its disclosure control: ellipsis is a compact default, never the
   only route to the full value. Expansion restores ordinary wrapping in the same place so revealing a
   long name neither depends on hover nor moves focus to a separate surface. */
.truncated-text { display: inline-grid; min-inline-size: 0; max-inline-size: 100%; }
.truncated-text-content {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.truncated-text-content-expanded {
  overflow: visible;
  overflow-wrap: anywhere;
  white-space: normal;
}
/* The disclosure (shown only while the text is cut off) is a small underlined text control of the cell, not a pill.
   A mouse gets a 24px target; touch keeps the full 44px. */
.truncated-text-toggle {
  justify-self: start;
  margin-block-start: var(--space-1);
  padding: 0;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  box-shadow: none;
  color: var(--gold-t);
  font-size: var(--font-size-0);
  text-decoration: underline;
  text-underline-offset: 2px;
}
@media (pointer: fine) {
  .truncated-text-toggle { min-block-size: 24px; }
}

/* Narrow controls grow vertically instead of hiding translated or user-provided text. The minimum is
   repeated inside the query because this is the contract that must survive any wider-screen restyle. */
@media (max-width: 767px) {
  button,
  nav a {
    min-block-size: 44px;
    overflow: visible;
    overflow-wrap: anywhere;
    white-space: normal;
  }
}

/* Reduced motion keeps every state change visible immediately while removing the movement that would
   carry it there. Applying the override to generated content too prevents a later decorative loop or
   panel transform from escaping the preference merely because it lives on a pseudo-element. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
}

/* Increased contrast makes glass solid, removes glows and aurora, and strengthens edges. */
@media (prefers-contrast: more) {
  :root:root {
    --glass: var(--surf);
    --glass2: var(--surf2);
    --veil: var(--surf);
    --line: var(--edge);
    --line2: var(--edge);
    --ring1: var(--edge);
    --ring2: var(--edge);
    --ring3: var(--edge);
    --glow: transparent;
    --glow2: transparent;
  }
  .glass-panel,
  .card,
  .modal-backdrop,
  dialog::backdrop,
  .toast-region > li {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .skeleton-shape { outline: 1px solid var(--edge); }
  .aurora-light { display: none; }
}

.song-form { margin: 0; padding: 0; border: 0; min-inline-size: 0; }

.canvas-toolbar, .canvas-zoom { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.canvas-viewport { overflow: auto; max-inline-size: 100%; }
.canvas-slide { position: relative; overflow: hidden; direction: ltr; }
.canvas-box { position: absolute; box-sizing: border-box; outline: 1px dashed var(--canvas-guide); color: var(--canvas-handle); cursor: move; touch-action: none; }
.canvas-box[aria-pressed="true"] { outline: 2px solid var(--gold); }
.canvas-box:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.canvas-box[aria-disabled="true"] { cursor: default; }
.canvas-box > span:not(.canvas-handle) { display: block; overflow: hidden; block-size: 100%; }
.canvas-box > img { inline-size: 100%; block-size: 100%; }
/* A small gold square with a dark edge reads on light, dark and checkered slides; the invisible area round it is
   what a pointer or a finger actually has to hit. */
.canvas-handle { position: absolute; inline-size: 12px; block-size: 12px; background: var(--gold); box-shadow: inset 0 0 0 1px var(--canvas-ink); touch-action: none; }
.canvas-handle::before { content: ""; position: absolute; inset: -6px; }
@media (pointer: coarse) {
  .canvas-handle::before { inset: -16px; }
}
.canvas-handle-nw, .canvas-handle-n, .canvas-handle-ne { inset-block-start: -6px; }
.canvas-handle-sw, .canvas-handle-s, .canvas-handle-se { inset-block-end: -6px; }
.canvas-handle-nw, .canvas-handle-w, .canvas-handle-sw { inset-inline-start: -6px; }
.canvas-handle-ne, .canvas-handle-e, .canvas-handle-se { inset-inline-end: -6px; }
.canvas-handle-n, .canvas-handle-s { inset-inline-start: calc(50% - 6px); cursor: ns-resize; }
.canvas-handle-e, .canvas-handle-w { inset-block-start: calc(50% - 6px); cursor: ew-resize; }
.canvas-handle-nw, .canvas-handle-se { cursor: nwse-resize; }
.canvas-handle-ne, .canvas-handle-sw { cursor: nesw-resize; }
.canvas-inline-text { position: absolute; box-sizing: border-box; z-index: 10000; }
.layout-canvas-slide { outline: 1px solid var(--edge); }
.layout-canvas-transparent, .layout-preview .preview-stage, .layout-thumbnail > [role="img"] {
  color: var(--canvas-ink);
  background-color: var(--canvas-paper);
  background-image: conic-gradient(var(--canvas-checker) 25%, var(--canvas-paper) 0 50%, var(--canvas-checker) 0 75%, var(--canvas-paper) 0);
  background-size: 24px 24px;
}
.layout-safe-area { position: absolute; border: 2px dashed var(--canvas-safe-area); pointer-events: none; }
.layout-box { color: var(--canvas-ink); outline-color: var(--canvas-box-edge); background: var(--canvas-box-fill); }
.layout-box > span:not(.canvas-handle) { padding: 4px; box-sizing: border-box; overflow-wrap: anywhere; }
.layout-position { display: flex; flex-wrap: wrap; gap: 8px 16px; }
.layout-placements { display: flex; flex-wrap: wrap; gap: var(--space-2); flex-basis: 100%; }
.layout-properties, .layout-text-style { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: end; }
.layout-properties > legend, .layout-properties > [role="alert"], .layout-properties > .form-hint { flex-basis: 100%; }
.layout-editor-fields { display: grid; gap: 16px; min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.layout-editor { display: grid; gap: 16px; }
.layout-editor > * { min-inline-size: 0; }
.layout-save-state:empty { display: none; }
.layout-editor-conflict { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; }
.layout-ratio { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; }
.layout-ratio > legend, .layout-ratio > .form-hint { flex-basis: 100%; }
.layout-variants { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.layout-variant { display: grid; gap: 8px; padding-block: 8px; border-block-end: 1px solid var(--line); }
.layout-variant-actions { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; }
.layout-variant-draft, .preview-draft, .thumbnail-draft { font-weight: 600; }
:where(.preview-legend) { margin: var(--space-1) 0 0; color: var(--ink2); font-size: var(--font-size-0); }
.template-editor { display: grid; gap: 16px; min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.template-section, .template-entries { display: grid; gap: 8px; }
.template-entry { display: grid; gap: 8px; padding-block: 8px; border-block-end: 1px solid var(--line); }
.template-actions, .template-move { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: end; }
.layout-box-list > ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; }
.layout-box-list [role="option"] { display: flex; align-items: center; min-inline-size: 44px; min-block-size: 44px; padding: 4px 8px; border: 1px solid currentColor; border-radius: 4px; cursor: pointer; }
.layout-box-list [role="option"][aria-selected="true"] { outline: 2px solid var(--gold); }
.layout-shared-style > .layout-shared-note { flex-basis: 100%; margin: 0; }
.truncate { display: inline-block; max-inline-size: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.media-list { list-style: none; margin: 0; padding: 0; }
.media-row { display: flex; gap: 8px; align-items: center; padding-block: 4px; padding-inline: 8px; cursor: pointer; }
.media-row[aria-selected="true"] { outline: 2px solid var(--gold); }
.media-row[aria-disabled="true"] { cursor: not-allowed; }
.media-row:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.media-name { flex: 1; min-inline-size: 0; }
.media-row[aria-pressed="true"] { outline: 2px solid var(--gold); }
.media-library .media-row { inline-size: 100%; text-align: start; }
.drop-zone { display: block; padding-block: 24px; padding-inline: 16px; border: 2px dashed currentColor; border-radius: 8px; text-align: center; }
.drop-zone.over { outline: 3px solid var(--gold); }
.drop-zone input { display: block; margin-block-start: 8px; margin-inline: auto; }
.media-inspect dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px 12px; }
.media-inspect dd { margin: 0; min-inline-size: 0; }
.pptx-block { padding-block: 8px; padding-inline: 8px; border-inline-start: 3px solid transparent; }
.pptx-block:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.pptx-block.is-problem { border-inline-start-color: currentColor; }
.pptx-block-text { margin: 0; white-space: pre-wrap; }
.pptx-block-meta { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-block: 4px; }
.pptx-wizard { max-inline-size: min(48rem, 100%); max-block-size: 100%; overflow: auto; }
.pptx-wizard-close { float: inline-end; }
.pptx-wizard progress { display: block; inline-size: 100%; }
.pptx-song-picker ul { list-style: none; margin: 0; padding: 0; }
.pptx-song-picker button[aria-pressed="true"] { outline: 2px solid var(--gold); }
.library-imports { display: flex; flex-wrap: wrap; gap: 8px; margin-block: 8px; }
.pptx-unfinished ul { list-style: none; margin: 0; padding: 0; }
