/*
|------------------------------------------------------------------------------
| The admin panel
|------------------------------------------------------------------------------
|
| Its own stylesheet, because it is its own document. The site's `main.css` is
| 8,500 lines of a marketing surface -- hero bands, search bar, fare cards, a
| footer of directories -- and the panel uses none of it.
|
| **The palette is Orchid's, as bought (A10, #286)**, not the site's. A3.5 had
| this file copy the site's teal so the panel "looked like the same people
| made it"; A10 buys a dashboard template specifically for its design, and
| keeping the old palette under Bootstrap's components would be wearing one
| coat over another. So this is Orchid's own token set
| (`assets/css/orchid.css`), renamed onto the variable names the rest of this
| file already reads -- `--signal` is Orchid's `--orchid-primary`, `--ground`
| is `--orchid-bg`, and so on -- so every component this task does not touch
| keeps working, unaware its colours moved. `AdminShellTest`'s old parity
| check against `main.css` is gone with it: there is nothing left to stay in
| step with.
|
| The rows/tables/forms this bought (`.group`, `.sheet`, `.field`, `.pair`,
| `.pill`, `.tile`, most of `.button`) have since been rebuilt onto Orchid's
| own Bootstrap components page by page (G2.1-G2.5, #287-#291) and removed
| once the last page using one was; `.flag`/`.notice`/`.band`/`.field__hint`
| are what is left of the panel's own row-and-form vocabulary today.
|
| Nothing external is loaded except the typeface, self-hosted the same way
| Bootstrap and its icons are (A10.1, #287): no CDN, no jQuery, no Font
| Awesome.
|
| What is *not* Orchid's is the density and the fixed-width type on data. The
| chrome wears the template; the rows are a board of slugs, counts and cron
| lines, and those read better in a column that lines up.
|
*/

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-latin.woff2") format("woff2");
  /* Latin only, matching Plus Jakarta Sans' own subsetting on the public
     side -- the panel shows slugs, commands and English labels. */
  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;
}

:root {
  --ground:      #F5F6FA;   /* orchid.css --orchid-bg */
  --surface:     #FFFFFF;   /* --orchid-surface -- the sidebar and header wear this too, not a separate band */
  --sunken:      #F2F3F8;   /* --orchid-hover */
  --rule:        #E9ECF3;   /* --orchid-border */
  --rule-strong: #D8DCE8;   /* Orchid has one border strength; a second is interpolated for this file's own two-strength components */

  --ink:         #1E2436;   /* --orchid-text */
  --ink-quiet:   #6B7385;   /* --orchid-text-muted */
  --ink-faint:   #9AA1B5;   /* interpolated, as above */

  /* Orchid's indigo, and the cyan it pairs with in every gradient accent --
     the brand mark's text, the active nav bar, the primary button. */
  --signal:       #4F46E5;   /* --orchid-primary */
  --signal-accent: #22D3EE;  /* --orchid-accent */
  --signal-soft:  #EEEDFC;   /* tint of --signal, Orchid's own `rgba(79,70,229,.10)` flattened onto --surface */
  --signal-edge:  #C7C2F5;
  --brand-gradient: linear-gradient(90deg, var(--signal), var(--signal-accent));

  /* Orchid's own success/danger, lifted from `auth.css` -- the only place the
     template states them, since the base file leaves semantic colour to
     Bootstrap's own defaults everywhere else. Darkened from Orchid's own
     hex (`#10B981`/`#EF4444`, still visible in the dark palette below):
     neither cleared 4.5:1 as plain text against `--surface`, let alone
     against its own `-soft` chip background -- measured at 2.54:1 and
     3.76:1. These clear both (G5.3, #318). */
  --good:        #0C7A4E;
  --good-soft:   #E3F9F0;
  --good-edge:   #B8ECD8;
  --bad:         #D01414;
  --bad-soft:    #FDECEC;
  --bad-edge:    #F8C9C9;

  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono", Menlo, Consolas, monospace;

  /* Orchid's own: 10px on a nav row or button, 12-18px on a card. */
  --radius: .625rem;
  --radius-card: 1rem;

  /* One row height, everywhere. It is what makes a list scannable, and it is
     the one measurement here that is the panel's own. */
  --row: 2.25rem;
}

/* Follows the machine while nothing has been chosen, and the attribute wins
   when it has -- the same two-state rule the public side uses, so a reader who
   picked dark out there gets dark in here. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:      #0F1220;
    --surface:     #171A2B;
    --sunken:      #1E2338;
    --rule:        #232842;
    --rule-strong: #2F3555;

    --ink:         #E6E8F2;
    --ink-quiet:   #8891A8;
    --ink-faint:   #5B6280;

    --signal:       #818CF8;
    --signal-accent: #22D3EE;
    --signal-soft:  #201F3D;
    --signal-edge:  #383468;

    --good:        #34D399;
    --good-soft:   #0D2B22;
    --good-edge:   #155E42;
    --bad:         #F87171;
    --bad-soft:    #2C1516;
    --bad-edge:    #5C2626;
  }
}

:root[data-theme="dark"] {
  --ground:      #0F1220;
  --surface:     #171A2B;
  --sunken:      #1E2338;
  --rule:        #232842;
  --rule-strong: #2F3555;

  --ink:         #E6E8F2;
  --ink-quiet:   #8891A8;
  --ink-faint:   #5B6280;

  --signal:       #818CF8;
  --signal-accent: #22D3EE;
  --signal-soft:  #201F3D;
  --signal-edge:  #383468;

  --good:        #34D399;
  --good-soft:   #0D2B22;
  --good-edge:   #155E42;
  --bad:         #F87171;
  --bad-soft:    #2C1516;
  --bad-edge:    #5C2626;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Every identifier is fixed-width: a slug, a code, a cron line, a count. It is
   what makes a column of them read as a column, and it is the one thing here
   the public pages do not do -- they have no identifiers to line up. */
code, .mono { font-family: var(--mono); }

a { color: var(--signal); text-decoration: none; }
a:hover { text-decoration: underline; }

/* An `<a class="btn">` is a button first: this rule's own `a:hover` above
   outranks Bootstrap's plain `.btn { text-decoration: none }` by
   specificity, which is what put an underline back on every anchor
   styled as a button in the panel, not just the notification cards'
   (G5.2, #317) -- the same fix already scoped to `.rail__item`/
   `.well__user-menu .dropdown-item`, generalised here because a button's
   own text never underlines regardless of which page it is on. */
.btn:hover, .btn:focus { text-decoration: none; }

/* Visible and on the signal colour, because a panel is keyboard territory. */
:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

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

/* Bootstrap ships no such utility, and a flex item with a long value still
   needs one to keep from pushing its row wide. */
.min-w-0 { min-width: 0; }

/*
|------------------------------------------------------------------------------
| The shell: a rail and a well
|------------------------------------------------------------------------------
*/

.shell { min-height: 100vh; }

/*
| The sidebar is fixed and permanent, the way `.orchid-sidebar` is -- not a
| flex child, because Orchid never lays it out beside the content; the
| content wraps around it instead, via `.well`'s own `margin-left`. That is
| also what makes the collapse-to-icons state (`html[data-rail-collapsed]`) a
| single number to animate rather than a grid track.
*/
.rail {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 1040;
  display: flex;
  flex-direction: column;
  width: 16.25rem;
  background: var(--surface);
  border-right: 1px solid var(--rule);
  transition: transform 220ms ease, width 220ms ease;
}

.rail-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1039;
  background: #0f122080;
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms ease, visibility 220ms ease;
}

.rail-backdrop.is-visible { opacity: 1; visibility: visible; }

@media (max-width: 991.98px) {
  .rail { transform: translateX(-100%); box-shadow: 0 20px 40px #0f122019; }
  .rail.is-open { transform: translateX(0); }
}

@media (min-width: 992px) {
  .well { margin-left: 16.25rem; transition: margin-left 220ms ease; }

  /* Collapsed keeps only the icon column -- the label and the role word
     both disappear with the width that held them, the same trade
     `.orchid-sidebar-collapsed` makes. */
  html[data-rail-collapsed] .rail { width: 5.25rem; }
  html[data-rail-collapsed] .well { margin-left: 5.25rem; }
  html[data-rail-collapsed] .rail__mark-name,
  html[data-rail-collapsed] .rail__mark-role,
  html[data-rail-collapsed] .rail__section-label,
  html[data-rail-collapsed] .rail__item span { display: none; }
  html[data-rail-collapsed] .rail__item { justify-content: center; }
}

.rail__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 4.25rem;
  padding: 1.125rem 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.rail__mark { display: inline-flex; align-items: center; gap: .625rem; color: var(--ink); }
.rail__mark:hover { text-decoration: none; }

/* Brand teal, fixed in both palettes -- `main.css` gives the same reason for
   its own footer tile: a logo is not the thing that themes. */
.rail__mark-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.125rem;
  height: 2.125rem;
  border-radius: .625rem;
  background: #0F766E;
  color: #fff;
  font-size: 1.0625rem;
  flex-shrink: 0;
}

.rail__mark-name {
  display: block;
  font-size: 1.0625rem;
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--ink);
}

/* The word that says which side of the site this is. */
.rail__mark-role {
  display: block;
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}

.rail__body { display: flex; flex-direction: column; flex: 1; overflow-y: auto; padding: 1.25rem 1rem 1.5rem; }

/* Orchid's own `.orchid-nav-section`/`.orchid-nav-section__label`, under
   this project's own naming -- a label above a group of items, the same
   look, none of the demo's page-per-category items to carry along with it. */
.rail__section:last-child .rail__list { margin-bottom: 0; }
.rail__section-label {
  display: block;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  padding: 0 .75rem;
  margin-bottom: .375rem;
}

.rail__list { display: flex; flex-direction: column; gap: .125rem; margin: 0 0 1.25rem; padding: 0; list-style: none; }

.rail__item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .75rem;
  border-radius: var(--radius);
  color: var(--ink-quiet);
  font-size: .875rem;
  font-weight: 500;
  transition: background-color 160ms ease, color 160ms ease;
}

.rail__item:hover { background: var(--sunken); color: var(--ink); text-decoration: none; }
.rail__item .bi { font-size: 1.05rem; min-width: 1.25rem; text-align: center; }

/* The current section carries the gradient bar Orchid marks an active link
   with, so it reads without colour as well as with it. */
.rail__item.is-current {
  position: relative;
  color: var(--signal);
  background: linear-gradient(90deg, #4f46e51a, #22d3ee0f);
}

.rail__item.is-current::before {
  content: "";
  position: absolute;
  left: -1rem;
  top: 20%;
  bottom: 20%;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--brand-gradient);
}

/*
|------------------------------------------------------------------------------
| A rail item with children
|------------------------------------------------------------------------------
|
| Orchid's own pattern for "Dashboard" expanding into Default/Analytics/CRM/...
| (G2.6, #299): Bootstrap's stock Collapse component, already loaded and
| unused elsewhere in this panel -- `data-bs-toggle="collapse"` on the parent
| link, a `.collapse` list as its target, no bespoke JS. The chevron rotates
| off `aria-expanded`, which Bootstrap keeps in sync with the collapse state
| on its own; the server sets the *initial* value (and `.show`) from
| `admin_section`, the same way a plain item's `.is-current` already is.
| Clicking the parent only ever toggles -- `data-bs-toggle` intercepts the
| click before the `href` is followed -- so the `href` is a no-JS fallback,
| not the way this link is normally used.
|
*/

.rail__item[aria-expanded] { cursor: pointer; }

.rail__chevron {
  margin-left: auto;
  font-size: .75rem;
  transition: transform 220ms ease;
}

.rail__item[aria-expanded="true"] .rail__chevron { transform: rotate(180deg); }

.rail__sub {
  margin: .25rem 0 .25rem 1.65rem;
  padding: .125rem 0 .125rem .75rem;
  border-left: 1px solid var(--rule);
  list-style: none;
}

.rail__sublink {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .4rem .625rem;
  border-radius: var(--radius);
  color: var(--ink-quiet);
  font-size: .8125rem;
  transition: background-color 160ms ease, color 160ms ease;
}

.rail__sublink:hover { background: var(--sunken); color: var(--ink); text-decoration: none; }

.rail__sublink::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--rule-strong);
  flex-shrink: 0;
  transition: transform 160ms ease, background-color 160ms ease;
}

.rail__sublink.is-current { color: var(--signal); font-weight: 600; }
.rail__sublink.is-current::before { background: var(--signal); transform: scale(1.4); }

@media (min-width: 992px) {
  html[data-rail-collapsed] .rail__chevron,
  html[data-rail-collapsed] .rail__sub { display: none; }
}

.well { display: flex; flex-direction: column; min-width: 0; }

/* Sticky and blurred, the way `.orchid-header` sits above scrolling content
   rather than scrolling with it. Chrome only -- a breadcrumb and the icon
   toggles -- since the page header below carries the title, the description
   and that page's own actions (G6.1, #329). */
.well__top {
  position: sticky;
  top: 0;
  z-index: 1030;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4.25rem;
  padding: .5rem 1rem;
  background-color: var(--surface);
  border-bottom: 1px solid var(--rule);
  backdrop-filter: saturate(180%) blur(6px);
}

@media (max-width: 575.98px) {
  .well__top { padding: .5rem .75rem; }
}

.well__lead { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.well__top-tools { display: flex; align-items: center; gap: .375rem; }

.well__breadcrumb .breadcrumb {
  align-items: center;
  margin-bottom: 0;
  font-size: .8125rem;
  color: var(--ink-quiet);
}

.well__breadcrumb .breadcrumb a { color: var(--ink-quiet); text-decoration: none; }
.well__breadcrumb .breadcrumb a:hover { color: var(--signal); }
.well__breadcrumb .breadcrumb-item.active { color: var(--ink); font-weight: 500; }

/* Sizing comes from Bootstrap's own `.h3` (`cms-page-title`'s own split, in
   the reference) -- only the weight, tracking and spacing below the title
   are this app's to set. */
.well__title { margin: 0 0 .25rem; font-weight: 700; letter-spacing: -.01em; }
.well__tools { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.well__body { padding: 1.5rem; min-width: 0; }

/* The page's own title, description and actions -- not sticky, unlike
   `.well__top` above: it scrolls away with the content beneath it, the same
   as Orchid's own page header inside `.orchid-main` (G6.1, #329). Wraps for
   the same reason a page's action buttons used to live in a wrapping bar:
   a search box and two buttons next to a long title needs a second line on
   a narrow screen rather than pushing either off it. */
.well__page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.well__description { margin: 0; color: var(--ink-quiet); font-size: .875rem; }

/* Orchid's own `.orchid-footer` (G6.2, #330): a border rather than the
   sticky topbar's blur, since nothing scrolls under a page's last element. */
.well__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: 1.25rem 1.5rem;
  background-color: var(--surface);
  border-top: 1px solid var(--rule);
}

.well__footer a { text-decoration: none; }
.well__footer a:hover { color: var(--ink); }

/*
| One icon button shape, shared by the nav toggle and the theme switch --
| Orchid's own `.btn-icon`, its `--bs-btn-*` variables shrinking `.btn` to a
| square rather than a new set of rules.
*/
.btn-icon {
  --bs-btn-padding-x: .55rem;
  --bs-btn-padding-y: .5rem;
  --bs-btn-color: var(--ink-quiet);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-hover-bg: var(--sunken);
  --bs-btn-active-color: var(--ink);
  --bs-btn-active-bg: var(--sunken);
  --bs-btn-border-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  border-radius: var(--radius);
}

/* A `.btn-icon` sized to sit beside a value rather than in the topbar --
   the copy buttons on identifiers (G3.3, #306). The checkmark it swaps to
   on click reads as confirmation on its own; the tone just says so twice. */
.copy-btn {
  --bs-btn-padding-x: .3rem;
  --bs-btn-padding-y: .2rem;
  font-size: .8rem;
}

.copy-btn.is-copied { --bs-btn-color: var(--good); }

/* The Order column's own pair (`admin/partials/row-action-macros.html.twig`) --
   full `.btn-icon` size reads fine as one button among others in Actions, but
   two of them side by side as their own column read as oversized for what they
   are. Smaller than `.copy-btn` even: that one still sits beside body text,
   this one only ever sits beside its own twin. */
.order-actions .btn-icon {
  --bs-btn-padding-x: .35rem;
  --bs-btn-padding-y: .3rem;
  font-size: .8rem;
}

/* A button's own icon, hidden the moment its neighbouring spinner is not --
   `admin.js`'s `diagnosticsForm()`/`disableOnSubmit()` only ever toggle the
   spinner's own `d-none`, never touch the icon beside it, so without this the
   busy state showed both at once (a real defect this caught, not a style
   preference): a spinner already means "working", and a second glyph beside
   it just repeats that. */
.spinner-border:not(.d-none) + .bi {
  display: none;
}

/* One glyph shown at a time, the same `aria-pressed`-reads-the-icon pattern
   `theme-switcher.html.twig` uses on the public site -- the button's state is
   the one source of truth, not a class kept in step with it. Sun by default
   (pressing it goes dark); the button flips both when it is pressed. */
.well__theme-icon--moon { display: none; }
[aria-pressed="true"] .well__theme-icon--sun { display: none; }
[aria-pressed="true"] .well__theme-icon--moon { display: inline-block; }

/* The command palette (G4.1, #312) -- a search-bar-as-header modal rather
   than the usual title-and-body shape, since the input is the only thing
   worth a reader's attention until they have typed something. */
.palette { overflow: hidden; }

.palette__search {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-quiet);
}

.palette__input {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: 1rem;
}
.palette__input::placeholder { color: var(--ink-faint); }

.palette__results { max-height: 22rem; overflow-y: auto; padding: .5rem 0; }

.palette__group {
  padding: .625rem 1.25rem .25rem;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}

.palette__item {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
  padding: .625rem 1.25rem;
  border: 0;
  background: transparent;
  color: var(--ink);
  text-align: left;
}
.palette__item:hover, .palette__item.is-active { background: var(--sunken); }
.palette__item-icon { color: var(--ink-quiet); flex-shrink: 0; }
.palette__item-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette__item-meta {
  margin-left: auto;
  padding-left: .75rem;
  color: var(--ink-quiet);
  font-size: .8125rem;
  white-space: nowrap;
}

.palette__empty { padding: 2.5rem 1.25rem; text-align: center; color: var(--ink-quiet); font-size: .875rem; }

/* The topbar's own user menu (G6.4, #348) -- Orchid's `.orchid-profile-btn`
   and `.orchid-dropdown--profile` shape (`analytics.html`), renamed into
   this panel's own `.well__` vocabulary rather than its literal class
   names. Scoped to Sign out for now, the same way the dropdown's own
   Profile/Settings/Billing/Help Center items are not here yet -- that is
   the user-profile work still ahead, not this one. */
.well__user {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  padding: .3rem .5rem;
}
.well__user:hover { background: var(--sunken); }

.well__user-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.well__user-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.15;
  text-align: left;
}
.well__user-name { font-weight: 600; font-size: .8125rem; }
.well__user-role { font-size: .6875rem; color: var(--ink-quiet); }

.well__user-menu {
  min-width: 240px;
  padding: 0;
  overflow: hidden;
  border-radius: 12px;
  box-shadow: 0 20px 40px rgba(15, 18, 32, .1);
  /* Bootstrap's own dropdown colors otherwise: a border a shade flatter
     than `--rule` and a hover tint too faint against `--surface` to read
     as a hover at all. Every other component in this panel is on this
     app's own tokens; this one was missed. */
  border: 1px solid var(--rule);
  background: var(--surface);
  color: var(--ink);
}
.well__user-menu-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .875rem 1rem;
  border-bottom: 1px solid var(--rule);
}
.well__user-menu-header small { font-size: .75rem; }
.well__user-menu .well__user-avatar { width: 40px; height: 40px; }

.well__user-menu .dropdown-item { padding: .55rem 1rem; font-size: .875rem; color: var(--ink); }
.well__user-menu .dropdown-item i { font-size: 1rem; width: 20px; }
.well__user-menu .dropdown-item:hover,
.well__user-menu .dropdown-item:focus { background: var(--sunken); color: var(--ink); text-decoration: none; }
.well__user-menu .dropdown-item.text-danger:hover,
.well__user-menu .dropdown-item.text-danger:focus { color: var(--bad); }

/* Same pattern, the density toggle: `aria-pressed="true"` means compact is
   on (G3.6, #309). */
.well__density-icon--compact { display: none; }
[aria-pressed="true"] .well__density-icon--comfortable { display: none; }
[aria-pressed="true"] .well__density-icon--compact { display: inline-block; }

/* Said in a word, never only in a colour. Still used on every state/flag the
   panel prints outside a `.stat-card`/`.status-chip` -- "Overridden" on a
   settings field is its last first-class user (G2.5, #291). */
.flag {
  padding: .05rem .4rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--sunken);
  color: var(--ink-quiet);
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.flag--owned { border-color: var(--good-edge); background: var(--good-soft); color: var(--good); }

/*
|------------------------------------------------------------------------------
| Form fields
|------------------------------------------------------------------------------
|
| Bootstrap's own dark mode gives `.form-control`/`.form-select` a palette of
| its own (`--bs-body-bg`, `--bs-border-color`), which this file never
| touches -- so every text field and select in the panel rendered Bootstrap's
| generic grey box rather than this app's surface and border, the one thing
| left that did not actually follow the page into dark mode. `.gate__field`
| had already worked out the fix for the login form; this is that fix made
| general, so nothing else has to work it out a second time.
|
*/

.form-control,
.form-select {
  border-radius: var(--radius);
  border-color: var(--rule);
  background-color: var(--surface);
  color: var(--ink);
}

.form-control::placeholder { color: var(--ink-faint); }

.form-control:focus,
.form-select:focus {
  border-color: var(--signal);
  background-color: var(--surface);
  color: var(--ink);
  box-shadow: 0 0 0 3px var(--signal-soft);
}

.input-group-text {
  border-color: var(--rule);
  background-color: var(--surface);
  color: var(--ink-quiet);
}

/*
|------------------------------------------------------------------------------
| The dashboard
|------------------------------------------------------------------------------
|
| Three bands down the page: states, counts, then the table the states
| summarise. The order is the order the questions get asked -- is it running,
| how much is there, and what exactly happened (A3.6, #231).
|
*/

/* The band label, in the type identifiers are read in, so a section reads as a
   heading without being one more size of bold text. */
/* A section heading in the site's own face, at the size a caption wears. */
.band {
  margin: 0 0 .5rem;
  color: var(--ink-quiet);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.band ~ .band { margin-top: 1.5rem; }

/* A band's own drill-down, Orchid's `.analytics-tile__link` (analytics.html)
   adopted for this app's own tokens -- used once so far, Overview's "Most
   searched" pointing at the full `searches()` page (G16, #369). */
.band-link {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .78rem;
  font-weight: 700;
  color: var(--signal);
  text-decoration: none;
  margin-bottom: .5rem;
}
.band-link:hover { color: var(--signal-accent); }

.stamp { color: var(--ink-quiet); font-size: .75rem; }

/*
|------------------------------------------------------------------------------
| Orchid stat cards
|------------------------------------------------------------------------------
|
| Orchid's own `.orchid-card`/`.orchid-stat-card` shape (G2.2, #288): an icon
| chip, a label, a value, a note. Reused as the booking detail page's own
| header row (G2.4, #290) rather than inventing a second "KPI" component --
| one card shape for every place this panel states a fact and a tone.
|
*/

.orchid-card {
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: 0 1px 2px #0f122010;
}

.stat-card__label { margin: 0 0 .25rem; font-size: .8125rem; color: var(--ink-quiet); }
.stat-card__value { margin: 0; font-size: 1.375rem; font-weight: 700; letter-spacing: -.01em; }
.stat-card__value--none { font-weight: 400; color: var(--ink-faint); }
.stat-card__note { margin: .375rem 0 0; font-size: .75rem; color: var(--ink-quiet); }

.stat-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.625rem;
  height: 2.625rem;
  border-radius: var(--radius);
  font-size: 1.15rem;
  flex-shrink: 0;
  background: var(--sunken);
  color: var(--ink-quiet);
}

/* A tile that actually leads somewhere (G20, #378) -- most do not, since
   most of the eight have no page to link to yet. `color: inherit` and
   no underline because the card's own children already set their colour;
   left as a plain `<div>` this rule never applies. */
.stat-card-link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color .18s ease;
}
.stat-card-link:hover { border-color: var(--signal); text-decoration: none; }

/* The tones. Colour is emphasis here and never the whole message -- every
   card prints its state in words too, so none of this is load-bearing.
   Bad is the one exception that also colours its own value text (G5.4,
   #357): a late schedule or an empty flight table is the one state this
   page needs to be unmissable about, where good/warn stay understated on
   purpose -- "everything is fine" does not need to shout. */
.stat-card--good .stat-card__icon { background: var(--good-soft); color: var(--good); }
.stat-card--warn .stat-card__icon { background: var(--signal-soft); color: var(--signal); }
.stat-card--bad .stat-card__icon { background: var(--bad-soft); color: var(--bad); }
.stat-card--bad .stat-card__value { color: var(--bad); }

/* The value text's own warning icon (G5.4, #357) -- the same pairing
   `.status-chip` already gives every other state indicator in the
   panel, so red is never the only thing saying "bad". */
.stat-card__warn-icon { font-size: 1.1rem; margin-right: .25rem; vertical-align: -.05em; }

.orchid-chart-wrap { position: relative; width: 100%; }
.orchid-chart-wrap--md { height: 12rem; }
/* A card-sized trend, not a page-wide one -- Route watches' own two hero
   cards (G21, #385) sit two to a row, so the full `--md` height read as
   the card competing with its own number for attention. */
.orchid-chart-wrap--sm { height: 6rem; }

/* "Most searched" -- Orchid's own Top Landing Pages (analytics.html,
   `.analytics-page-row`), renamed into this app's own vocabulary the way
   `.bookings-hero` renamed `.analytics-hero` (G7.1, #332). The rank, the
   two-line main cell, the bold count and the highlight bar sized to it
   are all real data (`DashboardRepository::topSearches()`) -- the trend
   pill Orchid's own row carries has nothing to read here, since `search`
   has no history to compare a count against, so that slot carries the
   one real action this list needs instead: removing a route that
   reached its count before rate limiting existed on `search_count`
   (G13, #362). No load animation on the bar, or the JS that would drive
   one -- every other chart on this page already disables animation. */
.searches-list { margin: 0; display: flex; flex-direction: column; gap: .375rem; }
.searches-row {
    position: relative;
    display: grid;
    grid-template-columns: 28px 1fr auto auto auto;
    align-items: center;
    gap: .875rem;
    padding: .625rem .75rem;
    border-radius: 12px;
    overflow: hidden;
}
.searches-row > * { position: relative; z-index: 1; }
.searches-row__bg {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 0;
    /* Rounded on its own right edge too, not just clipped by the row's
       `overflow: hidden` -- Orchid's own bg span carries the row's full
       `border-radius` even where that edge sits inside the row, so the
       highlight reads as a rounded bar rather than a slab with a flat
       cut where it happens to end. */
    border-radius: 12px;
    /* `--signal-soft` (built for a small icon-chip fill) read as barely
       there stretched across a whole row -- Orchid's own two-tone
       violet-to-cyan wash, at its own real opacity, is the visible
       version this was meant to be. */
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--signal) 18%, transparent) 0%,
        color-mix(in srgb, var(--signal-accent) 10%, transparent) 100%);
}
.searches-row__rank {
    font-size: .78rem;
    font-weight: 800;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}
.searches-row__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.searches-row__route {
    font-family: var(--mono);
    font-size: .78rem;
    color: var(--signal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.searches-row__cities {
    font-size: .82rem;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.searches-row__metric {
    font-size: .78rem;
    color: var(--ink-quiet);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
    /* Each row is its own grid (Orchid's own `.analytics-page-row` is too),
       so nothing shares a column across rows the way a table's would --
       without a floor, a row's own "auto" track only ever fits that row's
       own text, and the count/last-searched/button read as loose text
       rather than columns the moment two rows' lengths differ. */
    min-width: 44px;
}
.searches-row__metric--count { color: var(--ink); font-weight: 700; }
.searches-row__metric--last { min-width: 96px; }
@media (max-width: 575.98px) {
    .searches-row { grid-template-columns: 24px 1fr auto auto; }
    .searches-row__metric--last { display: none; }
}

/* The `searches()` page's own range switcher (G16, #369) -- same shape as
   `.bookings-range` (real `<a>` links, full reload, `is-active` +
   `aria-current`), but that one lives inside a hero band that is always
   dark regardless of the panel's own toggle, so its fixed white/rgba
   values would go low-contrast here. This sits on an ordinary
   theme-following surface, so it reads off this app's own tokens instead. */
.searches-range {
    display: inline-flex;
    flex-wrap: wrap;
    padding: 3px;
    background: var(--sunken);
    border: 1px solid var(--rule);
    border-radius: 999px;
    margin-bottom: 1rem;
}
.searches-range__btn {
    padding: .35rem .8rem;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--ink-quiet);
    font-weight: 700;
    font-size: .75rem;
    letter-spacing: .02em;
    text-decoration: none;
    transition: background .18s ease, color .18s ease;
}
.searches-range__btn:hover { color: var(--ink); }
.searches-range__btn.is-active { background: var(--surface); color: var(--signal); box-shadow: 0 2px 8px rgba(15, 18, 32, .08); }

/* A row of small facts, one `.stat-card__icon` chip each, side by side
   inside a single card rather than a table -- Orchid's own deals KPI strip
   (`.deals-kpi-strip`), adopted here without its sparklines: nothing on the
   booking page has a trend to show (G8.1, #336). */
.detail-strip {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: .75rem;
    padding: .85rem 1rem;
    /* Bootstrap's `.card` sets `word-wrap: break-word`, and this strip sits
       inside one -- without resetting it, a narrow column breaks something
       like an IP address mid-digit rather than wrapping at a space. */
    overflow-wrap: normal;
}

@media (max-width: 1199.98px) {
    .detail-strip { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .detail-strip__item:nth-child(3n + 1) { border-left: 0; padding-left: 0; }
}

@media (max-width: 575.98px) {
    .detail-strip { grid-template-columns: repeat(2, 1fr); }
    .detail-strip__item:nth-child(odd) { border-left: 0; padding-left: 0; }
}

.detail-strip__item {
    display: flex;
    align-items: center;
    gap: .65rem;
    min-width: 0;
}

/* Six of these side by side, not four in a row that spans the page --
   smaller than `.stat-card__icon` is everywhere else, so the value beside
   it keeps enough room to read. */
.detail-strip__item .stat-card__icon {
    width: 2.125rem;
    height: 2.125rem;
    font-size: 1rem;
}

.detail-strip__item + .detail-strip__item {
    border-left: 1px dashed var(--rule);
    padding-left: .95rem;
}

.detail-strip__meta { flex: 1; min-width: 0; }

.detail-strip__label {
    margin: 0;
    font-size: .7rem;
    color: var(--ink-quiet);
    text-transform: uppercase;
    letter-spacing: .05em;
}

.detail-strip__value {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.2;
}

/* A small icon tile wherever a card header wants one that is not a stat --
   same recipe as `.stat-card__icon`, kept separate because the two
   components should not have to evolve together (G2.3, #289). */
.icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  flex-shrink: 0;
  background: var(--sunken);
  color: var(--ink-quiet);
}

.icon-badge--sm { width: 2rem; height: 2rem; font-size: 1rem; }
.icon-badge--warn { background: var(--signal-soft); color: var(--signal); }

/* Orchid's own table dressing: a quiet, uppercase head and consistent row
   padding, layered onto Bootstrap's `.table` rather than replacing it. */
.orchid-table {
  --bs-table-bg: transparent;
  --bs-table-hover-bg: var(--sunken);
  --bs-table-color: var(--ink);
}

.orchid-table thead th {
  padding: .625rem .75rem;
  border-bottom: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-quiet);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.orchid-table tbody td, .orchid-table tbody th { padding: .875rem .75rem; border-bottom: 1px solid var(--rule); }
.orchid-table tbody tr:last-child td, .orchid-table tbody tr:last-child th { border-bottom: 0; }

/* A `<th scope="row">` -- a key/value table's own label column, read as a
   row header rather than a column one -- otherwise wears the browser's
   default bold, centered `th` regardless of the reset above, which does
   not touch `tbody`. It reads as a `<td>` because visually that is what
   every row-label cell beside it already looks like. */
.orchid-table tbody th { font-weight: 400; text-align: left; }

/* Compact reads as "the same table, tighter" rather than a different
   component, so this only ever touches the padding the row rule above
   already sets -- one global preference, not a per-table choice, the same
   `data-*` on `<html>` the theme already uses (G3.6, #309). */
[data-density="compact"] .orchid-table thead th { padding: .375rem .75rem; }
[data-density="compact"] .orchid-table tbody td, [data-density="compact"] .orchid-table tbody th { padding: .4rem .75rem; }

/* A row that sums the ones above it -- the booking payment breakdown's
   Total, so it reads as heavier than Base fare and Taxes & fees without a
   second table component (G2.4, #290). */
.orchid-table tr.is-total td, .orchid-table tr.is-total th { font-weight: 700; background: var(--signal-soft); }

/* Pinned to the right edge of `.table-responsive`'s own scroll area, so a
   wide table's last column survives scrolling out of view -- which is
   what an always-visible actions column did on the tickets table before
   this, with nothing on the page hinting there was more to the right
   (G8.3, #338). A solid background, not `.orchid-table`'s own transparent
   `--bs-table-bg`: a sticky cell with a transparent fill lets the columns
   scrolling underneath show through it, which is worse than the column
   it is meant to keep visible. */
.sticky-end { position: sticky; right: 0; background: var(--surface); }

/* A sticky cell with a set `right` always opens its own stacking context, so
   an open dropdown's `position: fixed` menu -- despite being positioned
   against the viewport -- still paints inside that context, behind every
   later row's own sticky cell. Raising the open row above its neighbours
   only while its menu is open fixes that without touching the rest. */
.sticky-end:has(.dropdown-menu.show) { z-index: 1051; }

/* A block's own title, inside the card rather than a `<p class="band">`
   above it -- Orchid's `.sales-card__head`/`.sales-card__title`
   (`payments.html`, `assets/css/pages/sales-lists.css`), renamed for reuse
   across every block on this page rather than one page's own transaction
   list (G8.5, #340). */
.block-head {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}
.block-head__title { margin: 0; font-size: .95rem; font-weight: 700; }

/* A tabbed switch between two views of the same block's own content --
   Orchid's `todo-filter-tabs` shape (`todo.html`), an underline rather than
   Bootstrap's boxed `.nav-tabs` look. Left as plain `.nav` markup rather
   than `.nav-tabs`: Bootstrap's tab JS only looks for `data-bs-toggle="tab"`
   and does not care which nav class carries it, and starting from a class
   with no default styling of its own is less to override than fighting
   `.nav-tabs`'s built-in borders and background (G8.5, #340). */
.block-tabs {
  display: flex;
  gap: .25rem;
  padding: 0 1rem;
  border-bottom: 1px solid var(--rule);
}
.block-tabs .nav-link {
  border: 0;
  background: transparent;
  padding: .625rem .75rem;
  color: var(--ink-quiet);
  font-size: .8125rem;
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.block-tabs .nav-link.active {
  color: var(--signal);
  border-bottom-color: var(--signal);
  font-weight: 600;
  background: transparent;
}
.block-tabs .nav-link:hover:not(.active) { color: var(--ink); }

/* Icon + label + tone, for anything that used to be a bare Bootstrap
   `.badge`: a booking's state in a list row, a flight leg's stop count. Tone
   is emphasis, same rule as `.stat-card` -- every chip still prints its
   state in words. */
.status-chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .2rem .6rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.4;
}

.status-chip i { font-size: .6875rem; }

.status-chip--good { background: var(--good-soft); color: var(--good); }
.status-chip--bad { background: var(--bad-soft); color: var(--bad); }
.status-chip--muted { background: var(--sunken); color: var(--ink-quiet); }
/* Something missing that should be filled in -- not broken, so not `--bad`.
   Bootstrap's own warning amber, the rail's count badges' colour. */
.status-chip--warn { background: var(--bs-warning-bg-subtle); color: var(--bs-warning); }

/* The job editor's argument picker -- `.status-chip`'s own pill shape,
   without a status tone since there is nothing here to signal, plus a
   remove button the read-only kind never needed. */
.argument-chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .2rem .3rem .2rem .6rem;
  border-radius: 999px;
  font-size: .8rem;
  background: var(--sunken);
  color: var(--ink);
}

.argument-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-quiet);
  font-size: .7rem;
  line-height: 1;
}

.argument-chip__remove:hover { background: var(--rule); color: var(--ink); }

/* An initial or two, for a passenger row with no photo to show. One tone
   for every circle rather than a hashed palette -- the colour would carry no
   information a hash didn't invent. */
.avatar-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--signal-soft);
  color: var(--signal);
  font-size: .6875rem;
  font-weight: 700;
  flex-shrink: 0;
}

/* The shared "Recent changes" feed (G28.1, #472): Orchid's own
   `projects.html` Activity Feed (`pages/projects.css`), values as-is, on
   this file's tokens (`--rule` is `--orchid-border`, `--surface` is
   `--orchid-surface`). The avatar holds the section's icon instead of a
   person's initials, in the one tone `.avatar-circle` already uses; the
   badge on it is the kind of change -- Orchid's comment violet for an
   edit (this palette's `--signal`), and red for a removal. */
.activity-feed {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .1rem;
}

.activity-feed__item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem 0;
  border-bottom: 1px dashed var(--rule);
}

.activity-feed__item:last-child { border-bottom: 0; }

.activity-feed__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--signal-soft);
  color: var(--signal);
  font-size: .9rem;
}

/* On the avatar's own corner, whatever the row's height -- a row with a
   second line or thumbnails is taller than the avatar. */
.activity-feed__icon {
  position: absolute;
  right: -5px;
  bottom: -5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 2px solid var(--surface);
  border-radius: 50%;
  color: #fff;
  font-size: .58rem;
}

/* The badge and the tag share a change's tone (`ChangeKind::tone()`). */
.activity-feed__icon--signal { background: var(--signal); }
.activity-feed__icon--good { background: var(--good); }
.activity-feed__icon--bad { background: var(--bad); }
.activity-feed__icon--muted { background: var(--ink-faint); }

.activity-feed__body { flex: 1; min-width: 0; }

.activity-feed__text {
  margin: 0;
  color: var(--ink);
  font-size: .82rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.activity-feed__link { color: var(--signal); font-weight: 500; text-decoration: none; }
.activity-feed__link:hover { text-decoration: underline; }

.activity-feed__sep { color: var(--ink-faint); }

/* A day heading, Orchid's `user-activity.html` `.act-day-header`: small
   capitals between the rows, not a row of its own. */
.activity-feed__day {
  padding: .875rem 0 .25rem;
  color: var(--ink-quiet);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.activity-feed__day:first-child { padding-top: 0; }

/* The second line: what exactly changed. */
.activity-feed__detail {
  margin: .15rem 0 0;
  color: var(--ink-quiet);
  font-size: .76rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.activity-feed__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .4rem;
}

.activity-feed__thumbs img {
  width: 48px;
  height: 36px;
  border-radius: 6px;
  object-fit: cover;
  background: var(--sunken);
}

.activity-feed__count {
  color: var(--ink-quiet);
  font-size: .76rem;
  font-weight: 600;
}

/* The right-hand column: when, then the kind of change -- side by side,
   so a row stays one line tall. Orchid puts a task's priority pill here;
   its values are reused as they are, with a fixed width so the tags line
   up as one column down the feed. */
.activity-feed__meta {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-shrink: 0;
  margin-left: auto;
}

.activity-feed__kind {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 4.75rem;
  padding: .15rem .45rem;
  border-radius: 6px;
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .04em;
}

.activity-feed__kind--signal { background: var(--signal-soft); color: var(--signal); }
.activity-feed__kind--good { background: var(--good-soft); color: var(--good); }
.activity-feed__kind--bad { background: var(--bad-soft); color: var(--bad); }
.activity-feed__kind--muted { background: var(--sunken); color: var(--ink-quiet); }

.activity-feed__meta .activity-feed__time {
  margin-top: 0;
  font-variant-numeric: tabular-nums;
}

/* A phone has no room for a right-hand column: the time and the tag drop
   under the text, lined up with it rather than with the avatar. */
@media (max-width: 575.98px) {
  .activity-feed__item {
    flex-wrap: wrap;
    align-items: flex-start;
    row-gap: .35rem;
  }

  .activity-feed__meta {
    width: 100%;
    margin-left: calc(32px + .75rem);
  }
}

/* Orchid's `.projects-activity__project` chip -- which section a row
   belongs to, on a feed that mixes them. */
/* Quiet on purpose: it says where a change happened, and the change is
   what a reader came for. */
.activity-feed__section {
  padding: .05rem .4rem;
  border-radius: 4px;
  background: var(--sunken);
  color: var(--ink-quiet);
  font-size: .72rem;
  font-weight: 500;
  white-space: nowrap;
}

.activity-feed__time {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  margin-top: .25rem;
  color: var(--ink-quiet);
  font-size: .7rem;
}

/* The booking log, as a flat grid row rather than a table: a fixed-width
   timestamp, a dot coloured by what happened, the message, the actor --
   Orchid's own compact-timeline column order, without the connecting spine a
   `.timeline` needs to earn its keep. */
.log-row {
  display: grid;
  grid-template-columns: 8.5rem 1rem 1fr auto;
  align-items: baseline;
  gap: .1rem .75rem;
  padding: .55rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: .8125rem;
}

.log-row:last-child { border-bottom: 0; }

.log-row__dot {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  align-self: center;
  background: var(--ink-faint);
}

.log-row__dot--signal { background: var(--signal); }
.log-row__dot--good { background: var(--good); }
.log-row__dot--bad { background: var(--bad); }

.log-row__actor { color: var(--ink-quiet); font-size: .75rem; white-space: nowrap; }

@media (max-width: 575.98px) {
  .log-row {
    grid-template-columns: 1rem 1fr;
    grid-template-areas: "dot time" "dot msg" "dot actor";
  }

  .log-row__dot { grid-area: dot; }
  .log-row__time { grid-area: time; }
  .log-row__msg { grid-area: msg; }
  .log-row__actor { grid-area: actor; }
}

/* What `.field__hint`/`.field__hint--bad` below hang off of now: Bootstrap's
   own `.form-control`/`.form-label`, not a `.field` wrapper -- every field on
   every admin form went onto those in G2.1-G2.5 (#287-#291). The hint text
   under a field stayed the panel's own, since Bootstrap's `.form-text` reads
   lighter than this data-dense panel wants. */
.field__hint { margin: .25rem 0 0; color: var(--ink-quiet); font-size: .75rem; }
.field__hint--bad { color: var(--bad); }

/* The Diagnostics page's own visible log (C6, #155) -- a toast reads
   once and is gone; this is for reading back what a check actually said,
   including the run before last. */
.diagnostic-console {
  max-height: 12rem;
  overflow-y: auto;
  padding: .75rem 1rem;
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: .8125rem;
}

.diagnostic-console__line {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.diagnostic-console__line + .diagnostic-console__line { margin-top: .5rem; }

.diagnostic-console__line--empty { color: var(--ink-quiet); font-style: italic; }
.diagnostic-console__line--ok { color: var(--good); }
.diagnostic-console__line--error { color: var(--bad); }

.notice {
  margin-bottom: 1rem;
  padding: .5rem .75rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--sunken);
  color: var(--ink-quiet);
  font-size: .8125rem;
}

.notice--bad { border-color: var(--bad-edge); background: var(--bad-soft); color: var(--bad); }
.notice--owned { border-color: var(--good-edge); background: var(--good-soft); color: var(--good); }

/*
|------------------------------------------------------------------------------
| The markdown editor
|------------------------------------------------------------------------------
*/

.editor { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: start; }

.editor__input {
  font-family: var(--mono);
  font-size: .8125rem;
  line-height: 1.55;
  min-height: 30rem;
  resize: vertical;
}

.editor__label {
  margin: 0 0 .25rem;
  color: var(--ink-quiet);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Scrolls with the textarea beside it rather than growing the page: the two
   are one control, and a preview that runs past its source is hard to
   compare. */
.editor__pane {
  max-height: 30rem;
  overflow-y: auto;
  padding: .75rem 1rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.editor__pane > :first-child { margin-top: 0; }
.editor__pane > :last-child { margin-bottom: 0; }
.editor__pane h2 { font-size: 1.125rem; }
.editor__pane h3 { font-size: 1rem; }
.editor__pane pre { overflow-x: auto; padding: .5rem; background: var(--sunken); border-radius: var(--radius); }
.editor__pane code { font-size: .8125rem; }

/* A scheduled job's own captured output (G26, #454) -- `cities:content` runs
   to dozens of lines, so this scrolls instead of stretching the page. */
.run-output { max-height: 24rem; overflow-y: auto; padding: .75rem; background: var(--sunken); border-radius: var(--radius); font-size: .8125rem; white-space: pre-wrap; word-break: break-word; }

/*
|------------------------------------------------------------------------------
| The way in
|------------------------------------------------------------------------------
|
| No rail: there is nothing to navigate until somebody is signed in, and a
| panel that showed its own shape to a stranger would be telling them what is
| worth attacking.
|
| Orchid's own `.auth-shell` is a hero half and a form half -- taken here as
| the split itself, not its copy. The hero's feature list sells "40+
| integrations" and "SOC 2 Type II"; this one says what is actually true of a
| server with one password and no accounts, because that is the only content
| honest to put in the same three lines (A10.1, #287).
|
*/

.shell--gate { min-height: 100vh; }

.gate { display: grid; grid-template-columns: 6fr 4fr; min-height: 100vh; }

@media (max-width: 991.98px) {
  .gate { grid-template-columns: 1fr; }
}

/* ---------- Hero half ---------- */
.gate__hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 2.5rem 3rem;
  color: #fff;
  background:
    radial-gradient(circle at 15% 20%, #d946ef59, transparent 45%),
    radial-gradient(circle at 85% 80%, #22d3ee52, transparent 45%),
    linear-gradient(135deg, #4338ca 0%, #6d28d9 40%, #0e7490 100%);
}

:root[data-theme="dark"] .gate__hero {
  background:
    radial-gradient(circle at 15% 20%, #d946ef47, transparent 45%),
    radial-gradient(circle at 85% 80%, #22d3ee47, transparent 45%),
    linear-gradient(135deg, #3730a3 0%, #581c87 40%, #155e75 100%);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate__hero {
    background:
      radial-gradient(circle at 15% 20%, #d946ef47, transparent 45%),
      radial-gradient(circle at 85% 80%, #22d3ee47, transparent 45%),
      linear-gradient(135deg, #3730a3 0%, #581c87 40%, #155e75 100%);
  }
}

@media (max-width: 991.98px) {
  .gate__hero { display: none; }
}

.gate__hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: .55;
  background-image: radial-gradient(circle, #ffffff2e 1px, transparent 1px);
  background-size: 26px 26px;
  mask-image: radial-gradient(ellipse at center, #000 45%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 45%, transparent 80%);
  animation: gate-drift 22s linear infinite;
}

@keyframes gate-drift {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50% { transform: translate3d(-24px, -18px, 0); }
}

.gate__hero-brand { display: inline-flex; align-items: center; gap: .625rem; font-weight: 700; letter-spacing: -.02em; font-size: 1.375rem; }

.gate__hero-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: .75rem;
  background: #ffffff29;
  color: #fff;
  font-size: 1.25rem;
  backdrop-filter: blur(8px);
  border: 1px solid #ffffff38;
}

.gate__hero-body { max-width: 32rem; margin: 2rem 0; }

.gate__hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .75rem;
  border-radius: 999px;
  background: #ffffff24;
  border: 1px solid #ffffff38;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
}

.gate__hero-title { font-size: clamp(1.9rem, 3vw, 2.75rem); font-weight: 800; line-height: 1.15; letter-spacing: -.02em; margin: 0 0 1rem; }
.gate__hero-lead { font-size: 1.05rem; line-height: 1.6; color: #ffffffd9; margin: 0 0 1.5rem; }

.gate__hero-facts { list-style: none; margin: 0; padding: 0; display: grid; gap: .75rem; }

.gate__hero-facts li {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  font-size: .95rem;
  color: #ffffffeb;
}

.gate__hero-facts .bi {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: .5rem;
  background: #ffffff2e;
  font-size: .875rem;
}

/* ---------- Form half ---------- */
.gate__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 2rem 1.5rem;
  background: var(--surface);
}

@media (min-width: 576px) { .gate__panel { padding: 2.5rem; } }
@media (min-width: 992px) { .gate__panel { padding: 2rem 3rem; } }

.gate__theme {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 1050;
  width: 2.625rem;
  height: 2.625rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 4px 12px #0000001f;
}

.gate__mark {
  display: none;
  align-items: center;
  gap: .625rem;
  margin-bottom: 1.5rem;
  font-weight: 700;
  letter-spacing: -.02em;
  font-size: 1.0625rem;
}

@media (max-width: 991.98px) { .gate__mark { display: inline-flex; } }

.gate__mark-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.125rem;
  height: 2.125rem;
  border-radius: .625rem;
  background: #0F766E;
  color: #fff;
  font-size: 1.0625rem;
  flex-shrink: 0;
}

.gate__mark-text { color: var(--ink); }

.gate__form { max-width: 27.5rem; width: 100%; margin: 0 auto; }

.gate__eyebrow {
  color: var(--signal);
  font-weight: 600;
  font-size: .8rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  margin-bottom: .5rem;
}

.gate__title { font-size: clamp(1.6rem, 2.2vw, 2rem); font-weight: 800; letter-spacing: -.02em; margin: 0 0 .5rem; color: var(--ink); }
.gate__subtitle { color: var(--ink-quiet); margin: 0 0 1.75rem; font-size: .95rem; }

.gate__field { margin-bottom: 1.1rem; }
.gate__field .form-label { font-size: .85rem; font-weight: 600; color: var(--ink); margin-bottom: .375rem; }

/* The border, background, colour and focus ring now come from the general
   `.form-control` rule; a bigger field earns a bigger ring, not a
   different one, which is the only thing still worth overriding here. */
.gate__field .form-control { padding: .7rem .95rem; font-size: .925rem; }
.gate__field .form-control:focus { box-shadow: 0 0 0 4px var(--signal-soft); }

/* The gradient CTA, Orchid's own -- a moving gradient on hover rather than a
   flat colour shift, which is what makes it read as this template's button
   and not a generic one wearing the brand colour. */
.gate__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  height: 3rem;
  border: 0;
  border-radius: var(--radius);
  color: #fff;
  font-weight: 600;
  font-size: .95rem;
  background: linear-gradient(120deg, #4f46e5 0%, #7c3aed 55%, #06b6d4 100%);
  background-size: 200% 100%;
  background-position: 0 50%;
  box-shadow: 0 12px 24px -12px #4f46e58c;
  transition: background-position 350ms ease;
  cursor: pointer;
}

.gate__submit:hover { background-position: 100% 50%; color: #fff; }

/* =====================================================
   Bookings' analytics hero (G7.1, #332)
   Orchid's own `.analytics-hero` shape (analytics.html): a signal-to-accent
   gradient by default (light), Orchid's own fixed navy radial-gradient
   restored for dark -- not derived from `--signal`, which reads too pale
   as a background fill once dark mode lightens it for legibility as a
   foreground colour elsewhere. Same two-path override every other themed
   token here uses: the OS preference when nothing is stored, the
   attribute when it is.
   ===================================================== */
.bookings-hero {
  position: relative;
  overflow: hidden;
  margin-bottom: 1.5rem;
  padding: 1.75rem clamp(1.25rem, 3vw, 2.5rem) 1.5rem;
  border-radius: 22px;
  color: #f8fafc;
  background: linear-gradient(135deg, var(--signal) 0%, var(--signal-accent) 100%);
  box-shadow: 0 24px 60px -20px rgba(10, 18, 48, .45);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bookings-hero {
    background: radial-gradient(140% 100% at 0% 0%, #182058 0%, #0a1230 55%, #050914 100%);
  }
}

:root[data-theme="dark"] .bookings-hero {
  background: radial-gradient(140% 100% at 0% 0%, #182058 0%, #0a1230 55%, #050914 100%);
}

.bookings-hero__decor { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }

.bookings-hero__grid {
  position: absolute;
  inset: -1px;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, .045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, .045) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(120% 80% at 50% 30%, #000 0%, transparent 75%);
}

.bookings-hero__orb { position: absolute; border-radius: 50%; filter: blur(60px); opacity: .55; }
.bookings-hero__orb--a {
  top: -120px;
  right: -60px;
  width: 380px;
  height: 380px;
  background: radial-gradient(circle, #7c3aed, transparent 70%);
}
.bookings-hero__orb--b {
  bottom: -160px;
  left: -80px;
  width: 320px;
  height: 320px;
  background: radial-gradient(circle, #22d3ee, transparent 70%);
  opacity: .35;
}

.bookings-hero__head {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.25rem;
  margin-bottom: 1.75rem;
}

.bookings-hero__title {
  margin: 0;
  font-size: clamp(1.7rem, 3.5vw, 2.4rem);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.05;
  background: linear-gradient(90deg, #fff 0%, #c4b5fd 60%, #7dd3fc 100%);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

.bookings-hero__sub { margin: .5rem 0 0; color: rgba(255, 255, 255, .65); font-size: .92rem; }

.bookings-hero__actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }

.bookings-range {
  display: inline-flex;
  padding: 3px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 999px;
}

.bookings-range__btn {
  padding: .35rem .8rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: rgba(255, 255, 255, .75);
  font-weight: 700;
  font-size: .75rem;
  letter-spacing: .04em;
  text-decoration: none;
  transition: background .18s ease, color .18s ease;
}
.bookings-range__btn:hover { color: #fff; }
.bookings-range__btn.is-active { background: #fff; color: #0a1230; box-shadow: 0 4px 14px rgba(0, 0, 0, .25); }

.bookings-btn-primary {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem .9rem;
  border-radius: 12px;
  color: #fff;
  text-decoration: none;
  font-size: .82rem;
  font-weight: 700;
  background: linear-gradient(135deg, #7c3aed, #22d3ee);
  box-shadow: 0 10px 24px rgba(124, 58, 237, .35);
  transition: transform .18s ease, box-shadow .18s ease;
}
.bookings-btn-primary:hover { color: #fff; transform: translateY(-1px); box-shadow: 0 14px 28px rgba(124, 58, 237, .45); }

.bookings-hero__kpis {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: .875rem;
  padding: .875rem;
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02));
  border: 1px solid rgba(255, 255, 255, .08);
  backdrop-filter: blur(6px);
}

.bookings-hero__kpi {
  display: flex;
  flex-direction: column;
  padding: .875rem 1rem 0;
  border-radius: 12px;
  background: rgba(255, 255, 255, .03);
  border: 1px solid rgba(255, 255, 255, .06);
  overflow: hidden;
  transition: background .18s ease, border-color .18s ease;
}
.bookings-hero__kpi:hover { background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .12); }

.bookings-hero__kpi-head { display: flex; flex-direction: column; gap: .35rem; margin-bottom: .75rem; }

.bookings-hero__kpi-label {
  color: rgba(255, 255, 255, .55);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.bookings-hero__kpi-value { color: #fff; font-size: clamp(1.4rem, 2.2vw, 1.85rem); font-weight: 800; letter-spacing: -.02em; line-height: 1; }

.bookings-hero__kpi-delta {
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  width: fit-content;
  padding: .15rem .5rem;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 700;
}
.bookings-hero__kpi-delta--up { background: rgba(132, 204, 22, .14); color: #a3e635; }
.bookings-hero__kpi-delta--down { background: rgba(244, 63, 94, .14); color: #fda4af; }
.bookings-hero__kpi-delta--flat { background: rgba(255, 255, 255, .08); color: rgba(255, 255, 255, .55); }

.bookings-hero__kpi-chart { position: relative; height: 64px; margin: 0 -1rem; }
.bookings-hero__kpi-chart canvas { display: block; width: 100% !important; height: 100% !important; }

@media (max-width: 991.98px) {
  .bookings-hero__kpis { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 575.98px) {
  .bookings-hero { padding: 1.5rem 1.25rem; }
  .bookings-hero__kpis { grid-template-columns: 1fr; }
}

/* Orchid's `.products-toolbar` (`inventory.html`), renamed into this page's
   own namespace: the bordered strip a filter bar sits in, with the search
   box carrying its own icon rather than an input-group. */
.bookings-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  padding: .875rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background-color: var(--surface);
}

/* Grows to fill the toolbar strip -- `.search-box` itself (below) does not
   assume a flex parent, since Route watches uses the same class inline
   next to a heading instead (G25.2, #441). The basis sends it to its own
   row on a phone rather than squeezing it down to its icon. */
.bookings-toolbar__search {
  flex: 1 1 14rem;
  min-width: 0;
}

.bookings-toolbar > .form-select-sm,
.bookings-toolbar > .form-control-sm {
  flex: 0 1 auto;
  min-width: 0;
  width: auto;
}

/* Orchid's `.sprod-catchip` (`shop-products.html`): toggle pills, filled
   when on. Each is the label of a visually hidden `.btn-check` checkbox,
   so it posts, tabs and toggles like one (G29, #477). */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .375rem;
}

.filter-chips__label {
  color: var(--ink-quiet);
  font-size: .8rem;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  padding: .4rem .85rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: .8rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: border-color .15s, color .15s, background-color .15s;
}

.filter-chip:hover {
  border-color: var(--signal);
  color: var(--signal);
}

.btn-check:checked + .filter-chip {
  border-color: var(--signal);
  background: var(--signal);
  color: #fff;
}

.btn-check:focus-visible + .filter-chip {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

/* An input with its search icon set into its own left edge -- shared by
   `search-box-macros.html.twig`'s `input()`, which renders the icon and the
   input this wraps but leaves sizing to whatever page puts it there
   (G25.2, #441). */
.search-box {
  position: relative;
}

.search-box i {
  position: absolute;
  top: 50%;
  left: .75rem;
  transform: translateY(-50%);
  color: var(--ink-quiet);
  pointer-events: none;
}

.search-box input.form-control {
  padding-left: 2.15rem;
  height: 38px;
}

/* Orchid's own `.sales-pager` (`orders.html`), renamed: the count's
   permanent home, flush under the table rather than a separate block
   below the card. */
.bookings-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .875rem 1.25rem;
  border-top: 1px solid var(--rule);
  color: var(--ink-quiet);
  font-size: .8125rem;
  flex-wrap: wrap;
}

.bookings-pager .page-link {
  border-radius: 8px !important;
  margin: 0 2px;
  font-size: .8125rem;
  color: var(--ink);
  border: 1px solid var(--rule);
}

/* Orchid's own `.inv-table` (`inventory.html`), the one thing `.orchid-table`
   -- this panel's shared table dressing -- doesn't already give it: a
   tinted head, rather than one that blends into the card. Scoped to this
   table rather than folded into `.orchid-table` itself, which every other
   admin list also uses. */
.bookings-table thead th { background: var(--sunken); }

.bookings-pager .page-item.active .page-link {
  background: var(--signal);
  border-color: var(--signal);
}

/* Orchid's own `orders.html` fulfillment pipeline (`.ord-pipeline`/
   `.ord-stages`/`.ord-stage`), structure and style, renamed into this
   page's own vocabulary and read off this app's tokens instead of
   Orchid's fixed indigo -- unlike `.settings-nav`'s own pills, this sits
   on an ordinary surface rather than carrying its own brand weight, the
   same reasoning `.searches-range` already gives for reading `--signal`
   (G25.11, #450). Sticky at the same offset `.settings-nav` already
   uses, so a hand does not have to be found for a second header height. */
.bookings-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 1.25rem;
  align-items: flex-start;
}

.bookings-pipeline {
  position: sticky;
  top: 90px;
  border: 1px solid var(--rule);
  border-radius: 16px;
  background: var(--surface);
  padding: 1rem;
}

.bookings-pipeline__title {
  margin: 0;
  font-weight: 600;
  font-size: .875rem;
}

.bookings-pipeline__sub {
  margin: .125rem 0 1rem;
  font-size: .78rem;
  color: var(--ink-quiet);
}

.bookings-stages {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

/* The connector line behind every dot -- drawn once on the list rather
   than between each pair of stages, the same economy `.ord-stages::before`
   spends one element on. */
.bookings-stages::before {
  content: "";
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: 12px;
  width: 2px;
  background: var(--rule);
}

.bookings-stage { position: relative; }
.bookings-stage + .bookings-stage { margin-top: .125rem; }

.bookings-stage__link {
  position: relative;
  display: block;
  padding: .6rem .6rem .6rem 2rem;
  border-radius: 10px;
  color: inherit;
  text-decoration: none;
  transition: background .15s ease;
}

.bookings-stage__link:hover { background: var(--sunken); text-decoration: none; }

.bookings-stage.is-active .bookings-stage__link { background: color-mix(in srgb, var(--signal) 8%, transparent); }

.bookings-stage__link::before {
  content: "";
  position: absolute;
  top: 1rem;
  left: 7px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--surface);
  border: 3px solid var(--ink-faint);
}

.bookings-stage.is-active .bookings-stage__link::before {
  border-color: var(--signal);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--signal) 14%, transparent);
}

.bookings-stage__row { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.bookings-stage__name { font-weight: 600; font-size: .85rem; }

.bookings-stage__count {
  min-width: 1.75rem;
  padding: .1rem .45rem;
  border-radius: 999px;
  background: var(--sunken);
  color: var(--ink-quiet);
  font-size: .75rem;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.bookings-stage.is-active .bookings-stage__count { background: var(--signal); color: #fff; }

.bookings-stage__meta {
  margin: .125rem 0 0;
  font-size: .75rem;
  color: var(--ink-quiet);
}

/* Below this, a data-heavy table beside a 280px sidebar has nowhere left
   to breathe -- `.settings-shell`'s own two forms don't need this at any
   width, but a table's own header row and this sidebar's own toolbar
   fighting for the same cramped column is a worse trade than stacking
   them. Sticky serves nothing once the sidebar is above the content
   instead of beside it. */
@media (max-width: 991.98px) {
  .bookings-layout { grid-template-columns: 1fr; }
  .bookings-pipeline { position: static; }
}

/* Orchid's own `account-settings.html` -- `.settings-shell`/`.settings-nav`/
   `.settings-panel`/`.settings-section`, structure and style, for the
   profile page (G9, #350). Token names renamed into this app's own
   vocabulary; the active-pill gradient and icon-chip tint are kept as
   Orchid's own indigo/violet, the same call `.bookings-btn-primary` already
   made for its own gradient rather than flattening it to `--signal`. */
.settings-shell {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 1.25rem;
  align-items: flex-start;
}

.settings-nav {
  position: sticky;
  top: 90px;
  border: 1px solid var(--rule);
  border-radius: 16px;
  background: var(--surface);
  padding: .5rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

.settings-nav .nav-link {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .7rem .85rem;
  border-radius: 12px;
  color: var(--ink);
  font-weight: 500;
  white-space: nowrap;
  transition: background .18s ease, color .18s ease;
}

.settings-nav .nav-link i {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: rgba(99, 102, 241, .12);
  color: #6366f1;
  display: grid;
  place-items: center;
  font-size: 1rem;
  flex-shrink: 0;
}

.settings-nav .nav-link:hover { background: var(--sunken); }

.settings-nav .nav-link.active {
  background: linear-gradient(120deg, #6366f1 0%, #8b5cf6 100%);
  color: #fff;
}

.settings-nav .nav-link.active i { background: rgba(255, 255, 255, .2); color: #fff; }

.settings-panel {
  border: 1px solid var(--rule);
  border-radius: 16px;
  background: var(--surface);
  padding: 1.5rem;
}

.settings-panel__head { margin-bottom: 1.25rem; }
.settings-panel__title { font-weight: 700; margin: 0 0 .25rem; }
.settings-panel__desc { color: var(--ink-quiet); margin: 0; font-size: .9rem; }

.settings-section + .settings-section {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}

.settings-section__title { font-weight: 600; margin: 0 0 .75rem; font-size: .95rem; }

.profile-photo__preview { width: 72px; height: 72px; }

@media (max-width: 991.98px) {
  .settings-shell { grid-template-columns: 1fr; }
  .settings-nav { position: static; flex-direction: row; overflow-x: auto; }
}

/* Orchid's own notification card (`ui-cards.html`, `#notif`), structure
   and style -- the Overview page's "What needs attention" list (G5.2,
   #317). */
.ui-notif-card {
  display: flex;
  align-items: center;
  gap: .875rem;
  padding: 1rem;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background: var(--surface);
}

.ui-notif-card__icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 1.1rem;
}

/* The aircraft type page's exterior/interior photo galleries (C27, #432): a
   small fixed-size thumbnail in its own table cell, rather than the
   grid of tiles this used to be -- a row now carries a filename next to
   the picture, which a caption-less tile had no room for. */
.admin-photo-thumb {
  width: 4rem;
  border-radius: .375rem;
}

/* The Aircraft types list's hero preview: a wide transparent render, so
   capped by height and left at its own width rather than cropped. */
.admin-hero-thumb {
  display: block;
  width: auto;
  max-width: 7rem;
  height: 2rem;
  object-fit: contain;
}

/* `cursor: grab`/`:active { cursor: grabbing }` and the dragging state's
   opacity are Orchid's own real HTML5 drag-and-drop kanban card values
   (`orchid-components/02-crm-sales.md`), reused here for the same
   reason they exist there: a row that looks graspable before anything
   is dragged, and visibly "picked up" once it is. Applies equally to a
   `<tr>` as it did to the card `<div>` this class used to be on --
   `cursor` is not a block-level-only property. Drag is the only way to
   reorder this gallery -- the up/down buttons an earlier pass added
   were removed once this covered the same job. */
.admin-photo-card {
  cursor: grab;
}
.admin-photo-card:active { cursor: grabbing; }
.admin-photo-card.is-dragging { opacity: .5; }

@media (max-width: 60em) {
  .editor { grid-template-columns: 1fr; }
  .well__body { padding: 1rem; }
}
