/**
 * singular-platform.css — the Singular design system.
 *
 * WHY THIS FILE EXISTS
 * --------------------
 * Singular had no shared component vocabulary. Three screens (Today, Settings,
 * Calendar) were hand-built to look modern; every other screen fell through to
 * `stylesheet.css`, a 2012 stylesheet that styled bare elements globally:
 *
 *     a  { text-transform: uppercase; color: #0096FE; }   → every link SHOUTED
 *     h2 { background: #ccc; linear-gradient(...); }      → grey "title bars"
 *     body { font: 12px Tahoma; text-align: center; }     → whole app centred
 *     .pagecontainer { background-image: Ptouch_contentBG.jpg }  → watermark
 *     #files, #account, #reports { width: 1000px }        → fixed-width pages
 *
 * Those rules also leaked into screens that HAD been converted to Bootstrap,
 * which is why Find Photos rendered with a wrapped "Locatio/n" label and a grey
 * header bar despite being clean Bootstrap 5 markup. Deleting the legacy sheet
 * was the single highest-leverage change; this file is what replaces it.
 *
 * WHAT IT PROVIDES
 * ----------------
 * A real component layer — page furniture, panels, data tables, forms, buttons,
 * pagination, empty states, toolbars — built entirely on the design tokens
 * already defined in style.css (--brand, --surface, --border, --text, --muted,
 * --radius-card …). Because it uses only tokens, light and dark themes both
 * work with no extra rules.
 *
 * THE LEGACY BRIDGE (§13)
 * -----------------------
 * ~30 views still use old class names (.toolBar, .settingTab, .editButton,
 * .formbox …). Rather than rewrite all of them at once and risk breaking
 * working screens, §13 re-points those names at the modern components. The
 * markup stays familiar; the rendering is new. Views get converted to the
 * real class names over time, and each conversion deletes a bridge rule.
 *
 * CASCADE POSITION
 * ----------------
 * Loaded after bootstrap.min.css and style.css, before singular-theme.css:
 *     bootstrap → shared theme (tokens) → THIS (system) → singular-theme (features)
 * So it may override Bootstrap, and feature CSS may override it.
 *
 * Sections:
 *    1. Base & type scale          8. Empty states
 *    2. Page furniture             9. Chips, badges, status
 *    3. Panels                    10. Notices
 *    4. Data tables               11. Toolbars
 *    5. Forms                     12. Device & preview frames
 *    6. Buttons                   13. Legacy bridge
 *    7. Pagination                14. Responsive
 */

/* ═══════════════════════════════════════════════════════════════════
   1. BASE & TYPE SCALE

   The legacy sheet set 12px Tahoma and text-align:center on <body>, so
   every page inherited both. These are the corrective defaults; they are
   deliberately plain so Bootstrap and the shared theme stay in charge of
   everything else.
   ═══════════════════════════════════════════════════════════════════ */
:root {
  /* Spacing rhythm — one scale, used by every component below. */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;

  /* Type scale. Body sits at 15px: the legacy 12px was unreadable on the
     dense table screens, and 16px pushed the calendar grid off-screen. */
  --fs-xs:   0.75rem;
  --fs-sm:   0.8125rem;
  --fs-base: 0.9375rem;
  --fs-lg:   1.0625rem;
  --fs-xl:   1.375rem;
  --fs-2xl:  1.75rem;

  /* Table geometry, shared by .dt and the legacy-table bridge. */
  --dt-cell-y: 0.7rem;
  --dt-cell-x: 0.9rem;
}

body.singular-app {
  font-size: var(--fs-base);
  line-height: 1.55;
  text-align: left;          /* undo legacy body{text-align:center} */
  -webkit-font-smoothing: antialiased;
}

/* Links inherit brand colour and stay sentence case. The single most
   visible legacy artefact was `text-transform: uppercase` on every <a>,
   which turned "Open calendar" into "OPEN CALENDAR" app-wide. */
body.singular-app a {
  color: var(--brand);
  text-transform: none;
  text-decoration: none;
  padding-right: 0;
  transition: color 0.15s ease;
}
body.singular-app a:hover { color: var(--brand-hover); text-decoration: underline; }

/* Headings own no chrome. Legacy h1 carried a border and h2 a grey gradient
   bar, so any view that used a plain heading got decoration it never asked
   for. Panels draw their own headers (§3) instead. */
body.singular-app :is(h1, h2, h3, h4, h5, h6) {
  background: none;
  border: 0;
  padding: 0;
  margin: 0 0 var(--sp-3);
  color: var(--text);
  font-weight: 650;
  line-height: 1.25;
  text-align: inherit;
  text-shadow: none;
  filter: none;
}
body.singular-app h1 { font-size: var(--fs-2xl); letter-spacing: -0.02em; }
body.singular-app h2 { font-size: var(--fs-xl);  letter-spacing: -0.01em; }
body.singular-app h3 { font-size: var(--fs-lg); }
body.singular-app h4 { font-size: var(--fs-base); }

body.singular-app hr {
  border: 0;
  border-top: 1px solid var(--border);
  opacity: 1;
  margin: var(--sp-5) 0;
}

/* Focus ring — one definition, everywhere. Legacy relied on the browser
   default, which vanished entirely against the dark theme. */
body.singular-app :is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--radius-btn-sm);
}

/* ═══════════════════════════════════════════════════════════════════
   2. PAGE FURNITURE

   .pagecontainer is the wrapper navbar_view.php opens around every
   authenticated page. The name is kept (8 views and both shells emit it)
   but the styling is entirely new: no watermark, no 1000px cap.
   ═══════════════════════════════════════════════════════════════════ */
.pagecontainer,
.page {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 0 var(--sp-7);
  background: none;          /* was the Ptouch_contentBG.jpg watermark */
  text-align: left;
}

/* Page header: title on the left, actions on the right, collapsing to two
   rows on narrow screens. Replaces the ad-hoc d-flex block each converted
   view was repeating by hand. */
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}

.page-head-text { min-width: 0; }

.page-title {
  font-size: var(--fs-2xl);
  font-weight: 680;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--text);
}

.page-sub {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
}

.page-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* Breadcrumb / back row above a page title. */
.page-crumbs {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--muted);
}
.page-crumbs a { color: var(--muted); font-weight: 600; }
.page-crumbs a:hover { color: var(--text); text-decoration: none; }
.page-crumbs .sep { opacity: 0.4; }

/* ═══════════════════════════════════════════════════════════════════
   3. PANELS

   The universal content container. Bootstrap's .card is aliased onto it so
   already-converted views (Find Photos, Setup) pick this up unchanged.
   ═══════════════════════════════════════════════════════════════════ */
.panel,
body.singular-app .card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;          /* keeps child tables inside the rounded corners */
  margin-bottom: var(--sp-4);
}

.panel-head,
body.singular-app .card-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: none;          /* legacy h2/card-header painted a grey gradient */
  border-bottom: 1px solid var(--border);
}

.panel-title,
body.singular-app .card-header > :is(h1, h2, h3, h4, h5, h6) {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.panel-body,
body.singular-app .card-body { padding: var(--sp-4); }

.panel-foot,
body.singular-app .card-footer {
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
  background-color: var(--surface-hover);
}

/* A panel whose body is nothing but a table wants no padding — the table
   supplies its own cell rhythm and should meet the panel edges. */
.panel-body.is-flush,
.panel > .dt-wrap:only-child { padding: 0; }

/* ═══════════════════════════════════════════════════════════════════
   4. DATA TABLES

   Every list screen (Emails, Photos, Slideshow rooms, Payments, Staff) was
   a bare <table> with borders and grey header cells. .dt is the one
   replacement: no vertical rules, a quiet header, generous rows, and a
   horizontal scroll container so wide tables never blow out the layout.
   ═══════════════════════════════════════════════════════════════════ */
.dt-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.dt {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  color: var(--text);
  margin: 0;
}

.dt thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--dt-cell-y) var(--dt-cell-x);
  background: var(--surface);
  border: 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  white-space: nowrap;
}

.dt tbody td {
  padding: var(--dt-cell-y) var(--dt-cell-x);
  border: 0;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.dt tbody tr:last-child td { border-bottom: 0; }
.dt tbody tr { transition: background 0.12s ease; }
.dt tbody tr:hover { background: var(--row-hover); }

/* Column helpers — used instead of per-cell inline width/align attributes. */
.dt .num       { text-align: right; font-variant-numeric: tabular-nums; }
.dt .center    { text-align: center; }
.dt .nowrap    { white-space: nowrap; }
.dt .shrink    { width: 1%; white-space: nowrap; }
.dt .muted     { color: var(--muted); }

/* Codes and IDs read as data, not prose. */
.dt .mono,
.code-cell {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.92em;
  letter-spacing: 0.02em;
}

/* Row selection checkbox column. */
.dt .pick { width: 1%; padding-right: 0; }

/* A table nested directly in a panel loses its outer radius clipping
   problems because .panel already sets overflow:hidden. */
.panel .dt-wrap { border-radius: 0; }

/* ═══════════════════════════════════════════════════════════════════
   5. FORMS

   Legacy laid forms out with .formbox (a 300px inline-block) and coloured
   .formname labels. The modern equivalent is a responsive grid of .field
   blocks with quiet labels above full-width controls.
   ═══════════════════════════════════════════════════════════════════ */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-4);
}

.field { min-width: 0; margin-bottom: var(--sp-4); }
.form-grid .field { margin-bottom: 0; }

.field-label,
body.singular-app .form-label {
  display: block;
  width: auto;              /* legacy .formname was a fixed narrow chip, which
                               is what wrapped "Location" into "Locatio/n" */
  margin: 0 0 var(--sp-2);
  padding: 0;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: left;
  white-space: normal;
}

.field-hint {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--muted);
}

/* Controls. Bootstrap supplies the behaviour; these align it to the tokens
   so inputs match panels in both themes.

   `:not(.premium-card *)` keeps this baseline off the login card. `:is()` takes
   the specificity of its most specific argument — `input[type="email"]` — so
   this selector outweighs both `.premium-card .form-control` in style.css and
   Bootstrap's own `.input-group > .form-control`. That last one matters: it is
   what sets `width: 1%` so an input can flex beside its icon addon. Overriding
   it with `width: 100%` pushed the field past the group's width and, because
   `.input-group` wraps, dropped it onto its own line below the icon. The card
   is a fully-styled component and owns its inputs; this rule is for the bare
   ones everywhere else. */
body.singular-app :is(.form-control, .form-select, input[type="text"],
                      input[type="email"], input[type="password"],
                      input[type="number"], input[type="search"],
                      input[type="tel"], input[type="date"], select,
                      textarea):not(.premium-card *) {
  width: 100%;
  padding: 0.5rem 0.75rem;
  background-color: var(--surface-hover);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  color: var(--text);
  font-size: var(--fs-base);
  font-family: inherit;
  line-height: 1.5;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

body.singular-app :is(.form-control, .form-select, input, select, textarea):focus {
  background: var(--surface-hover);
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-glow);
  color: var(--text);
  outline: none;
}

body.singular-app :is(.form-control, input, textarea)::placeholder { color: var(--muted); opacity: 1; }

body.singular-app :is(.form-control, .form-select, input, select, textarea):disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Checkboxes and radios keep the brand colour and a comfortable hit area. */
body.singular-app input[type="checkbox"],
body.singular-app input[type="radio"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--brand);
  vertical-align: middle;
  cursor: pointer;
}

/* Inline "or" divider between mutually exclusive search fields (Find Photos). */
.singular-or,
.or-rule {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-4) 0;
  color: var(--muted);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.singular-or::before, .singular-or::after,
.or-rule::before,    .or-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* An input with a trailing action (the "Clear" buttons on Find Photos). The
   corner rule assumes that shape — field first, button second. The login card
   is the mirror image (icon addon first, field second), so it is excluded here
   too and keeps the corners style.css gives it. */
body.singular-app .input-group { display: flex; }
body.singular-app .input-group > .form-control:not(.premium-card *) { border-radius: var(--radius-input) 0 0 var(--radius-input); }
body.singular-app .input-group > .btn {
  border-radius: 0 var(--radius-input) var(--radius-input) 0;
  border-left: 0;
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════
   6. BUTTONS
   ═══════════════════════════════════════════════════════════════════ */
body.singular-app .btn,
.btn-modern {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.5rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font-size: var(--fs-sm);
  font-weight: 650;
  line-height: 1.4;
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease,
              transform 0.08s ease, box-shadow 0.15s ease;
}
body.singular-app .btn:active { transform: translateY(1px); }

body.singular-app .btn-primary,
body.singular-app input[type="submit"],
body.singular-app input[type="button"] {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  box-shadow: 0 2px 10px var(--brand-shadow);
}
body.singular-app .btn-primary:hover,
body.singular-app input[type="submit"]:hover,
body.singular-app input[type="button"]:hover {
  background: var(--brand-hover);
  border-color: var(--brand-hover);
  color: #fff;
}

/* Secondary / outline / "light" all resolve to one quiet button. Legacy
   views use several names for the same intent, so they share a rule. */
body.singular-app :is(.btn-secondary, .btn-outline-light, .btn-outline-secondary,
                      .btn-default, .btn-quiet) {
  background: var(--surface-hover);
  border-color: var(--border);
  color: var(--text);
}
body.singular-app :is(.btn-secondary, .btn-outline-light, .btn-outline-secondary,
                      .btn-default, .btn-quiet):hover {
  background: var(--surface-hover);
  border-color: var(--brand);
  color: var(--text);
}

body.singular-app .btn-danger {
  background: var(--c-red);
  border-color: var(--c-red);
  color: #fff;
}
body.singular-app .btn-danger:hover { filter: brightness(0.92); color: #fff; }

/* A link that should read as an action without becoming a filled button. */
body.singular-app .btn-link,
.link-action {
  background: none;
  border-color: transparent;
  color: var(--brand);
  padding: 0.25rem 0.4rem;
  font-weight: 650;
}
body.singular-app .btn-link:hover, .link-action:hover { color: var(--brand-hover); text-decoration: underline; }

body.singular-app .btn-sm { padding: 0.35rem 0.7rem; font-size: var(--fs-xs); }
body.singular-app .btn-lg { padding: 0.7rem 1.4rem; font-size: var(--fs-base); }

/* Square icon-only button, used for row actions (delete, edit). */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-btn-sm);
  background: var(--surface-hover);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.btn-icon:hover { color: var(--text); border-color: var(--brand); }
.btn-icon.is-danger:hover { color: var(--c-red); border-color: var(--c-red); }

/* ═══════════════════════════════════════════════════════════════════
   7. PAGINATION

   The legacy pager printed "Previous Page | Page [1] of 1 GO | Next Page"
   as loose inline text, which overlapped itself on every list screen.
   ═══════════════════════════════════════════════════════════════════ */
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--muted);
}

.pager-group {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.pager-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-btn-sm);
  background: var(--surface-hover);
  color: var(--text);
  font-size: var(--fs-xs);
  font-weight: 650;
}
.pager-btn:hover { border-color: var(--brand); color: var(--text); text-decoration: none; }
.pager-btn[aria-disabled="true"],
.pager-btn.is-disabled { opacity: 0.4; pointer-events: none; }

.pager-input {
  width: 3.5rem !important;
  padding: 0.3rem 0.4rem !important;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Each pager control is its own POST form (the list is POST-driven), so the
   forms must lay out inline and contribute no box of their own. */
.pager-form { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; padding: 0; }

/* Filter pills ("Today | This week | Pending | All"). Rendered as <button>
   inside those forms, so the button chrome has to be reset here. */
.pager-filters { display: flex; flex-wrap: wrap; gap: var(--sp-1); }

button.pager-filter,
button.pager-btn {
  border: 0;
  font-family: inherit;
  cursor: pointer;
}
button.pager-btn { border: 1px solid var(--border); }

.pager-filter {
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 650;
  color: var(--muted);
}
.pager-filter:hover { background: var(--surface-hover); color: var(--text); text-decoration: none; }
.pager-filter.active { background: var(--brand); color: #fff; }
.pager-filter.active:hover { color: #fff; }

/* ═══════════════════════════════════════════════════════════════════
   8. EMPTY STATES

   Legacy printed "No Records Found" as a bare string in the top-left of an
   empty table. An empty list is a normal state and should look designed.
   ═══════════════════════════════════════════════════════════════════ */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-7) var(--sp-4);
  text-align: center;
}

.empty-art {
  font-size: 1.75rem;
  color: var(--muted);
  opacity: 0.5;
  margin-bottom: var(--sp-1);
}

.empty-title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 650;
  color: var(--text);
}

.empty-text {
  margin: 0;
  max-width: 42ch;
  font-size: var(--fs-sm);
  color: var(--muted);
}

.empty-actions { margin-top: var(--sp-3); }

/* ═══════════════════════════════════════════════════════════════════
   9. CHIPS, BADGES, STATUS
   ═══════════════════════════════════════════════════════════════════ */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background: var(--surface-hover);
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: 650;
  color: var(--muted);
  white-space: nowrap;
}

.chip.is-success { background: var(--c-green-bg);  border-color: transparent; color: var(--c-green); }
.chip.is-warning { background: var(--c-amber-bg);  border-color: transparent; color: var(--c-amber); }
.chip.is-danger  { background: var(--c-red-bg);    border-color: transparent; color: var(--c-red); }
.chip.is-info    { background: var(--c-blue-bg);   border-color: transparent; color: var(--c-blue); }
.chip.is-brand   { background: var(--c-violet-bg); border-color: transparent; color: var(--c-violet); }

/* A small coloured dot for inline status, e.g. "● Sent". */
.status-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--c-gray);
  margin-right: 0.4rem;
  vertical-align: 0.05em;
}
.status-dot.is-success { background: var(--c-green); }
.status-dot.is-warning { background: var(--c-amber); }
.status-dot.is-danger  { background: var(--c-red); }

/* ═══════════════════════════════════════════════════════════════════
   10. NOTICES

   The "settings are not switched on yet" bar that flags an unapplied
   migration. Generalised so warnings, errors and info all share a shape.
   ═══════════════════════════════════════════════════════════════════ */
.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--muted);
  border-radius: var(--radius-btn);
  background: var(--surface);
  font-size: var(--fs-sm);
  color: var(--text);
}

.notice-icon { flex: none; margin-top: 0.15em; color: var(--muted); }
.notice-body { min-width: 0; }
.notice-title { font-weight: 700; margin: 0 0 0.15rem; }
.notice code {
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  background: var(--surface-hover);
  font-size: 0.92em;
  color: inherit;
}

.notice.is-warning { border-left-color: var(--c-amber); background: var(--c-amber-bg); }
.notice.is-warning .notice-icon { color: var(--c-amber); }
.notice.is-danger  { border-left-color: var(--c-red);   background: var(--c-red-bg); }
.notice.is-danger  .notice-icon { color: var(--c-red); }
.notice.is-success { border-left-color: var(--c-green); background: var(--c-green-bg); }
.notice.is-success .notice-icon { color: var(--c-green); }
.notice.is-info    { border-left-color: var(--c-blue);  background: var(--c-blue-bg); }
.notice.is-info    .notice-icon { color: var(--c-blue); }

/* ═══════════════════════════════════════════════════════════════════
   11. TOOLBARS

   A titled action strip above a table or inside a panel. This is the
   modern shape that .toolBar / .settingTab are bridged onto in §13.
   ═══════════════════════════════════════════════════════════════════ */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  height: auto;              /* legacy .toolBar hard-coded 35px */
  font-size: var(--fs-base);
}

.toolbar-title {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* Segmented control (Day / Week, List / Grid). */
.segmented {
  display: inline-flex;
  padding: 0.2rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-hover);
}
.segmented > * {
  padding: 0.3rem 0.85rem;
  border: 0;
  border-radius: 999px;
  background: none;
  font-size: var(--fs-xs);
  font-weight: 650;
  color: var(--muted);
  cursor: pointer;
}
.segmented > .active { background: var(--brand); color: #fff; }

/* ═══════════════════════════════════════════════════════════════════
   12. DEVICE & PREVIEW FRAMES

   The receipt and mobile-screen previews mock a real device, so their pixel
   dimensions are meaningful and kept. Only the chrome is modernised — the
   legacy versions used a 1px #333 border and a background JPG of a phone.
   ═══════════════════════════════════════════════════════════════════ */
.preview-frame {
  margin: var(--sp-4) auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.preview-bar {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
  background: var(--surface-hover);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}

/* ═══════════════════════════════════════════════════════════════════
   13. LEGACY BRIDGE

   Old class names, modern rendering. Each block notes which views still
   emit the name; when the last one is converted, delete the block.

   These are intentionally *aliases*, not re-implementations — they point at
   the components above so there is only ever one source of truth for how a
   toolbar or a panel looks.
   ═══════════════════════════════════════════════════════════════════ */

/* .toolBar — section header strip.
   Used by: account/*, emails/emails_view, files/*, settings/*  (15 views) */
.toolBar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  height: auto;
  padding: var(--sp-3) 0;
  margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-lg);
  font-weight: 650;
  line-height: 1.4;
  text-align: left;
  color: var(--text);
}
.toolBar a { font-size: var(--fs-sm); font-weight: 650; cursor: pointer; }

/* .settingTab — was a right-floated 35px tab. Now a quiet pill that sits in
   the toolbar's flex row instead of floating out of it.
   Used by: account/*, emails/*, files/searchcodes, settings/*  (8 views) */
.settingTab {
  position: static;
  float: none;
  height: auto;
  margin: 0;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-hover);
  font-size: var(--fs-xs);
  font-weight: 650;
  color: var(--muted);
  text-align: center;
  cursor: pointer;
}
.settingTab:hover { border-color: var(--brand); color: var(--text); }
.settingTab a { color: inherit; }

/* .editButton — 24px icon anchored to the corner of its container. The
   positioning contract is load-bearing (parents are position:relative), so
   only the appearance changes.
   Used by: settings/appdata, mobile, receipt, roomsettings, settings_510 */
.editButton {
  position: absolute;
  top: var(--sp-2);
  right: var(--sp-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-btn-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}
.editButton:hover { color: var(--text); border-color: var(--brand); }

/* .formbox / .field300 — a fixed 300px inline-block form column and its
   294px input. Both become fluid so forms reflow on small screens.
   Used by: account/account_view, paypal_subscribe, signup/* */
.formbox {
  display: block;
  position: relative;
  width: 100%;
  max-width: 26rem;
  margin: 0 0 var(--sp-4);
  padding: 0;
  text-align: left;
  vertical-align: top;
}
.field300 { width: 100%; }

/* .customFile — file-input row; legacy indented it 42px to clear a phone
   mockup that no longer sits behind it.
   Used by: settings/appdata, settings/roomsettings */
.customFile {
  position: relative;
  width: 100%;
  max-width: 26rem;
  min-height: auto;
  margin-left: 0;
  line-height: 1.5;
  text-align: left;
}

/* .loginbox — the login card. Legacy painted Ptouch_loginbox.png behind it.
   Used by: login/password_view, login/passwordconfirm_view */
.loginbox {
  background: var(--surface);
  background-image: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  width: 100%;
  max-width: 26rem;
  margin: var(--sp-7) auto var(--sp-6);
  padding: var(--sp-5);
  height: auto;
}

/* .subslogan — was 25px right-aligned Arial Narrow in legacy blue.
   Used by: login/privacypolicy, support, suspendedaccount, termsofuse */
.subslogan {
  font-family: inherit;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--muted);
  text-align: left;
  margin: 0 0 var(--sp-4);
}

/* .tandcbox — scrolling terms panel.  Used by: signup/subscribe */
.tandcbox {
  height: 18rem;
  overflow: auto;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  font-size: var(--fs-sm);
}

/* .expText — explanatory small print under a setting.
   Used by: settings/settings_view_510 */
.expText {
  text-align: left;
  color: var(--muted);
  font-size: var(--fs-xs);
  padding-top: var(--sp-2);
  line-height: 1.5;
}

/* Device previews. Geometry preserved (they mock real screens), chrome new.
   Used by: settings/receipt_view, settings/mobile_view, settings/appdata */
.receipt {
  width: 100%;
  max-width: 30rem;
  height: auto;
  min-height: 40rem;
  margin: var(--sp-4) auto;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-card);
  font-size: var(--fs-sm);
}

.mobile {
  width: 100%;
  max-width: 22rem;
  height: auto;
  margin: var(--sp-4) auto;
  padding: var(--sp-3);
  background-image: none;    /* was iPhoneBG.png */
  border: 1px solid var(--border);
  border-radius: var(--radius-premium);
  background-color: var(--surface);
  box-shadow: var(--shadow-card);
}

.mobileScreen {
  width: 100%;
  max-width: 20rem;
  height: 30rem;
  margin: 0 auto;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--surface-hover);
}

.iPhoneBanner {
  position: relative;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  padding: var(--sp-2);
  overflow: hidden;
  background-color: var(--brand);
  color: #fff;
  border-radius: var(--radius-btn) var(--radius-btn) 0 0;
  text-align: center;
  font-weight: 650;
}

/* Legacy layout blocks that hard-coded pixel widths. These wrapped whole
   pages, so the fixed widths are what stopped every list screen from using
   the viewport.  Used by: settings_view_510, appdata */
.banner, .browserTitle, .imgBox, .snBox, .snListBox {
  width: auto;
  max-width: 100%;
  height: auto;
  position: static;
  float: none;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
}
.browserTitle {
  padding: var(--sp-2) 0;
  margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  color: var(--text);
}
.snListBox {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-2);
  cursor: pointer;
}

/* Bare <table> markup that has not been converted to .dt yet. Without this
   an unconverted list renders with no spacing at all once the legacy sheet
   is gone. Deliberately minimal — it is a floor, not a design. */
.pagecontainer table:not(.dt):not(.cal):not([class*="fc-"]) {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.pagecontainer table:not(.dt):not(.cal):not([class*="fc-"]) :is(th, td) {
  padding: var(--dt-cell-y) var(--dt-cell-x);
  border: 0;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}
.pagecontainer table:not(.dt):not(.cal):not([class*="fc-"]) th {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
}

/* ═══════════════════════════════════════════════════════════════════
   14. RESPONSIVE

   Legacy was a fixed 1038px page with no breakpoints at all; on a phone the
   whole app scrolled sideways. Staff run this from the floor on tablets and
   phones, so the list screens in particular have to work small.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 767.98px) {
  :root { --dt-cell-x: 0.65rem; --dt-cell-y: 0.6rem; }

  .page-head { align-items: flex-start; }
  .page-title { font-size: var(--fs-xl); }
  .page-actions { width: 100%; }
  .page-actions > .btn { flex: 1 1 auto; }

  .pager { justify-content: center; }
  .toolBar, .toolbar { align-items: flex-start; }

  .panel-body, body.singular-app .card-body,
  .panel-head, body.singular-app .card-header { padding: var(--sp-3); }
}

@media (prefers-reduced-motion: reduce) {
  body.singular-app *,
  body.singular-app *::before,
  body.singular-app *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* Party slideshow experience builder. */
.party-media-upload{display:grid;grid-template-columns:1fr 180px minmax(240px,1.4fr) 120px auto;gap:.75rem;align-items:end}.party-media-upload label{display:grid;gap:.3rem;font-size:.8rem;font-weight:700}
@media(max-width:900px){.party-media-upload{grid-template-columns:1fr}}
.experience-explainer{display:flex;align-items:center;justify-content:center;gap:1.5rem;text-align:center}.experience-explainer>div{display:grid;gap:.25rem;justify-items:center;max-width:220px}.experience-explainer>div>i{font-size:1.5rem;color:var(--primary)}.experience-explainer span{color:var(--muted);font-size:.82rem}.experience-theme-form{display:grid;grid-template-columns:minmax(180px,1fr) minmax(180px,1fr) minmax(220px,1.4fr) auto auto;gap:1rem;align-items:end}.experience-theme-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:1rem}.experience-theme-card>header{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}.experience-theme-card>header>div{display:flex;gap:.75rem}.experience-theme-card h2{font-size:1.1rem;margin:0}.experience-theme-card header p{color:var(--muted);margin:.2rem 0 0}.theme-preview{width:42px;height:42px;border-radius:12px;background:linear-gradient(135deg,#6d28d9,#ec4899);box-shadow:inset 0 0 0 1px rgba(255,255,255,.25)}.theme-preview-space,.theme-preview-dark{background:linear-gradient(135deg,#070b20,#5546b8)}.theme-preview-gaming,.theme-preview-slime{background:linear-gradient(135deg,#081c15,#39ff14)}.theme-preview-sunrise,.theme-preview-party{background:linear-gradient(135deg,#ff7a18,#ffcf40)}.theme-preview-forest{background:linear-gradient(135deg,#18392b,#75b798)}.experience-card-settings{display:grid;gap:.75rem;margin-top:1rem}.experience-card-settings>label:not(.form-check){display:grid;gap:.3rem;font-size:.82rem;font-weight:700}.experience-colors{display:flex;gap:1rem}.experience-colors label{display:grid;gap:.25rem;color:var(--muted);font-size:.75rem}.experience-current-audio{display:flex;gap:.5rem;align-items:center;font-size:.82rem}.experience-current-audio label{margin-left:auto}.experience-backgrounds{border-top:1px solid var(--border);margin-top:1rem;padding-top:1rem}.experience-backgrounds h3{font-size:.95rem}.experience-backgrounds>p{font-size:.82rem;color:var(--muted)}.background-thumb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:.5rem}.background-thumb-grid figure{margin:0}.background-thumb-grid img{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:8px}.background-thumb-grid figcaption{font-size:.72rem;margin-top:.25rem}.background-upload-form{display:grid;grid-template-columns:1fr 1.5fr auto auto;gap:.5rem;align-items:center;margin-top:1rem}.party-theme-picker{display:flex;align-items:end;gap:.75rem}.party-theme-picker label{margin:0}.party-theme-picker select{max-width:420px}.party-experience-summary{display:flex;align-items:center;gap:.5rem;margin:.5rem 0;color:var(--muted);font-size:.78rem}.slide-composer-layout{display:grid;grid-template-columns:minmax(300px,.8fr) minmax(420px,1.2fr);gap:1.5rem}.slide-composer-controls{display:grid;gap:1rem}.slide-composer-controls>label,.text-layer-controls>label{display:grid;gap:.3rem;font-weight:700;font-size:.82rem}.text-layer-controls{border:1px solid var(--border);border-radius:12px;padding:.75rem}.text-layer-controls legend{float:none;width:auto;padding:0 .35rem;margin:0;font-size:.8rem;font-weight:800}.text-layer-controls>div{display:grid;grid-template-columns:1fr auto 120px;gap:.75rem;align-items:end;margin-top:.5rem}.text-layer-controls>div label{display:grid;gap:.25rem;font-size:.72rem;color:var(--muted)}.slide-composer-stage{position:relative;aspect-ratio:16/9;overflow:hidden;border-radius:14px;background:#161824 center/cover no-repeat;box-shadow:0 12px 30px rgba(0,0,0,.25)}.slide-safe-zone{position:absolute;inset:5%;border:1px dashed rgba(255,255,255,.55);pointer-events:none}.composed-layer{position:absolute;transform:translate(-50%,-50%);padding:.25rem;line-height:1.08;text-shadow:0 2px 8px #000;cursor:move;user-select:none;white-space:pre-wrap}.composed-layer.headline{font-weight:700}.party-slide-list{display:grid;gap:.6rem}.party-slide-list article{display:grid;grid-template-columns:120px 1fr auto;gap:1rem;align-items:center;padding:.6rem;border:1px solid var(--border);border-radius:12px}.party-slide-list img,.slide-placeholder{width:120px;aspect-ratio:16/9;object-fit:cover;border-radius:8px}.slide-placeholder{display:grid;place-items:center;background:var(--surface-2);font-size:1.5rem}.party-slide-list h3{font-size:.95rem;margin:.25rem 0}.party-slide-list p{margin:0;color:var(--muted);font-size:.8rem}.idle-slides-callout{border-left:4px solid var(--primary)}
@media(max-width:900px){.experience-theme-form{grid-template-columns:1fr 1fr}.slide-composer-layout{grid-template-columns:1fr}.experience-explainer{align-items:stretch}.experience-explainer>i{display:none}}@media(max-width:575px){.experience-theme-form,.background-upload-form{grid-template-columns:1fr}.experience-theme-grid{grid-template-columns:1fr}.experience-explainer{display:grid}.party-theme-picker{align-items:stretch;flex-direction:column}.party-slide-list article{grid-template-columns:80px 1fr}.party-slide-list img,.slide-placeholder{width:80px}.party-slide-list form{grid-column:2}.slide-composer-layout{display:block}.slide-composer-stage{margin-top:1rem}}
