:root[data-theme="light"] {
  --bg: #f7f7f9;
  --surface: #ffffff;
  --text: #1a1a1a;
  --muted: #6b7280;
  --border: #e5e7eb;
  --primary: #1d4ed8;
  --primary-contrast: #ffffff;
  --danger: #dc2626;
  --danger-dark: #991b1b;
  --success: #16a34a;
  --warning: #f97316;
  --warning-contrast: #ffffff;
}

/* Placeholder palette — swap these hex values for your exact brand colours
   once you share them, this is where the site's "dark" scheme lives. */
:root[data-theme="dark"] {
  --bg: #0f1420;
  --surface: #171d2b;
  --text: #e8eaf0;
  --muted: #9aa3b2;
  --border: #2a3244;
  --primary: #4f7cff;
  --primary-contrast: #ffffff;
  --danger: #f87171;
  --danger-dark: #b91c1c;
  --success: #4ade80;
  --warning: #fb923c;
  --warning-contrast: #1a1206;
}

* { box-sizing: border-box; }

html {
  height: 100%;
}

/* Sticky footer: body is a full-height column (header / main / footer) so
   that on pages with little content the footer sits at the bottom of the
   viewport instead of floating up under a short block of content. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  transition: background-color .15s ease, color .15s ease;
  overflow-x: hidden;
}

/* Site-wide link style: no underline, a subtle dim-on-hover instead. Opacity
   (rather than swapping to a fixed color) keeps this legible no matter what
   background a link sits on — hero banners, badges, nav bars, etc. Anything
   more specific (nav links, buttons styled as links) sets its own color and
   simply inherits this hover behaviour. */
a {
  color: var(--primary);
  text-decoration: none;
  transition: opacity .15s ease, color .15s ease;
}

a:hover {
  opacity: .72;
}

.site-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  padding: 1rem 2rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 500;
  gap: .5rem 1rem;
}

/* Window Controls Overlay title bar — only ever visible when app.js detects
   the app is installed and running in a Chromium browser that supports WCO
   (html.wco-active), so it's a safe no-op in every other context (regular
   browser tab, Firefox/Safari, mobile, not-yet-installed). Uses --bg rather
   than --surface so it visually reads as "the OS chrome above the app" —
   and because it's a plain theme variable, it re-colours instantly when the
   light/dark toggle runs, unlike the browser's own static manifest colour.
   The env() values come from the Window Controls Overlay API and describe
   the safe rectangle to draw in without overlapping the native minimize/
   maximize/close buttons; the px fallbacks only matter before app.js has
   run, and are harmless since the element is display:none until then. */
#wco-titlebar {
  display: none;
  position: fixed;
  top: 0;
  left: env(titlebar-area-x, 0);
  width: env(titlebar-area-width, 100%);
  height: env(titlebar-area-height, 33px);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  align-items: center;
  gap: .5rem;
  padding: 0 .75rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text);
  z-index: 1000;
  -webkit-app-region: drag;
  app-region: drag;
}

html.wco-active #wco-titlebar {
  display: flex;
}

/* Push the real page content down below the overlay bar so nothing hides
   underneath it. */
html.wco-active .site-header {
  margin-top: env(titlebar-area-height, 33px);
  /* Sticky's `top` offset is measured from the viewport, independent of the
     margin above — without this the stuck header would settle at the very
     top of the screen, right under the fixed WCO title bar instead of
     below it. */
  top: env(titlebar-area-height, 33px);
}

.site-header .logo { font-weight: 700; font-size: 1.25rem; flex: 0 0 auto; }

/* The PProma mark is fill="currentColor", so its colour is set purely here —
   brand blue on a light surface, switching to white on dark so it still
   reads clearly against the dark header/titlebar instead of nearly
   disappearing at low contrast. */
.brand-logo { color: #1D45A3; }
:root[data-theme="dark"] .brand-logo { color: #ffffff; }

/* Two logo variants sit in the header markup at once (see brand_logo() /
   brand_icon_mark() in helpers.php) — the full wordmark by default, and the
   icon-only mark swapped in on narrow screens where there isn't room for
   the full "pproma" text, rather than shrinking the wordmark down to
   illegible. */
.brand-logo-icon { display: none; }

.site-header nav { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.site-header nav a { color: var(--text); text-decoration: none; }
.site-header nav a:hover { color: var(--primary); }

/* Sits directly to the right of the logo, on the left side of the header —
   deliberately NOT centered/absolutely positioned, so it can never collide
   with the notification/theme/account icons on the right on narrow screens.
   Gap matches .site-header-right below so both icon groups read as the
   same visual rhythm instead of the left one looking noticeably tighter. */
.site-header-center {
  gap: .6rem !important;
}

/* Pushed to the far right; the logo + center icons naturally stay grouped
   together on the left because this is the only header child with auto
   margin pulling space toward itself. Gap explicitly matches
   .site-header-center rather than inheriting the generic `.site-header nav`
   1rem, which read as noticeably looser than the left icon group. */
.site-header-right {
  margin-left: auto;
  gap: .6rem;
}

.site-header .header-icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--primary);
  text-decoration: none;
  padding: .4rem;
  border-radius: 3px;
  line-height: 1;
}

.site-header .header-icon-link:hover {
  background: var(--bg);
}

/* Shared shape for every icon-only control on the right of the header
   (notifications, cart, theme toggle, language) — same height, padding and
   icon size so they all sit on one straight vertical line regardless of
   whether the markup is a <button> or an <a>, and regardless of an extra
   badge span inside (which can still grow the control's width without
   affecting its height/alignment). Colour matches the dashboard's icon
   tiles (.tile-btn .icon-svg) — var(--primary) — on light theme, rather
   than the neutral text colour, so the header and dashboard read as the
   same visual system there. Scoped as `.site-header .header-icon-btn`
   (not just `.header-icon-btn`) so it outweighs `.site-header nav a`'s
   color rule below for the <a>-tag instances of this class (cart-link) —
   otherwise that rule's higher specificity would silently win and leave
   just this one icon grey. */
.site-header .header-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  padding: 0 .3rem;
  margin: 0;
  background: none;
  border: none;
  color: var(--primary);
  cursor: pointer;
  text-decoration: none;
  border-radius: 3px;
  box-sizing: border-box;
  line-height: 1;
}

.site-header .header-icon-btn:hover {
  background: var(--bg);
}

/* On dark theme, revert these same header icons (and the icons inside the
   header's dropdown menus — account menu, language menu, mobile nav panel)
   back to the original neutral scheme instead of dashboard-blue: the
   brighter primary blue reads well against a white light-theme header, but
   sits harshly against the dark header's low-contrast surface, so dark
   theme keeps the plain/subtle look it always had (colour only shifts to
   primary on hover, same as before this change). */
:root[data-theme="dark"] .site-header .header-icon-link,
:root[data-theme="dark"] .site-header .header-icon-btn,
:root[data-theme="dark"] .user-menu-link .icon-svg {
  color: var(--text);
}

:root[data-theme="dark"] .site-header .header-icon-link:hover,
:root[data-theme="dark"] .site-header .header-icon-btn:hover,
:root[data-theme="dark"] .user-menu-link:hover .icon-svg {
  color: var(--primary);
}

/* Light theme: header dropdown menu icons (account menu, language menu,
   mobile nav panel — all rendered with the shared .user-menu-link row)
   match the dashboard-blue scheme too, same reasoning as the header icons
   above; the row's own text stays var(--text) via .user-menu-link itself,
   only the icon recolours. */
:root[data-theme="light"] .user-menu-link .icon-svg {
  color: var(--primary);
}

/* Below this width the two centre nav icons collapse behind a hamburger
   button (folded into a dropdown panel) instead of wrapping onto their own
   line, which was crowding the header next to the notification/theme/
   language/account icons on the right. */
@media (max-width: 768px) {
  #mobile-menu-btn { display: inline-flex !important; align-items: center; }
  .site-header-center { display: none !important; }
}

@media (max-width: 560px) {
  .site-header { padding: .75rem 1rem; gap: .4rem .6rem; }
  .site-header nav { gap: .6rem; }
  .site-main { padding: 1.25rem; }
  .hero { padding: 2rem 1.25rem; }
  .hero h1 { font-size: 1.5rem; }
  .hero h2 { font-size: 1rem; }
  .brand-logo-full { display: none; }
  .brand-logo-icon { display: inline-block; }
}

/* flex:1 makes this stretch to fill any leftover vertical space in the
   body's flex column, so the footer never gets pulled up next to short
   content; min-height keeps that true even before flex has a chance to
   grow it (e.g. print/no-JS edge cases) by guaranteeing a tall baseline. */
.site-main { padding: 2rem; max-width: 960px; width: 100%; margin: 0 auto; flex: 1 0 auto; min-height: 80vh; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1.75rem;
}

/* Separates sections within a single "one card, multiple headings" page
   (Post a Project, project detail) so it reads as one document rather than
   several disconnected boxes, while still visually distinguishing sections. */
.card hr,
.section-divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 1.75rem 0;
}

.card h2 { margin-top: 0; }

/* Icon-on-top, label-below tile button used on the dashboard and admin
   overview screens (stat tiles, "My ..." shortcuts, quick actions) — keeps
   every tile the same shape regardless of what's inside, so the grid
   columns line up cleanly across sections. */
.tile-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  text-align: center;
  text-decoration: none;
  color: inherit;
}
.tile-btn .icon-svg { color: var(--primary); }
.tile-btn span { font-size: .85rem; color: var(--text); }

/* Selected-service badges on project cards (Printing / Binding / etc.) —
   a light tint of the theme's primary colour rather than a flat grey pill,
   so it reads as "part of this app" rather than a generic tag. */
.req-badge {
  font-size: .75rem;
  background: color-mix(in srgb, var(--primary) 12%, var(--surface));
  color: var(--primary);
  border: 1px solid color-mix(in srgb, var(--primary) 30%, var(--border));
  border-radius: 3px;
  padding: .15rem .6rem;
  display: inline-block;
}


/* Horizontal stage tracker — shows every trade the project needs as a step,
   with completed/current/upcoming states. */
.stage-tracker {
  display: flex;
  align-items: flex-start;
  gap: 0;
  margin: 1rem 0;
  overflow-x: auto;
  padding-bottom: .25rem;
}

.stage-tracker-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 0;
  min-width: 90px;
  position: relative;
  text-align: center;
  /* Reset browser button chrome for the clickable <button> variant — the
     plain (non-clickable) steps are <div>s and unaffected by this. */
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  margin: 0;
  color: inherit;
}

.stage-tracker-step.is-clickable {
  cursor: pointer;
}

.stage-tracker-step.is-clickable:hover .stage-tracker-dot {
  border-color: var(--primary);
  transform: scale(1.08);
}

.stage-tracker-step.is-clickable:hover .stage-tracker-label {
  color: var(--primary);
}

.stage-tracker-step:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 13px;
  left: 50%;
  width: 100%;
  height: 2px;
  background: var(--border);
  z-index: 0;
}

.stage-tracker-step.is-done:not(:last-child)::after {
  background: var(--success);
}

.stage-tracker-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--success);
  z-index: 1;
  flex: 0 0 auto;
  transition: border-color .15s ease, transform .15s ease;
}

.stage-tracker-step.is-current .stage-tracker-dot {
  border-color: var(--primary);
  background: var(--primary);
}

.stage-tracker-step.is-done .stage-tracker-dot {
  border-color: var(--success);
  background: var(--surface);
}

.stage-tracker-label {
  font-size: .78rem;
  color: var(--muted);
  margin-top: .4rem;
  max-width: 100px;
}

.stage-tracker-step.is-current .stage-tracker-label {
  color: var(--primary);
  font-weight: 600;
}

.stage-tracker-step.is-done .stage-tracker-label {
  color: var(--text);
}

.stage-tracker-step.is-custom .stage-tracker-dot {
  border-style: dashed;
  border-color: var(--danger);
  color: var(--danger);
}

.stage-tracker-step.is-custom.is-current .stage-tracker-dot {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--surface);
}

.stage-tracker-step.is-custom .stage-tracker-label {
  color: var(--danger);
  font-style: italic;
}

label { display: block; font-size: .85rem; color: var(--muted); margin-bottom: .3rem; }

input, select, textarea {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: .6rem .75rem;
  width: 100%;
  margin-bottom: 1rem;
  font-size: 1rem;
}

/* The rule above is sized for text/select/textarea fields — applied
   unchanged to a checkbox it renders as a giant full-width padded
   rectangle instead of a normal ~1em box. Fixed once globally here rather
   than requiring every checkbox on every page to carry its own inline
   width:auto override (a few already do, from before this rule existed). */
input[type="checkbox"], input[type="radio"] {
  width: auto;
  padding: 0;
  margin: 0;
  vertical-align: middle;
}

button, .btn {
  display: inline-block;
  background: var(--primary);
  color: var(--primary-contrast);
  /* Transparent border of the same width as input/select/textarea's real
     border (see rule above) — without this, a button sitting next to a
     form field is ~2px shorter despite identical padding, since box-sizing:
     border-box counts the input's border inside its height and the
     button had none to match it. */
  border: 1px solid transparent;
  border-radius: 3px;
  padding: .6rem 1.1rem;
  cursor: pointer;
  font-size: 1rem;
  text-decoration: none;
  line-height: 1.5;
}

button:hover, .btn:hover { filter: brightness(1.08); }

/* Project status pills (Open/In progress/Completed/Cancelled — see
   project_status_color() in helpers.php). Overrides the base .btn text
   color (var(--primary-contrast), usually white) with black — the
   background colors here (success green, warning orange, danger red) are
   all light/mid-toned enough that black reads clearly on every one of
   them, unlike the default white which was made for --primary's blue. */
.status-badge {
  color: #000;
}

/* Blends with the page instead of standing out — background matches the
   active theme (light/dark) rather than a fixed grey, with a border
   so it still reads as a button. Used for secondary actions like Print and
   Start Chat. */
button.btn-bg, .btn.btn-bg {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
}

/* Orange "caution" action — used for Hold, i.e. pausing a project. */
button.btn-warning, .btn.btn-warning {
  background: var(--warning);
  color: var(--warning-contrast);
}

/* Compact action buttons — used for the project page's top button row
   (Chat / Print / status / Edit / Start / Hold / Cancel) so a run of
   several buttons stays small and every one of them matches in size,
   regardless of which color/style class it's paired with. */
button.btn-sm, .btn.btn-sm {
  padding: .35rem .7rem;
  font-size: .82rem;
  border-radius: 3px;
}

/* Search/filter bar (see projects/index.php). A grid rather than flex:N
   ad hoc values on each field — grid-template-columns fills the row's
   full width predictably at any viewport, and the actions column gets an
   explicit track instead of being the one leftover item with no flex
   value (which previously meant it didn't grow/shrink with the rest of
   the row and could end up misaligned or oddly sized next to it).
   Two states only: one inline row on desktop, fully stacked on mobile —
   no intermediate tablet layout. */
.filter-bar {
  display: grid;
  width: 100%;
  box-sizing: border-box;
  grid-template-columns: 2fr 1fr 1fr 1fr auto;
  gap: .75rem;
  align-items: end;
  margin-bottom: 1.25rem;
  background: var(--bg);
  border-radius: 5px;
  /* Single source of truth for every control's height in this row —
     inputs, the select, and the buttons all reference the same value
     instead of each arriving at "about the same height" via their own
     padding/border math, which in practice still drifted by a few px
     and left mismatched corner radii (buttons default to 3px sitewide,
     inputs to 6px). */
  --control-height: 2.75rem;
  --control-radius: 6px;
}

.filter-bar .filter-field { min-width: 0; }

.filter-bar .filter-field input,
.filter-bar .filter-field select {
  height: var(--control-height);
  padding: 0 .75rem;
  margin-bottom: 0;
  border-radius: var(--control-radius);
  box-sizing: border-box;
  width: 100%;
}

/* Actions column has no <label>, so it has no label-height pushing it
   down the way every other column does — this placeholder keeps its
   button(s) sitting on the exact same baseline as the inputs beside it
   rather than being vertically centered against the taller label+input
   columns. */
.filter-bar .filter-actions-spacer {
  display: block;
  height: 1.2rem; /* matches label font-size(.85rem) + line-height + margin-bottom(.3rem) */
}

.filter-bar .filter-actions {
  display: flex;
  gap: .5rem;
}

.filter-bar .filter-actions button,
.filter-bar .filter-actions .btn {
  height: var(--control-height);
  padding: 0 1.1rem;
  border-radius: var(--control-radius);
  box-sizing: border-box;
  /* Strips the browser's native button chrome (which carries its own
     intrinsic sizing on top of our padding in some browsers) so height
     above is the only thing determining how tall the button renders. */
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid transparent;
  line-height: 1;
  display: inline-flex;
  align-items: center;
}

@media (max-width: 700px) {
  .filter-bar { grid-template-columns: 1fr; }
  .filter-bar .filter-actions-spacer { display: none; }
}

/* Post-project form (projects/create.php): every dropdown field sits in
   its own .field cell so grid-auto-flow naturally pairs two per row;
   anything that isn't a bare dropdown (text inputs, textareas, headings,
   the repeatable paper-items block, etc.) is wrapped in .field-full to
   span both columns and keep its existing full-width appearance. Each
   .toggle-section is a .field-grid in its own right (nested inside the
   outer one) so its dropdowns pair up independently of the rest of the
   form. */
.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 1rem;
  align-items: start;
}

.field-grid > .field-full { grid-column: 1 / -1; }

.field-grid > .field select,
.field-grid > .field input,
.field-grid > .field-full select,
.field-grid > .field-full input { width: 100%; }

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

/* Repeatable "Add Paper" blocks (projects/create.php) — a thin top border
   between entries instead of each one being its own bordered/background
   box, so multiple papers read as one continuous list rather than a stack
   of separate cards. */
#paper-items-container .paper-item-block {
  padding: 1rem 0;
  border-top: 1px solid var(--border);
}

#paper-items-container .paper-item-block:first-child {
  padding-top: 0;
  border-top: none;
}

.section-toggle-row {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: 1rem;
}

.section-toggle-btn {
  background: var(--surface);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: .4rem 1rem;
  font-size: .9rem;
  cursor: pointer;
}

.section-toggle-btn.active {
  background: var(--primary);
  color: var(--primary-contrast);
  border-color: var(--primary);
}

.user-menu-link {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem 1rem;
  color: var(--text);
  text-decoration: none;
  font-size: .9rem;
}

.user-menu-link:hover {
  background: var(--bg);
}

.site-footer {
  text-align: center;
  padding: 1.5rem 1rem;
  margin-top: 2rem;
  color: var(--muted);
  font-size: .85rem;
  border-top: 1px solid var(--border);
}

.site-footer a { color: var(--muted); }

.hero {
  background: linear-gradient(135deg, var(--primary), var(--success));
  color: #fff;
  padding: 3rem 2rem;
  text-align: center;
  margin-bottom: 2rem;
  width: 100vw;
  position: relative;
  left: 50%;
  margin-left: -50vw;
}

.hero-inner {
  max-width: 700px;
  margin: 0 auto;
}

.hero h1 {
  margin: 0 0 .5rem;
  font-size: 2.25rem;
}

.hero h2 {
  margin: 0 0 1.25rem;
  font-weight: 400;
  font-size: 1.15rem;
  opacity: .95;
}

.hero p {
  max-width: 560px;
  margin: 0 auto 1.5rem;
  line-height: 1.6;
  opacity: .95;
}

.hero .btn {
  background: #fff;
  color: var(--primary);
  font-weight: 600;
}

.hero .btn.btn-outline {
  background: transparent;
  color: #fff;
  border: 1px solid rgba(255,255,255,.7);
}

.benefits-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin: 1.5rem 0 2rem;
  padding: 0;
}

.benefits-grid li {
  list-style: none;
}

.error { color: var(--danger); font-size: .85rem; margin: -.75rem 0 1rem; }

/* ===================== Chat / messages: threaded rows ===================== */

.chat-thread-box {
  margin-bottom: 1.1rem;
}

.chat-msg-row {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
}

.chat-avatar-wrap { flex: 0 0 auto; }

.chat-avatar,
.chat-avatar-fallback {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: block;
}

.chat-avatar { object-fit: cover; }

.chat-avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--primary);
  color: var(--primary-contrast);
  font-weight: 700;
  font-size: .9rem;
}

.chat-msg-bubble {
  flex: 1 1 auto;
  min-width: 0;
}

.chat-msg-meta strong { color: var(--text); }

.chat-mention {
  color: var(--primary);
  font-weight: 600;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border-radius: 4px;
  padding: 0 .2rem;
}

.reply-btn {
  background: none;
  border: none;
  color: var(--primary) !important;
  text-decoration: none;
  padding: 0;
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
  margin-top: .3rem;
  opacity: .9;
}
.reply-btn:hover { opacity: 1; }

/* Replies nest directly under their parent row, indented under the parent's
   avatar with a connecting line — matching the LinkedIn-style comment thread. */
.chat-replies {
  display: flex;
  flex-direction: column;
  gap: .65rem;
  margin: .65rem 0 0 18px;
  padding-left: 18px;
  border-left: 2px solid var(--border);
}

.chat-replies .chat-avatar,
.chat-replies .chat-avatar-fallback {
  width: 28px;
  height: 28px;
  font-size: .75rem;
}

.chat-thread-box .collapse-replies-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-size: .8rem;
  cursor: pointer;
  padding: 0;
  margin: .5rem 0 0 18px;
}
.chat-thread-box .collapse-replies-btn:hover { color: var(--text); }

/* ===================== Chat composer: emoji + attach-file icon ===================== */

.chat-composer-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  position: relative;
}

.chat-composer-actions {
  display: flex;
  align-items: center;
  gap: .35rem;
  position: relative;
}

.chat-icon-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
  width: 38px;
  height: 38px;
  border-radius: 3px;
  font-size: 1.05rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  padding: 0;
}
.chat-icon-btn:hover { background: var(--bg); }

.chat-file-input { display: none; }

.chat-file-chip {
  display: none;
  align-items: center;
  gap: .35rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: .25rem .7rem;
  font-size: .8rem;
  color: var(--text);
}

.chat-file-chip.is-visible { display: inline-flex; }

.chat-file-chip-remove {
  background: none;
  border: none;
  color: var(--danger);
  cursor: pointer;
  font-size: .85rem;
  padding: 0;
  line-height: 1;
}

.emoji-panel {
  display: none;
  position: absolute;
  bottom: 46px;
  left: 0;
  width: 236px;
  max-height: 190px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  box-shadow: 0 6px 20px rgba(0,0,0,.18);
  padding: .5rem;
  grid-template-columns: repeat(7, 1fr);
  gap: .15rem;
  z-index: 40;
}

.emoji-panel.is-open { display: grid; }

.emoji-panel-item {
  background: none;
  border: none;
  font-size: 1.15rem;
  cursor: pointer;
  border-radius: 3px;
  padding: .25rem 0;
  line-height: 1;
}
.emoji-panel-item:hover { background: var(--bg); }

/* ===================== @mention dropdown ===================== */

.mention-dropdown {
  display: none;
  position: absolute;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  box-shadow: 0 4px 16px rgba(0,0,0,.15);
  z-index: 45;
  max-height: 180px;
  overflow-y: auto;
}

.mention-dropdown-item {
  padding: .45rem .7rem;
  font-size: .88rem;
  cursor: pointer;
}
.mention-dropdown-item:hover,
.mention-dropdown-item.active { background: var(--bg); }

/* ===================== "Include a member" bar, above the chat composer ===================== */

.chat-members-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .6rem .9rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: .55rem .75rem;
  margin-bottom: .75rem;
}

.chat-members-bar-people {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
}

.chat-members-bar-form {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 0;
  flex-wrap: wrap;
}

.chat-members-bar-form select {
  width: auto;
  min-width: 170px;
  margin: 0;
}

.chat-members-bar-form button {
  margin: 0;
}

/* ===================== Brand / social icons (theme-recolorable) ===================== */
/* These render via CSS mask so the SVG picks up var(--muted) / var(--primary)
   like any other themed element, instead of being stuck at a fixed color. */

.brand-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background-color: var(--muted);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: 55%;
  mask-size: 55%;
  transition: background-color .15s ease, transform .15s ease;
  text-decoration: none;
  flex: 0 0 auto;
}

.brand-icon:hover {
  background-color: var(--primary);
  transform: translateY(-1px);
}

.brand-icon.brand-icon-linkedin  { -webkit-mask-image: url('/assets/icons/brands/linkedin-in.svg'); mask-image: url('/assets/icons/brands/linkedin-in.svg'); }
.brand-icon.brand-icon-behance   { -webkit-mask-image: url('/assets/icons/brands/behance.svg');      mask-image: url('/assets/icons/brands/behance.svg'); }
.brand-icon.brand-icon-dribbble  { -webkit-mask-image: url('/assets/icons/brands/dribbble.svg');      mask-image: url('/assets/icons/brands/dribbble.svg'); }
.brand-icon.brand-icon-instagram { -webkit-mask-image: url('/assets/icons/brands/instagram.svg');     mask-image: url('/assets/icons/brands/instagram.svg'); }
.brand-icon.brand-icon-facebook  { -webkit-mask-image: url('/assets/icons/brands/facebook.svg');      mask-image: url('/assets/icons/brands/facebook.svg'); }
.brand-icon.brand-icon-x         { -webkit-mask-image: url('/assets/icons/brands/x-twitter.svg');     mask-image: url('/assets/icons/brands/x-twitter.svg'); }
.brand-icon.brand-icon-youtube   { -webkit-mask-image: url('/assets/icons/brands/youtube.svg');       mask-image: url('/assets/icons/brands/youtube.svg'); }
.brand-icon.brand-icon-whatsapp  { -webkit-mask-image: url('/assets/icons/brands/whatsapp.svg');      mask-image: url('/assets/icons/brands/whatsapp.svg'); }

.brand-icon-row {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}

.brand-icon-sm {
  width: 26px;
  height: 26px;
}

.site-footer .brand-icon-row {
  justify-content: center;
  margin-top: .75rem;
}

/* ===================== Duotone UI icons (inlined SVGs) ===================== */
/* fill is set to currentColor at insertion time (see icon() in helpers.php),
   so these automatically match whatever color their container already uses —
   no per-icon color rules needed. This one rule gives every inlined icon its
   two-tone look. */

.icon-svg {
  display: inline-block;
  vertical-align: -0.15em;
  flex: 0 0 auto;
}

.icon-svg .fa-secondary { opacity: .45; }

/* ===================== Print styles ===================== */
/* Used by the "Print" button on a project page: hides site chrome and any
   management/action UI (buttons, forms, chat, proposals, tracker) so what
   comes out of the printer is just the project's requirements — handy to
   hand to a printer/binder/packager on the shop floor. */
@media print {
  .no-print { display: none !important; }

  body { background: #fff; color: #000; }

  .site-main {
    max-width: none;
    padding: 0;
    margin: 0;
  }

  .card {
    border: none;
    box-shadow: none;
    padding: 0;
    margin: 0 0 1rem;
  }

  a { color: #000; text-decoration: none; }

  table { page-break-inside: avoid; }
}

/* ===================== File picker (modern attach-files widget) ===================== */
/* Replaces the raw browser <input type=file> control: a styled trigger
   button plus a preview list of the currently-selected files (shown above
   the button), each removable before submitting. */

.file-picker-list {
  list-style: none;
  margin: 0 0 .6rem;
  padding: 0;
}

.file-picker-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .4rem .6rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-bottom: .35rem;
  font-size: .85rem;
}

.file-picker-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-picker-remove {
  background: none;
  border: none;
  color: var(--danger);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 .3rem;
  flex: 0 0 auto;
}

.file-picker-remove:hover { filter: brightness(1.3); }

/* -------------------------------------------------------------------------
   Pricing page (/pricing)
   ---------------------------------------------------------------------- */

/* Free-tier "what you get for nothing" stats — plain icon + number, not a
   numbered list, since these two facts aren't a sequence. */
.pricing-stat-row {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.pricing-stat {
  flex: 1 1 220px;
  display: flex;
  gap: .75rem;
  align-items: flex-start;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1rem 1.1rem;
}

.pricing-stat-icon { color: var(--primary); flex: 0 0 auto; margin-top: .1rem; }
.pricing-stat .num { font-size: 1.15rem; font-weight: 700; }
.pricing-stat .sub { font-size: .8rem; color: var(--muted); margin-top: .1rem; }

/* Feature checklist shown once above the three plan cards — every plan
   unlocks the same full platform, so the difference between tiers is
   billing cadence and price, not features; repeating an identical list
   inside all three cards would just be noise. */
.pricing-feature-grid {
  display: block;
}

.pricing-feature-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .9rem;
  padding: .35rem 0;
}

.pricing-feature-icon { color: var(--success); flex: 0 0 auto; }

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.25rem;
  margin: 1.5rem 0;
  align-items: stretch;
}

.pricing-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1.75rem 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  text-align: center;
}

/* The one plan we steer people toward gets a lift and a brand-gradient cap —
   reusing the same gradient as .hero rather than a new colour, so the
   "recommended" cue reads as an extension of the app's own palette. */
.pricing-card.is-featured {
  border-color: var(--primary);
  box-shadow: 0 10px 26px rgba(0,0,0,.14);
  transform: translateY(-6px);
}

.pricing-card.is-featured::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--primary), var(--success));
  border-radius: 5px 5px 0 0;
}

.pricing-ribbon {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: linear-gradient(90deg, var(--primary), var(--success));
  color: #fff;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: .3rem .8rem;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0,0,0,.22);
}

.pricing-plan-name {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
  font-weight: 700;
}

.pricing-price {
  font-size: 2.1rem;
  font-weight: 800;
  margin: .5rem 0 0;
  line-height: 1.1;
}

.pricing-price small { font-size: .95rem; font-weight: 500; color: var(--muted); }

.pricing-billed { font-size: .8rem; color: var(--muted); margin-top: .3rem; }

.pricing-save {
  display: inline-block;
  margin-top: .6rem;
  background: var(--success);
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  padding: .2rem .55rem;
  border-radius: 3px;
}

/* A perforated-ticket rule instead of a plain line — a small nod to a
   printed stub tearing away from its counterfoil, fitting for a printing-
   industry tool without pulling in any new colour or asset. */
.pricing-divider {
  border: none;
  height: 1px;
  margin: 1.15rem 0;
  background-image: linear-gradient(90deg, var(--border) 55%, transparent 0%);
  background-size: 9px 1px;
  background-repeat: repeat-x;
}

.pricing-tagline {
  font-size: .85rem;
  color: var(--muted);
  flex: 1;
  margin: 0 0 1.15rem;
}

.pricing-card .btn,
.pricing-card .btn:disabled { width: 100%; }

@media (max-width: 560px) {
  .pricing-card.is-featured { transform: none; }
}

/* -------------------------------------------------------------------------
   News page (/news)
   ---------------------------------------------------------------------- */

.news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.25rem;
}

.news-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
  transition: box-shadow .15s ease, transform .15s ease;
}

.news-card:hover {
  box-shadow: 0 8px 20px rgba(0,0,0,.12);
  transform: translateY(-2px);
}

/* Wraps the thumbnail image so the video play-badge can be positioned
   over it. Position context only — the image itself still fills it. */
.news-card-media {
  position: relative;
}

.news-card-img {
  width: 100%;
  height: 150px;
  object-fit: cover;
  background: var(--bg);
  display: block;
}

.news-card-img-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
}

/* Round play-button badge shown on the thumbnail when NewsData.io
   supplies a video_url for the article, opening the video in a new tab
   independently of the article-link click target below it. */
.news-card-play {
  position: absolute;
  bottom: .5rem;
  right: .5rem;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(0,0,0,.65);
  color: #fff;
  text-decoration: none;
  transition: background .15s ease;
}

.news-card-play:hover { background: rgba(0,0,0,.85); }

.news-card-body {
  padding: .9rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  flex: 1;
  text-decoration: none;
  color: var(--text);
}

.news-card-title {
  font-weight: 600;
  font-size: .95rem;
  line-height: 1.35;
  margin-bottom: .4rem;
}

.news-card-desc {
  font-size: .85rem;
  color: var(--muted);
  line-height: 1.5;
  margin: 0 0 .6rem;
  flex: 1;
}

.news-card-meta {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  font-size: .75rem;
  color: var(--muted);
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}
