/* ============================================================================
   SANTHOM PAY — ORGANISATION ADMIN PORTAL
   ----------------------------------------------------------------------------
   Loaded *after* site.css by the two application layouts — _PortalLayout for the
   signed-in portal and _OnboardingLayout for registration and sign-in. Everything
   here is built on the tokens site.css already declares — no new colour, no new
   spacing scale, no new radius. If a value below is not a var(), that is a bug.

   WHY A SECOND FILE RATHER THAN A SECTION 21 IN site.css
   The landing page is production code and its stylesheet is frozen. A separate
   file means site.css is byte-identical, so the public page cannot be affected by
   anything in here — the strongest possible guarantee, and cheaper than reviewing
   a 130 KB diff every time the portal gains a component.

   The portal reuses site.css sections 1-19 in full: .btn, .card, .badge, .field,
   .input, .table, .stat, .empty, .alert. This file adds only what a left-rail
   shell needs and site.css has no vocabulary for.
   ============================================================================ */

/* ---------------------------------------------------------------- shell ---- */

.pt-shell {
  display: grid;
  grid-template-columns: 264px 1fr;
  min-height: 100vh;
  background: var(--surface-1);
}

.pt-main {
  display: flex;
  flex-direction: column;
  min-width: 0;   /* lets wide tables scroll inside their own box instead of
                     stretching the grid column and pushing the page sideways */
}

.pt-content {
  padding: var(--s-7) var(--s-7) var(--s-10);
  max-width: 1280px;
  width: 100%;
}

/* -------------------------------------------------------------- sidebar ---- */

.pt-side {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  padding: var(--s-5) var(--s-4);
  background: var(--surface-0);
  border-right: 1px solid var(--border);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.pt-side-brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  text-decoration: none;
  color: inherit;
}

.pt-side-brand .brand-mark { flex: 0 0 auto; }

.pt-side-org {
  font-size: 0.78rem;
  color: var(--ink-500);
  line-height: 1.3;
}

.pt-nav { display: flex; flex-direction: column; gap: var(--s-1); }

.pt-nav-group {
  padding: var(--s-4) var(--s-3) var(--s-1);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-400);
}

.pt-nav-link {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  color: var(--ink-700);
  text-decoration: none;
  font-weight: 500;
  line-height: 1.2;
  /* 44px minimum target, same rule the landing page follows */
  min-height: 44px;
}

.pt-nav-link:hover { background: var(--surface-2); color: var(--ink-900); }

.pt-nav-link .icon { flex: 0 0 auto; width: 20px; height: 20px; color: var(--ink-500); }

.pt-nav-link[aria-current="page"] {
  background: var(--brand-050);
  color: var(--brand-700);
  font-weight: 600;
}

.pt-nav-link[aria-current="page"] .icon { color: var(--brand-600); }

.pt-nav-sub { display: flex; flex-direction: column; gap: var(--s-1); padding-left: var(--s-8); }

.pt-nav-sub .pt-nav-link { min-height: 38px; padding-block: var(--s-2); font-size: 0.9rem; }

/* A placeholder is a roadmap item, not a broken link. It is visibly inert and says
   so in words — a disabled-looking thing that still navigates reads as a bug, and a
   link that 404s reads as a worse one. */
.pt-nav-link.is-soon {
  color: var(--ink-400);
  cursor: default;
  pointer-events: none;
}

.pt-nav-link.is-soon .icon { color: var(--ink-300); }

.pt-soon {
  margin-left: auto;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-400);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  padding: 2px var(--s-2);
}

/* --------------------------------------------------------------- topbar ---- */

.pt-top {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-7);
  background: var(--surface-0);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
}

.pt-top-title { font-size: 1.05rem; font-weight: 650; margin: 0; }
.pt-top-actions { margin-left: auto; display: flex; align-items: center; gap: var(--s-3); }

.pt-user { display: flex; align-items: center; gap: var(--s-3); }

.pt-avatar {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--brand-100);
  color: var(--brand-700);
  font-weight: 700;
  font-size: 0.85rem;
}

.pt-user-name { font-size: 0.88rem; font-weight: 600; line-height: 1.2; }
.pt-user-role { font-size: 0.75rem; color: var(--ink-500); }

/* ----------------------------------------------------------- breadcrumb ---- */

.pt-crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2);
  font-size: 0.82rem; color: var(--ink-500);
  margin-bottom: var(--s-4);
}

.pt-crumbs a { color: var(--ink-600); text-decoration: none; }
.pt-crumbs a:hover { color: var(--brand-600); text-decoration: underline; }
.pt-crumbs [aria-current="page"] { color: var(--ink-800); font-weight: 600; }
.pt-crumbs-sep { color: var(--ink-300); }

/* ------------------------------------------------------------- headings ---- */

.pt-head {
  display: flex; align-items: flex-start; gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-6);
}

.pt-head h1 { margin: 0 0 var(--s-1); font-size: 1.6rem; line-height: 1.2; }
.pt-head p { margin: 0; color: var(--ink-600); }
.pt-head-actions { margin-left: auto; display: flex; gap: var(--s-3); flex-wrap: wrap; }

/* ------------------------------------------------------------ dashboard ---- */

.pt-grid { display: grid; gap: var(--s-5); }
.pt-grid-stats { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.pt-grid-split { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.pt-quick { display: flex; flex-direction: column; gap: var(--s-3); }

/* ------------------------------------------------------------------ tabs ---- */

/* The tab strip is horizontally scrollable on purpose: Phase 1 has one tab and the
   design anticipates fifteen. Wrapping them onto three rows is what makes an
   enterprise form look unfinished. */
.pt-tabs {
  display: flex;
  gap: var(--s-1);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--s-6);
  overflow-x: auto;
  scrollbar-width: thin;
}

.pt-tab {
  flex: 0 0 auto;
  padding: var(--s-3) var(--s-4);
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--ink-600);
  font: inherit;
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  min-height: 44px;
}

.pt-tab:hover { color: var(--ink-900); }

.pt-tab[aria-current="page"] {
  color: var(--brand-700);
  border-bottom-color: var(--brand-600);
}

.pt-tab.is-soon { color: var(--ink-300); cursor: default; pointer-events: none; }

/* --------------------------------------------------------- link preview ---- */

/* The generated public link, shown beside the slug field. Read-only by design: the
   organiser controls the slug, and the link is what the slug produces. Showing it
   live is what makes "this cannot change after publishing" intelligible before they
   publish rather than after. */
.pt-linkpreview {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-top: var(--s-2);
  padding: var(--s-2) var(--s-3);
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  color: var(--ink-600);
}

.pt-linkpreview code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  color: var(--ink-800);
  word-break: break-all;
}

/* The organisations sitting in a status, under its badge on the dashboard.

   A list rather than a comma-joined line: names run to four or five words here
   ("Hillside Cultural Society"), and separating those with commas leaves the
   reader working out where one organisation ends and the next begins. One per
   line answers "who is in this state" at a glance, which is the only question
   this panel is for — the count beside it and the View link own the rest. */
.pt-status-orgs {
  list-style: none;
  margin: var(--s-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--t-sm);
  color: var(--ink-700);
}

/* Long names wrap rather than widening the column and pushing the count and the
   View button out of the card. */
.pt-status-orgs li { overflow-wrap: anywhere; }

/* ------------------------------------------------------------ responsive ---- */

@media (max-width: 960px) {
  .pt-shell { grid-template-columns: 1fr; }

  .pt-side {
    position: static;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--s-4);
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }

  .pt-side-brand { flex: 0 0 auto; }
  .pt-nav { flex-direction: row; align-items: center; gap: var(--s-2); }
  .pt-nav-group, .pt-side-org { display: none; }
  .pt-nav-sub { display: none; }
  .pt-content { padding: var(--s-5) var(--s-4) var(--s-8); }
  .pt-top { padding-inline: var(--s-4); }
}

@media (max-width: 560px) {
  .pt-user-name, .pt-user-role { display: none; }
  .pt-head-actions { width: 100%; }

  /* ---------------------------------------------------- stacked table ----
     One block per row instead of a table that scrolls sideways.

     A three-column table inside the console's card needs 345px at a 375px
     viewport and has 261px — measured. .table-scroll then does what it is for
     and scrolls horizontally, which on this table means the organisation name
     is compressed into a 134px column four lines tall while the submitted date
     and the Review button sit off the right edge. The name is the one thing
     the row is about, so it is the wrong thing to lose.

     Opt-in via .pt-table-stack, not applied to .table, because the booking
     journey's tables are genuine numeric grids where the columns have to stay
     side by side to be compared. Every rule is inside this query, so the
     desktop layout is not touched.

     The honest cost: display:block removes the row and column relationships
     from the accessibility tree. That is why each cell carries its heading in
     data-label — the information stays, the grid does not. Against a table
     whose first column is unreadable and whose last is off-screen, this is the
     better trade at this width. */
  .pt-table-stack,
  .pt-table-stack tbody,
  .pt-table-stack tr,
  .pt-table-stack td {
    display: block;
    width: 100%;
  }

  /* The headings move into the cells below, so the row of them is redundant —
     hidden the way .sr-only does it rather than with display:none, which would
     also take it from a screen reader. */
  .pt-table-stack thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The border between rows becomes the divider between blocks. */
  .pt-table-stack tr {
    padding: var(--s-4) 0;
    border-bottom: 1px solid var(--border);
  }

  .pt-table-stack tr:last-child { border-bottom: 0; }
  .pt-table-stack tr:hover { background: none; }

  .pt-table-stack td {
    padding: 0 0 var(--s-2);
    border-bottom: 0;
  }

  .pt-table-stack td:last-child { padding-bottom: 0; }

  /* The column heading, carried down with its cell. Same treatment .table th
     already uses, so a stacked row reads like the table it came from. */
  .pt-table-stack td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--t-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-500);
    font-weight: 700;
    margin-bottom: 2px;
  }

  /* The organisation name leads the block and needs no label above it. Full
     width, so a long name wraps as prose instead of down a narrow column. */
  .pt-cell-primary { font-size: var(--t-md); }

  /* A right-aligned figure has nothing to align against once stacked. */
  .pt-table-stack td.num { text-align: left; }

  /* ------------------------------------------------ status breakdown ----
     Keeps its three columns where the queue table stacks.

     Stacking is right when every cell holds a sentence. Here the cells are a
     badge, one digit and a small button: turned into full-width blocks, the
     count and the View link each took a line of their own and no longer read as
     belonging to the status above them. The fix is not to stack this one.

     table-layout: fixed is what makes it hold: without it the first column is
     sized from its widest word, so a long organisation name widens column one
     and shoves the count and the button out of the card. Fixed layout means the
     two narrow columns take the widths set below, column one takes whatever is
     left, and the names wrap inside it — the primary row stays put however long
     a name is. */
  .pt-status-table { table-layout: fixed; width: 100%; }

  /* Top, not middle. .table td centres its content vertically, so beside a cell
     three names tall the count and the button drifted to the middle of the block
     instead of sitting on the badge's line. */
  .pt-status-table td {
    vertical-align: top;
    padding: var(--s-3) var(--s-2);
  }

  /* The card already provides the outer gutter. */
  .pt-status-table td:first-child { padding-left: 0; }
  .pt-status-table td:last-child { padding-right: 0; }

  /* Fixed so every row's count and button line up in the same place, whatever
     is above them. Sized to the content they actually hold — counts here are
     one or two digits, and the button says "View". */
  .pt-status-count { width: 2.5rem; }
  .pt-status-action { width: 4.5rem; }

  /* The button fills its column rather than sitting at an arbitrary width, which
     is what gives the third column one edge down the whole table. */
  .pt-status-action .btn { width: 100%; padding-inline: 0; }
}

/* ============================================================================
   ONBOARDING — registration, verification, sign-in
   ----------------------------------------------------------------------------
   Used by _OnboardingLayout. A narrow, centred column rather than the portal's
   left rail: nobody on these pages has an organisation yet, so there is nothing
   to navigate to and a sidebar would be an empty promise.
   ============================================================================ */

.ob-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--surface-1);
}

.ob-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-6);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.ob-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  text-decoration: none;
  color: inherit;
}

.ob-top-actions { display: flex; align-items: center; gap: var(--s-3); }

.ob-main {
  flex: 1;
  width: 100%;
  max-width: 780px;
  margin-inline: auto;
  padding: var(--s-8) var(--s-5) var(--s-10);
}

/* The profile step has four sections of two-column rows; 780px squeezes it. */
.ob-main-wide { max-width: 1040px; }

.ob-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-5) var(--s-6);
  border-top: 1px solid var(--border);
  font-size: var(--t-sm);
  color: var(--ink-500);
}

.ob-head { margin-bottom: var(--s-6); }
.ob-head h1 { margin: 0 0 var(--s-2); }
.ob-head p { margin: 0; color: var(--ink-600); }

/* --------------------------------------------------------------- steps ---- */

.ob-steps {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  list-style: none;
  margin: 0 0 var(--s-6);
  padding: 0;
  overflow-x: auto;
}

.ob-step {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: 0 0 auto;
  font-size: var(--t-sm);
  color: var(--ink-500);
}

/* The connector between steps. A pseudo-element on the FOLLOWING item rather
   than a border on each one, so the last step does not trail a line into
   nothing. */
.ob-step + .ob-step::before {
  content: "";
  width: 28px;
  height: 2px;
  background: var(--border);
  margin-right: var(--s-2);
}

.ob-step-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--surface);
  font-size: var(--t-sm);
  font-weight: 700;
  flex: 0 0 auto;
}

.ob-step-dot .icon { width: 16px; height: 16px; }

.ob-step.is-current { color: var(--ink-900); font-weight: 600; }
.ob-step.is-current .ob-step-dot { border-color: var(--brand-600); color: var(--brand-600); }

.ob-step.is-done .ob-step-dot {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: #fff;
}

/* -------------------------------------------------------- form sections ---- */

/* A titled block inside a long form. The profile step has four; without the
   grouping it is thirty fields in one column and nobody finishes it. */
.ob-section + .ob-section {
  margin-top: var(--s-6);
  padding-top: var(--s-6);
  border-top: 1px solid var(--border);
}

.ob-section-head { margin-bottom: var(--s-4); }
.ob-section-head h2 { margin: 0 0 var(--s-1); font-size: var(--t-md); }
.ob-section-head p { margin: 0; font-size: var(--t-sm); color: var(--ink-500); }

/* Two columns where there is room, one where there is not. auto-fit rather than
   a fixed count, so this needs no breakpoint of its own. */
.ob-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0 var(--s-5);
}

.ob-grid-full { grid-column: 1 / -1; }

.ob-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  margin-top: var(--s-6);
  padding-top: var(--s-5);
  border-top: 1px solid var(--border);
}

.ob-actions-end { margin-left: auto; }

/* ----------------------------------------------------- result / outcome ---- */

/* Verification results and the submitted confirmation. Centred, with room for
   the illustration — these pages carry one message and should look like it. */
.ob-result { text-align: center; padding: var(--s-6) var(--s-4); }
.ob-result h1 { margin: var(--s-5) 0 var(--s-3); }
.ob-result p { margin: 0 auto var(--s-4); max-width: 52ch; color: var(--ink-600); }
.ob-result-art { display: block; margin-inline: auto; width: 100%; max-width: 220px; height: auto; }

.ob-result-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  justify-content: center;
  margin-top: var(--s-6);
}

/* ------------------------------------------------------- password meter ---- */

.ob-meter { display: block; margin-top: var(--s-2); }

.ob-meter-track {
  display: block;
  height: 6px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  overflow: hidden;
}

.ob-meter-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: var(--r-sm);
  background: var(--danger-600);
  transition: width var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out);
}

.ob-meter[data-score="1"] .ob-meter-fill { width: 25%; }
.ob-meter[data-score="2"] .ob-meter-fill { width: 50%;  background: var(--warn-600); }
.ob-meter[data-score="3"] .ob-meter-fill { width: 75%;  background: var(--warn-600); }
.ob-meter[data-score="4"] .ob-meter-fill { width: 100%; background: var(--ok-600); }

@media (max-width: 560px) {
  .ob-main { padding: var(--s-6) var(--s-4) var(--s-8); }
  .ob-step-label { display: none; }
  .ob-step + .ob-step::before { width: 16px; }
  .ob-top-hint { display: none; }
}

/* ============================================================================
   CONFIRMATION DIALOG
   ----------------------------------------------------------------------------
   Rejecting and suspending an organisation both need a REASON, and that reason
   is emailed to the applicant word for word. window.confirm() cannot collect
   one — it returns a boolean — so these actions need a real dialog.

   <dialog> rather than a hand-built overlay: the browser provides focus
   trapping, Escape-to-close, inertness of the page behind it and the top layer
   for free, and a div-based modal gets at least one of those wrong.
   ============================================================================ */

.pt-dialog {
  width: min(520px, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--ink-900);
  box-shadow: var(--shadow-lg);
}

.pt-dialog::backdrop { background: rgb(0 0 0 / 0.45); }

.pt-dialog-head { padding: var(--s-5) var(--s-5) 0; }
.pt-dialog-head h2 { margin: 0 0 var(--s-2); font-size: var(--t-md); }
.pt-dialog-head p  { margin: 0; font-size: var(--t-sm); color: var(--ink-600); }

.pt-dialog-body { padding: var(--s-5); }

.pt-dialog-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* Motion is opt-in across this product — the reveal animations on the public
   page are gated the same way — so a reader who asked for less movement gets a
   dialog that simply appears. */
@media (prefers-reduced-motion: no-preference) {
  .pt-dialog[open] { animation: pt-dialog-in 160ms var(--ease-out); }

  @keyframes pt-dialog-in {
    from { opacity: 0; transform: translateY(6px) scale(0.98); }
    to   { opacity: 1; transform: none; }
  }
}

/* --------------------------------------------------------------- detail ---- */

/* Label/value pairs on the organisation detail page. A description list,
   because that is what it is — and it reads correctly to a screen reader with
   no extra markup. */
.pt-detail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s-5);
  margin: 0;
}

.pt-detail > div { min-width: 0; }

.pt-detail dt {
  font-size: var(--t-sm);
  color: var(--ink-500);
  margin-bottom: var(--s-1);
}

.pt-detail dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }

/* ------------------------------------------------------------- timeline ---- */

.pt-timeline { list-style: none; margin: 0; padding: 0; }

.pt-timeline li {
  position: relative;
  padding: 0 0 var(--s-5) var(--s-6);
  border-left: 2px solid var(--border);
}

.pt-timeline li:last-child { border-left-color: transparent; padding-bottom: 0; }

.pt-timeline li::before {
  content: "";
  position: absolute;
  left: -6px;
  top: 4px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand-600);
}

.pt-timeline-when { font-size: var(--t-sm); color: var(--ink-500); }
.pt-timeline-what { font-weight: 600; }
.pt-timeline-why  { font-size: var(--t-sm); color: var(--ink-600); margin-top: var(--s-1); }

/* ------------------------------------------------------- venue map picker ---- */

/* Google Maps draws its own controls and marker inside the frame. Everything here is
   the surrounding chrome — the search row and the frame itself — written in the design
   system's own tokens so the picker looks like part of the portal rather than like a
   widget dropped into it. */

.pt-mapsearch {
  display: flex;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-bottom: var(--s-2);
}

.pt-mapsearch .input { flex: 1 1 260px; min-width: 0; }

.pt-map {
  height: 340px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;

  /* The map stacks its own controls; without this they sit above the sticky topbar
     when the page scrolls. */
  z-index: 0;
}
