/* =========================================================================
   osTicket client portal theme — Global Pathways Academy
   =========================================================================

   PRESENTATION LAYER. This stylesheet carries the client-portal redesign;
   the only template edits made alongside it are wrapper/markup changes in
   footer.inc.php and login.inc.php, verified attribute-identical with
   tools/attr-inventory.sh. No PHP logic, form attribute, or JS hook changed.

   Scope: loaded only by include/client/header.inc.php (via ASSETS_PATH,
   defined in client.inc.php). The agent and admin panels load
   scp/css/scp.css instead and are unaffected.

   Design source — gp.academy
   --------------------------
   This portal runs in direct conjunction with https://gp.academy, so the
   design system is copied from that site's compiled stylesheet
   (assets/styles-*.css), not invented:

     cream       #fbfaf6   page background
     cream-soft  #f4efe7   warm panels, footer band
     warm-beige  #ece7dd   deeper warm surface
     ink         #1b2230   text            (15.3:1 on cream)
     sage        #4f6b5c   primary actions (5.6:1 on cream, 5.9:1 under #fff text)
     sage-deep   #3e5649   hover/strong    (7.6:1 on cream)
     blue-deep   #2a4275   staff/secondary (9.4:1 on cream)
     gold        #b89348   DECORATIVE ONLY — 2.9:1 on white, never text
     line        rgba(27,34,48,.1)  hairlines
     radius      10px controls, 14px cards, pills for buttons
     type        General Sans (Fontshare) — headlines LIGHT (300) with
                 negative tracking; buttons 500; eyebrows tracked uppercase

   General Sans is self-hosted from assets/default/font/ (Fontshare permits
   self-hosting; the files are the latin woff2 subsets Fontshare serves).
   Self-hosting keeps the GDPR posture from docs/PROJECT-CONTEXT.md intact:
   no visitor IP is sent to a font CDN.

   Load order matters. These files load AFTER this one and win ties, so some
   rules below are raised to #content specificity (and keep !important where
   upstream used it):
     css/thread.css       .thread-body typography and link colour
     css/redactor.css     .redactor-box editor chrome
     css/filedrop.css     .filedrop upload widget (injected as field media)
     css/font-awesome.min.css

   Other invariants preserved from the first pass (see git history):
   colour is semantic-only outside the brand hue; reference numbers, dates
   and file sizes are tabular mono; section labels share one uppercase
   micro-label voice; alert bars auto-height (upstream clipped at 16px);
   the ticket-form 50/50 table-layout bug and the subject-cell descender
   clipping stay fixed; responsive from 320px up with no horizontal
   overflow (asserted by tools/preview/check.mjs).

   Re-branding: the palette lives in the custom properties below.
   ========================================================================= */

/* --- Brand face --------------------------------------------------------- */

@font-face {
  font-family: 'General Sans';
  src: url('../font/GeneralSans-300.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('../font/GeneralSans-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('../font/GeneralSans-400-Italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('../font/GeneralSans-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('../font/GeneralSans-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Brand (gp.academy) -------------------------------------------------- */
  --gp-brand:        #4f6b5c;   /* sage */
  --gp-brand-strong: #3e5649;   /* sage-deep */
  --gp-brand-tint:   #eef3f0;   /* sage over white, ~8% */
  --gp-brand-edge:   #cfdcd4;
  --gp-brand-ring:   rgba(79, 107, 92, 0.28);
  --gp-navy:         #2a4275;   /* blue-deep — staff-facing accents */
  --gp-navy-strong:  #1f3259;
  --gp-navy-tint:    #eef1f7;   /* navy over white, ~8% */
  --gp-navy-edge:    #cdd6e6;
  --gp-gold-soft:    rgba(184, 147, 72, 0.18);  /* gold, decorative only */

  /* Ink and surfaces ----------------------------------------------------- */
  --gp-ink:       #1b2230;
  --gp-ink-2:     #4d5563;     /* 8.0:1 on cream */
  --gp-ink-3:     #6a7080;     /* 4.7:1 on cream — floor for small labels */
  --gp-line:      rgba(27, 34, 48, 0.12);
  --gp-line-soft: rgba(27, 34, 48, 0.07);
  --gp-page:      #fbfaf6;     /* cream */
  --gp-surface:   #ffffff;     /* cards */
  --gp-surface-2: #f4efe7;     /* cream-soft */
  --gp-beige:     #ece7dd;

  /* Semantic — meaning only, never decoration ---------------------------- */
  --gp-ok:        #3e5649;
  --gp-ok-bg:     #edf3ee;
  --gp-ok-edge:   #cfdcd3;
  --gp-warn:      #8a5300;
  --gp-warn-bg:   #faf3e2;
  --gp-warn-edge: #e7d3a8;
  --gp-err:       #a52121;
  --gp-err-bg:    #fbf0ef;
  --gp-err-edge:  #ecc9c9;
  --gp-info:      #2a4275;
  --gp-info-bg:   #eef2f9;
  --gp-info-edge: #c9d6ea;

  /* Type ------------------------------------------------------------------ */
  --gp-sans: "General Sans", ui-sans-serif, -apple-system, BlinkMacSystemFont,
             "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --gp-mono: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono",
             Menlo, Consolas, monospace;

  /* Metrics ---------------------------------------------------------------- */
  /* Column scale. The three rungs are a golden-ratio progression — 27φ≈43.7,
     44φ≈71.2 — so a surface that steps up one reads as a deliberate change of
     measure rather than a mismatch. Which rung a surface takes is decided by
     the widest thing that MUST fit inside it, rounded up to the next rung:

       auth  one short text input          sign-in, check status, sign-up
       form  a rich-text toolbar, or a
             picker with a button beside   new ticket, profile, ticket reply
       page  anything tabular or
             multi-column                  ticket list, thread, KB, landing
       console  a working queue an agent
             scans all day                 agent panel ticket queue

     Nothing else may set a container width. A surface that needs a value not
     on this list is a surface whose contents need rethinking. */
  --gp-w-auth: 27rem;   /* 432px */
  --gp-w-form: 44rem;   /* 704px */
  --gp-w-page: 71rem;   /* 1136px, which is 1088 inside the page gutters */
  --gp-w-console: 100rem;  /* 1600px — the agent console; sits outside the
                              golden progression deliberately: it is sized by
                              the widest display the queue must fill, not by
                              its neighbours. Used by scp/css/scp-theme.css,
                              which copies these tokens (this file never loads
                              in the agent panel). */

  --gp-pad:    24px;
  --gp-gutter: 56px;    /* thread avatar gutter */
  --gp-r:      14px;    /* cards */
  --gp-r-sm:   10px;    /* controls */
  --gp-r-pill: 999px;

  /* Card treatment. Two levels, and only two: a CARD is a standalone surface
     sitting on the page background; an INSET is a secondary surface nested in
     a page's flow. Boxes at the same width still look mismatched when one is
     padded 30 and its neighbour 22, which is most of what made the portal feel
     uneven — five different card paddings had accumulated. */
  --gp-card-pad:  30px;
  --gp-card-gap:  26px;   /* space above a card */
  --gp-inset-pad: 18px;

  /* Prose. Boxes fill their rung; the lines inside them do not. */
  --gp-measure:      68ch;   /* body copy in page-width content */
  --gp-measure-lede: 52ch;   /* the centred intro under a page heading */

  /* Motion — colours fast, transforms slightly slower, both ease-out ------- */
  --gp-t-color: 120ms ease-out;
  --gp-t-move:  160ms cubic-bezier(0.23, 1, 0.32, 1);

  /* Optical correction for Font Awesome 3.2.1 glyphs set beside text.
     FA's em box has ascent 1536 / descent 0, so a glyph's box centre does not
     coincide with its ink centre, and align-items:center lines up boxes, not
     ink — leaving the glyph visibly low against the text's cap band. Measured
     against General Sans by decoding rendered pixels: the text's cap band runs
     18.00-29.13px inside a 40px pill (centre 23.60) while the glyph ink centre
     landed at 22.69 — about 1px high. Nudging down by 1px at 15px text lands
     the plus, magnifier, house, book, and document glyphs on the cap-band
     centre. Expressed in em so it tracks font-size. */
  --gp-icon-nudge: 0.065em;
}

/* =========================================================================
   1. Reset  (upstream reset.less, kept intact except where noted)
   ========================================================================= */

html {
  font-size: 100%;
  overflow-y: scroll;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
}
body {
  margin: 0;
  padding: 0;
  font-size: 16px;
  line-height: 1.55;
}
body, input, select, textarea, button {
  font-family: var(--gp-sans);
  color: var(--gp-ink);
}
b, strong { font-weight: 600; }
blockquote {
  margin: 1em 0;
  padding: 2px 0 2px 16px;
  border-left: 3px solid var(--gp-line);
  color: var(--gp-ink-2);
}
hr {
  display: block;
  height: 1px;
  border: 0;
  border-top: 1px solid var(--gp-line);
  margin: 1.5em 0;
  padding: 0;
}
small { font-size: 85%; }
ul, ol { margin: 1em 0; padding: 0 0 0 24px; }
img { border: 0; vertical-align: middle; max-width: 100%; }
form { margin: 0; }
fieldset { border: 0; margin: 0; padding: 0; }
label { cursor: pointer; }
input, select, textarea {
  font-size: 100%;
  margin: 0;
  vertical-align: baseline;
}
input { line-height: normal; }
input[type="button"], input[type="reset"], input[type="submit"], button {
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
input[type="checkbox"], input[type="radio"] {
  box-sizing: border-box;
  width: 17px;
  height: 17px;
  accent-color: var(--gp-brand);
  vertical-align: -3px;
}
textarea { overflow: auto; vertical-align: top; resize: vertical; }
table { border-collapse: collapse; border-spacing: 0; }
th, td { vertical-align: top; }
th { text-align: left; font-weight: normal; }
h1, h2, h3, h4, h5, h6, form, fieldset { margin: 0; padding: 0; }
code, kbd, samp, pre { font-family: var(--gp-mono); font-size: 0.9em; }

/* Every element that reports a size should measure it the same way. */
*, *::before, *::after { box-sizing: border-box; }

/* =========================================================================
   2. Typography
   ========================================================================= */

/* gp.academy sets headlines LIGHT with negative tracking — the single most
   recognisable trait of the brand's type. Bold belongs to inline emphasis,
   not to headings. */
h1, h2, h3, h4 {
  color: var(--gp-ink);
  font-weight: 400;
  letter-spacing: -0.011em;
  text-wrap: balance;
}
h1 {
  font-size: 2.1rem;
  line-height: 1.15;
  font-weight: 300;
  letter-spacing: -0.025em;
  margin-bottom: 0.45em;
}
h2, .subject { font-size: 1.35rem; line-height: 1.25; letter-spacing: -0.015em; }
h3 { font-size: 1.1rem; line-height: 1.35; font-weight: 500; }
h4 { font-size: 1rem; font-weight: 500; }

/* Headings that open a new section need air above them. Scoped to direct
   children and article bodies so #reply h2 and .headline keep their own
   spacing. */
#content > h2,
#content > h3,
#content .faq-content .thread-body h2,
#content .faq-content .thread-body h3 { margin-top: 1.5em; }
#content .faq-content .thread-body h2 { font-size: 1.35rem; }
#content .faq-content .thread-body h3 { font-size: 1.1rem; }
#content .thread-body h1 { font-weight: 300; letter-spacing: -0.025em; }

/* Prose keeps a readable measure. The BOXES fill the width of the page (see the
   cards below); the lines inside them do not — a 130-character line is hard to
   track back to the next one. */
#content > p,
.thread-body p,
.faq-content p,
#landing_page .thread-body li { max-width: var(--gp-measure); }

#content > p { color: var(--gp-ink-2); margin: 0 0 1em; }

/* Reference numbers, dates, sizes: tabular mono. Ticket numbers read as
   record locators; digits align down a column. */
#ticketTable tbody td:first-child a,
#ticketInfo h1 small,
#clientLogin #ticketno,
.filesize,
.thread-entry .header time {
  font-family: var(--gp-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* One voice for every micro-label, tuned to gp.academy's eyebrow style. */
#ticketTable thead th,
#ticketTable caption,
.headline,
.sidebar section .header,
.freetext-files .title,
#reply h2 {
  font-size: 0.6875rem;   /* 11px */
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gp-ink-3);
}

/* --- Links ------------------------------------------------------------ */
a, .link {
  color: var(--gp-brand);
  text-decoration: none;
  text-decoration-color: var(--gp-brand-edge);
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
  transition: color var(--gp-t-color);
}
a:hover, .link:hover {
  color: var(--gp-brand-strong);
  text-decoration: underline;
  text-decoration-color: currentColor;
  cursor: pointer;
}
a:focus-visible,
.link:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[contenteditable]:focus-visible {
  outline: 2px solid var(--gp-brand);
  outline-offset: 2px;
  border-radius: 3px;
}

/* =========================================================================
   3. Helpers  (names are markup contracts — keep all of them)
   ========================================================================= */

.centered     { text-align: center; }
.clear        { clear: both; height: 1px; visibility: hidden; }
.hidden       { display: none; }
.faded        { color: var(--gp-ink-3); }
.flush-right  { text-align: right; }
.flush-left   { text-align: left; }
.bleed        { margin: 0 !important; padding: 0 !important; }
.valign-helper { height: 100%; display: inline-block; vertical-align: middle; }
.truncate {
  display: inline-block;
  width: auto;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
.row { }
.span4, .span8 { display: inline-block; vertical-align: top; margin: 0 1%; }
.span4 { width: 29.5%; }
.span8 { width: 66%; }

/* =========================================================================
   4. Page frame
   ========================================================================= */

body { background: var(--gp-page); }

/* Pin the footer to the viewport bottom on short pages. The body's flow
   children are #container then #footer (#overlay/#loading are fixed and
   scripts render nothing), so a flex column with the container growing
   keeps the footer at the bottom edge of every screen instead of floating
   mid-page after short content. */
body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
#container { flex: 1 0 auto; }
#footer { flex-shrink: 0; }

#container {
  width: 100%;
  max-width: var(--gp-w-page);
  margin: 0 auto;
  padding: 0 var(--gp-pad);
  background: transparent;
  box-shadow: none;
}

/* --- Embedded mode ------------------------------------------------------ */
/* header.inc.php puts .embed on <body> when the page is being framed, so the
   very same open.php that serves the portal serves the embed and no part of
   the ticket flow is duplicated. Everything below is chrome: the ticket form
   itself, its card, its fields and its uploader are untouched.

   The flex column that pins the footer to the bottom of the viewport has to
   be undone with it. Inside an iframe, min-height:100vh means the document
   can never measure shorter than the frame it is already in, so the height
   reporter in footer.inc.php could only ever ratchet the frame taller. */
body.embed {
  min-height: 0;
  display: block;
  /* The host page owns the backdrop. Painting cream over it would make the
     frame read as a pasted-in block rather than part of their layout. */
  background: transparent;
}
body.embed .agent-bar,
body.embed .site-bar,
body.embed #footer { display: none; }
/* Outer width and gutters belong to the host's column, not to ours: the frame
   renders the widget and nothing else, and the host spaces it. The form keeps
   its own 44rem card and stays centred in whatever width it is given. */
body.embed #container {
  max-width: none;
  padding: 0;
}
body.embed #content {
  padding: 0;
  min-height: 0;
}
body.embed #ticketForm:has(> table) { margin-top: 0; }

/* --- Agent context bar -------------------------------------------------- */
/* Shown only while a staff session is live and valid — header.inc.php gates
   the whole element on it — so an end user never renders this markup at all.

   It sits above .site-bar rather than inside it on purpose. The bar's nav is
   centred by giving the logo and the account cluster the same flex basis, and
   the 1150px collapse breakpoint was measured against the widest row the
   templates can emit; a fifth item in that row would break both, for every
   visitor, to serve a state only agents reach. Out here it costs the bar
   nothing.

   Navy is the portal's staff-facing accent and appears nowhere else above the
   fold, so the strip reads as a different plane from the client chrome —
   which is exactly what it is: a second identity, with one action. */
.agent-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin: 18px 0 0;
  /* Matches .site-bar's insets exactly so the label starts on the logo's left
     edge and the action ends on the account cluster's right edge. */
  padding: 8px 10px 8px 20px;
  background: var(--gp-navy-tint);
  border: 1px solid var(--gp-navy-edge);
  border-radius: var(--gp-r-pill);
  font-size: 0.875rem;
}
/* The bar keeps its own 18px top margin when it leads the page; stacked under
   the strip the pair reads as one header block instead of two. */
.agent-bar + .site-bar { margin-top: 8px; }
/* Text only, like every other uppercase micro-label in the theme
   (.hero-eyebrow, .agent-signin-label, .sidebar section strong). This one
   briefly carried a Font Awesome glyph and was the odd one out; the glyph's
   ink centre measured 1.38px below the cap band and could not be aligned
   without a hand-tuned magic number.

   The cause is worth recording, because the same trap is set for any future
   icon+label pair: --gp-icon-nudge was derived by decoding rendered pixels
   for 15px MIXED-CASE nav text. Uppercase has no descenders, so its optical
   centre sits higher in the line box, and a 12px glyph's ink (10.4px) is
   taller than an 11px cap band (8.4px) — so the nudge, which pushes down,
   made it worse rather than better. Baseline alignment was measured too and
   lands about 1px high instead: Font Awesome 3.2.1's em box (ascent 1536,
   descent 0) means box centre never coincides with ink centre, so there is no
   principled alignment here, only a per-glyph constant. The strip already
   reads as staff-facing from its navy tint and filled pill; it does not need
   a 12px glyph bought at that price. */
.agent-bar-label {
  color: var(--gp-navy);          /* 8.4:1 on the tint */
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.agent-bar-name { color: var(--gp-ink); font-weight: 500; }
/* Filled, not ghost: this is the one action on the strip, and it has to beat
   the footer's ghost .staff-link for prominence. */
.agent-bar-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  min-height: 36px;
  padding: 7px 16px;
  background: var(--gp-navy);
  border: 1px solid var(--gp-navy);
  border-radius: var(--gp-r-pill);
  color: #fff !important;         /* 9.6:1 */
  font-weight: 500;
  white-space: nowrap;
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color),
              transform var(--gp-t-move);
}
.agent-bar-link::after { content: "\2192"; font-size: 0.9em; }  /* → */
.agent-bar-link:hover {
  background: var(--gp-navy-strong);
  border-color: var(--gp-navy-strong);
  color: #fff !important;
  text-decoration: none;
}
.agent-bar-link:active { transform: scale(0.98); }

/* --- Site bar: logo + navigation + account, one capsule ----------------- */
/* gp.academy's header is a single rounded capsule holding the logo at the
   left, the nav in the middle, and one pill CTA at the right. The portal
   copies that: header.inc.php wraps #header and #nav in .site-bar, and
   #header is dissolved with display:contents so the logo and the account
   cluster become flex items of the bar alongside #nav — no DOM reordering,
   so every conditional in the template still emits exactly what it did. */
.site-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin: 18px 0 0;
  padding: 7px 10px 7px 20px;
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r-pill);
}
/* The template emits an <hr> in place of #nav when there is no nav, and a
   float-clearing div that the flex row makes redundant. */
.site-bar > hr,
.site-bar > .clear { display: none; }

#header {
  display: contents;
  position: static;
  height: auto;
  padding: 0;
}
#header #logo {
  order: 1;
  height: auto;
  /* Zero basis so both end zones resolve to the SAME width and the nav lands
     on the bar's true centre; min-width keeps either end from being squashed
     below its content (whereupon centring degrades rather than breaking). */
  flex: 1 1 0;
  min-width: max-content;
  display: inline-flex;
  align-items: center;
}
#header #logo:hover { text-decoration: none; }
#header #logo img {
  max-height: 40px;
  max-width: 240px;
  width: auto;
  height: auto;
  vertical-align: middle;
}
/* Account cluster / sign-in, anchored right. */
#header .pull-right {
  order: 3;
  float: none;
  flex: 1 1 0;
  min-width: max-content;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 4px 14px;
}
#header p {
  width: auto;
  margin: 0;
  padding: 0;
  font-size: 0.8125rem;
  color: var(--gp-ink-3);
}
#header p:empty { display: none; }
/* The template always emits a second <p> for the language flags, holding only
   whitespace when the desk runs one language — so :empty never matches it.
   Keying on "has no element children" collapses it, and still shows it when
   flags are actually rendered. */
#header .pull-right > p:not(:has(*)) { display: none; }
#header p + p { margin-top: 0; }
#header p a { white-space: nowrap; color: var(--gp-brand); }
/* Signed in, the template emits "Name | Profile | Tickets (n) - Sign Out" as
   one run of text and links with literal separators. Wrapping it in a soft
   chip gives the bar a defined right end — the role gp.academy's CTA pill
   plays — without touching those separators. Excluded when the cluster holds
   the sign-in pill, which is its own terminus. */
#header .pull-right > p:has(a):not(:has(.signin-button)) {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px;
  background: var(--gp-page);
  border: 1px solid var(--gp-line-soft);
  border-radius: var(--gp-r-pill);
  color: var(--gp-ink-2);
}
/* The template used to separate these with literal "|" and "-" text, which no
   selector can reach; they are drawn here instead, so the cluster is both
   narrower and adjustable. */
.acct-name { color: var(--gp-ink); font-weight: 500; }
.acct-link + .acct-link::before,
.acct-name + .acct-link::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 0.9em;
  margin-right: 9px;
  vertical-align: -0.1em;
  background: var(--gp-line);
}
/* Tickets is already a nav item two hundred pixels away; in the bar it only
   pushed the cluster wide enough to knock the nav off centre. It stays in the
   collapsed menu, where there is room. */
@media (min-width: 1151px) {
  #header .acct-tickets { display: none; }
}

/* The one pill CTA at the right of the bar — gp.academy's "Inquire now". */
.signin-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 9px 20px;
  background: var(--gp-brand);
  border: 1px solid var(--gp-brand);
  border-radius: var(--gp-r-pill);
  color: #fff !important;
  font-size: 0.9375rem;
  font-weight: 500;
  white-space: nowrap;
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color),
              transform var(--gp-t-move);
}
.signin-button::after { content: "\2192"; font-size: 0.9em; }   /* → */
.signin-button:hover {
  background: var(--gp-brand-strong);
  border-color: var(--gp-brand-strong);
  color: #fff !important;
  text-decoration: none;
}
.signin-button:active { transform: scale(0.98); }

/* --- Menu toggle -------------------------------------------------------- */
/* A checkbox drives the mobile menu so it works with no JavaScript at all —
   the client portal loads no pjax, so nothing re-renders the header behind
   our back, and a nav that depends on scripts is a nav that can fail. The
   input stays 1px and focusable (not display:none) so it remains reachable
   by keyboard and the label picks up its focus ring. */
#nav-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  appearance: none;
  -webkit-appearance: none;
  border: 0;
}
.nav-toggle-btn {
  display: none;         /* shown by the media query below */
  order: 4;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  flex: none;
  border: 1px solid var(--gp-line);
  border-radius: 50%;
  color: var(--gp-ink);
  cursor: pointer;
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color);
}
.nav-toggle-btn::before {
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  content: "\f0c9";      /* reorder (hamburger) */
  font-size: 15px;
  line-height: 1;
}
.nav-toggle-btn:hover {
  background: var(--gp-brand-tint);
  border-color: var(--gp-brand-edge);
}
#nav-toggle:checked ~ #header .nav-toggle-btn {
  background: var(--gp-brand);
  border-color: var(--gp-brand);
  color: #fff;
}
#nav-toggle:checked ~ #header .nav-toggle-btn::before { content: "\f00d"; }  /* × */
#nav-toggle:focus-visible ~ #header .nav-toggle-btn {
  outline: 2px solid var(--gp-brand);
  outline-offset: 2px;
}

/* --- Primary navigation ------------------------------------------------- */
/* Pills inside the bar; the active item is filled sage. Icons come from the
   Font Awesome build the page already loads. */
#nav {
  order: 2;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  height: auto;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  white-space: normal;
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  width: auto;
  max-width: 100%;
}
#nav li { margin: 0; padding: 0; list-style: none; display: block; }
#nav li a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: auto;
  height: auto;
  min-height: 40px;          /* 48px with capsule padding — touch target */
  line-height: 1.3;
  text-align: left;
  padding: 9px 14px;
  margin: 0;
  color: var(--gp-ink-2);
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: var(--gp-r-pill);
  background: none;
  transition: background-color var(--gp-t-color), color var(--gp-t-color);
}
#nav li a::before {
  font-family: FontAwesome;
  font-weight: normal;
  font-style: normal;
  font-size: 0.9em;
  line-height: 1;
  color: var(--gp-ink-3);
  flex: none;
  transform: translateY(var(--gp-icon-nudge));
  transition: color var(--gp-t-color);
}
#nav li a.home::before    { content: "\f015"; }  /* home        */
#nav li a.kb::before      { content: "\f02d"; }  /* book        */
#nav li a.new::before     { content: "\f067"; }  /* plus        */
#nav li a.tickets::before { content: "\f0f6"; }  /* file-text   */
#nav li a.status::before  { content: "\f002"; }  /* search      */

#nav li a:hover {
  background: var(--gp-brand-tint);
  color: var(--gp-brand-strong);
  text-decoration: none;
}
#nav li a:hover::before { color: var(--gp-brand); }
/* --- Which pill is lit --------------------------------------------------- */
/* client.inc.php builds the nav with Home already active —
   `new UserNav($thisclient, 'home')` — and several pages never override it:
   login.php's override is unreachable behind an `if (!$nav)` that is never
   true, and account.php, profile.php, kb/*.php and pages/*.php make no
   setActiveNav() call at all. The result is a lit Home pill on the sign-in,
   register, profile and knowledgebase pages, which misreports where you are.

   Corrected here rather than in PHP to keep this pass presentation-only. Each
   page is identified by markup only it renders. The real fix is four lines of
   setActiveNav() in those entry points; see this commit's message. */
#nav li a.active,
#container:has(.searchbar) #nav li a.kb {
  color: #fff;
  background: var(--gp-brand);
  font-weight: 500;
}
#nav li a.active::before,
#container:has(.searchbar) #nav li a.kb::before { color: rgba(255, 255, 255, 0.85); }
#nav li a.active:hover,
#container:has(.searchbar) #nav li a.kb:hover {
  background: var(--gp-brand-strong);
  color: #fff;
}

/* Unlight the pill the default left lit where it is wrong: on the KB pages
   (the rule above lights the right one instead), and on the sign-in, register
   and profile pages, which no nav item leads to at all. */
#container:has(.searchbar) #nav li a.home.active,
#container:has(.login-row) #nav li a.active,
#container:has(form[action="account.php"]) #nav li a.active,
#container:has(form[action="profile.php"]) #nav li a.active {
  color: var(--gp-ink-2);
  background: none;
  font-weight: 500;
}
#container:has(.searchbar) #nav li a.home.active::before,
#container:has(.login-row) #nav li a.active::before,
#container:has(form[action="account.php"]) #nav li a.active::before,
#container:has(form[action="profile.php"]) #nav li a.active::before {
  color: var(--gp-ink-3);
}
#container:has(.searchbar) #nav li a.home.active:hover,
#container:has(.login-row) #nav li a.active:hover,
#container:has(form[action="account.php"]) #nav li a.active:hover,
#container:has(form[action="profile.php"]) #nav li a.active:hover {
  background: var(--gp-brand-tint);
  color: var(--gp-brand-strong);
}
#container:has(.searchbar) #nav li a.home.active:hover::before,
#container:has(.login-row) #nav li a.active:hover::before,
#container:has(form[action="account.php"]) #nav li a.active:hover::before,
#container:has(form[action="profile.php"]) #nav li a.active:hover::before {
  color: var(--gp-brand);
}
.rtl #nav li a { padding: 9px 14px; margin: 0; background-position: initial; }

/* --- Content column ---------------------------------------------------- */
#content {
  padding: 32px 0 56px;
  margin: 0;
  height: auto !important;
  min-height: 42vh;
}

/* --- Footer ------------------------------------------------------------ */
/* The gp.academy footer is a warm cream-soft band; it also carries the
   site's "Staff Sign In" link, which is the pattern the portal copies for
   the agent panel (footer.inc.php adds .staff-link on every page). */
#footer {
  margin-top: 8px;
  padding: 0;
  text-align: left;
  font-size: 0.875rem;
  color: var(--gp-ink-2);
  background: var(--gp-surface-2);
  border-top: 1px solid var(--gp-line);
}
#footer a { color: var(--gp-ink-2); }
#footer p { margin: 0; }
.footer-inner {
  max-width: var(--gp-w-page);
  margin: 0 auto;
  padding: 26px var(--gp-pad) 30px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 28px;
}
.footer-copyright { color: var(--gp-ink-3); }
.footer-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 22px;
}
/* Staff entrance: quiet but unmissable — a navy ghost pill with an arrow,
   present on every page of the portal. */
.staff-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  padding: 7px 16px;
  border: 1px solid var(--gp-navy);
  border-radius: var(--gp-r-pill);
  color: var(--gp-navy) !important;
  font-weight: 500;
  transition: background-color var(--gp-t-color), color var(--gp-t-color);
}
.staff-link::after { content: "\2192"; font-size: 0.9em; }  /* → */
.staff-link:hover {
  background: var(--gp-navy);
  color: #fff !important;
  text-decoration: none;
}
#footer #poweredBy {
  display: block;
  width: 126px;
  height: 23px;
  outline: none;
  text-indent: -9999px;
  margin: 0;
  background: url('../images/poweredby.png') top left no-repeat;
  background-size: auto 20px;
  opacity: 0.45;
  transition: opacity var(--gp-t-color);
}
#footer #poweredBy:hover { opacity: 0.85; }

/* =========================================================================
   5. Buttons and form controls
   ========================================================================= */

/* --- .button family — gp.academy pills --------------------------------- */
/* .blue.button is the primary action in every template that uses it,
   .green.button the secondary; mapped to the brand's filled-sage and
   ghost-ring pills. Light sage (#7c9f86) from the marketing site fails
   contrast under white text (2.9:1), so fills use full sage. */
.button,
.button:visited {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 10px 22px;
  max-width: 100%;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
  text-decoration: none;
  text-shadow: none;
  border: 1px solid var(--gp-brand);
  border-radius: var(--gp-r-pill);
  background: var(--gp-brand);
  color: #fff;
  box-shadow: none;
  position: relative;
  cursor: pointer;
  font-family: inherit;
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color),
              color var(--gp-t-color), transform var(--gp-t-move);
}
.button:hover {
  background: var(--gp-brand-strong);
  border-color: var(--gp-brand-strong);
  color: #fff;
  text-decoration: none;
}
.button:active { top: 0; box-shadow: none; transform: scale(0.98); }

.button, .button:visited,
.blue.button, .blue.button:visited {
  background: var(--gp-brand);
  border-color: var(--gp-brand);
  color: #fff;
}
.blue.button:hover {
  background: var(--gp-brand-strong);
  border-color: var(--gp-brand-strong);
}
.green.button, .green.button:visited {
  background: transparent;
  border-color: rgba(27, 34, 48, 0.35);
  color: var(--gp-ink);
}
.green.button:hover {
  background: var(--gp-surface);
  border-color: var(--gp-ink);
  color: var(--gp-ink);
}

/* --- Native buttons ----------------------------------------------------- */
input[type="submit"],
button[type="submit"],
.btn {
  min-height: 44px;
  padding: 10px 22px;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
  color: #fff;
  background: var(--gp-brand);
  border: 1px solid var(--gp-brand);
  border-radius: var(--gp-r-pill);
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color),
              transform var(--gp-t-move);
}
input[type="submit"]:hover,
button[type="submit"]:hover,
.btn:hover {
  background: var(--gp-brand-strong);
  border-color: var(--gp-brand-strong);
}
input[type="reset"],
input[type="button"],
button {
  min-height: 44px;
  padding: 10px 18px;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--gp-ink-2);
  background: transparent;
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r-pill);
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color),
              color var(--gp-t-color), transform var(--gp-t-move);
}
input[type="reset"]:hover,
input[type="button"]:hover,
button:hover {
  background: var(--gp-surface);
  border-color: rgba(27, 34, 48, 0.4);
  color: var(--gp-ink);
}
input[type="submit"]:active,
input[type="reset"]:active,
input[type="button"]:active,
button:active,
.btn:active { transform: scale(0.98); }
input[type="submit"][disabled],
input[type="button"][disabled],
input[type="reset"][disabled],
button[disabled] {
  opacity: 0.55;
  cursor: default;
}

/* js/osticket.js flags an edited form with an inline color:red on the
   submit button, and clears it on reset. Inline colour wins, so give the
   button a light ground the red can be read against and carry the signal
   in the border too. */
input[type="submit"][style*="color"] {
  background: var(--gp-surface);
  border: 2px solid var(--gp-warn);
  font-weight: 600;
}

/* Action rows */
/* Action rows. These MUST stay direct-child selectors: as descendant
   selectors they also matched the last <p> inside Redactor's contenteditable
   (which is :last-child of .redactor-in), turning the paragraph the user types
   into a centred flex container with a 20px top margin — so text centred
   itself and the caret sat below the placeholder instead of over it. */
p.buttons,
#reply > p:last-child,
#ticketForm > p:last-child {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  align-items: center;
  margin: 20px 0 0;
}

/* --- Text inputs -------------------------------------------------------- */
input[type="text"],
input[type="password"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="search"],
input[type="date"],
input[type="time"],
select,
textarea {
  min-height: 44px;
  padding: 10px 14px;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--gp-ink);
  background: var(--gp-surface);
  border: 1px solid rgba(27, 34, 48, 0.18);
  border-radius: var(--gp-r-sm);
  max-width: 100%;
  transition: border-color var(--gp-t-color), box-shadow var(--gp-t-color);
}
textarea { min-height: 120px; padding: 12px 14px; line-height: 1.55; }
select {
  padding-right: 34px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--gp-ink-3) 50%),
    linear-gradient(135deg, var(--gp-ink-3) 50%, transparent 50%);
  background-position: right 17px center, right 12px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  -webkit-appearance: none;
  appearance: none;
}
.rtl select {
  padding-right: 14px;
  padding-left: 34px;
  background-position: left 12px center, left 17px center;
}
input[type="text"]:hover,
input[type="password"]:hover,
select:hover,
textarea:hover { border-color: rgba(27, 34, 48, 0.4); }

input:focus,
select:focus,
textarea:focus {
  border-color: var(--gp-brand);
  box-shadow: 0 0 0 3px var(--gp-brand-ring);
  outline: none;
}
input::placeholder, textarea::placeholder { color: var(--gp-ink-3); }
input[type="file"] { min-height: 0; padding: 0; border: 0; font-size: 0.9375rem; }

/* The contenteditable holds USER content, not form furniture — anything the
   form rules above could reach into it is reset here. Kept next to the editor
   styling so the two are read together. */
#content .redactor-in em {
  color: inherit;
  font-size: inherit;
}
/* Editor block spacing. Redactor sets no paragraph margins of its own, so a
   <p> kept the UA default 1em top margin — which at the editor's 15px font
   pushed the first line, and the caret, 15px below the placeholder. Redactor
   generates the placeholder on .redactor-in itself, so it sits at the padding
   box top and the two never lined up: you could only type under the
   placeholder, never over it. Zero the leading margin and space blocks from
   the bottom instead, the way a text editor should. */
#content .redactor-in p,
#content .redactor-in ul,
#content .redactor-in ol,
#content .redactor-in blockquote,
#content .redactor-in pre {
  margin: 0 0 0.7em;
}
#content .redactor-in > :first-child { margin-top: 0; }
#content .redactor-in > :last-child { margin-bottom: 0; }

/* Redactor draws its own chrome; match it to the inputs above. Raised to
   #content specificity because css/redactor.css loads after this file. */
#content .redactor-box.redactor-styles-on {
  border: 1px solid rgba(27, 34, 48, 0.18);
  border-radius: var(--gp-r-sm);
  overflow: hidden;
  background: var(--gp-surface);
}
#content .redactor-box.redactor-styles-on:focus-within {
  border-color: var(--gp-brand);
  box-shadow: 0 0 0 3px var(--gp-brand-ring);
}
#content .redactor-box.redactor-styles-on .redactor-toolbar {
  background: var(--gp-page);
  border-bottom: 1px solid var(--gp-line);
  padding: 4px 6px;
  border-radius: 0;
}
#content .redactor-box .redactor-in {
  padding: 12px 14px;
  min-height: 140px;
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* --- Attachments: one control with the editor ---------------------------- */
/* ThreadEntryWidget::render() prints the uploader straight after the textarea,
   so redactor's .redactor-box and .filedrop end up adjacent siblings on BOTH
   the new-ticket form and the ticket reply. That lets the two be drawn as a
   single bounded field: editor on top, attached files, then an attach bar fused
   to the bottom edge. Upstream anticipated this — filedrop.css already squares
   the dropzone's top corners inside a .-redactor-container.
   All rules are raised to #content specificity because css/filedrop.css is
   injected as field media and therefore loads after this file. */

/* The editor gives up its bottom edge to whatever follows. */
#content .redactor-box.redactor-styles-on:has(+ .filedrop) {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom: 0;
}
#content .redactor-box + .filedrop {
  padding-bottom: 0;
  border: 1px solid rgba(27, 34, 48, 0.18);
  border-top: 1px solid var(--gp-line);
  border-radius: 0 0 var(--gp-r-sm) var(--gp-r-sm);
  overflow: hidden;
  background: var(--gp-surface);
}
/* Standalone uploader (a file field of its own) keeps a full box. */
#content .filedrop { padding-bottom: 10px; }

/* The attach bar. The template's text is "Drop files here or choose them"; the
   link is the actionable half, so it reads as the control. */
#content .filedrop .dropzone {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  border: 0;
  border-radius: 0;
  background: var(--gp-page);
  color: var(--gp-ink-3);
  padding: 11px 14px;
  font-size: 0.875rem;
  transition: background-color var(--gp-t-color), color var(--gp-t-color);
}
#content .redactor-box + .filedrop .dropzone { border-radius: 0 0 var(--gp-r-sm) var(--gp-r-sm); }
#content .filedrop .dropzone i.icon-upload {
  color: var(--gp-brand);
  font-size: 1rem;
  position: relative;
  top: var(--gp-icon-nudge);
}
#content .filedrop .dropzone a.manual {
  color: var(--gp-brand);
  font-weight: 550;
  text-decoration: underline;
  text-decoration-color: var(--gp-brand-edge);
  text-underline-offset: 0.18em;
}
#content .filedrop .dropzone a.manual:hover {
  color: var(--gp-brand-strong);
  text-decoration-color: currentColor;
}
/* Drag state. filedrop.field.js sets an inline
   background-color: rgba(0,0,0,0.3) on dragover and clears the whole style
   attribute on leave/drop — there is no class to hook, so the inline value is
   the selector, and it needs !important to be overridden. */
#content .filedrop .dropzone[style*="background-color"] {
  background-color: var(--gp-brand-tint) !important;
  color: var(--gp-brand-strong);
  box-shadow: inset 0 0 0 2px var(--gp-brand);
}
#content .filedrop .dropzone[style*="background-color"] i.icon-upload,
#content .filedrop .dropzone[style*="background-color"] a.manual { color: var(--gp-brand-strong); }

/* --- The attached-file list --------------------------------------------- */
#content .filedrop .files { padding: 0; border: 0; }
#content .filedrop .files:not(:empty) {
  border: 0;
  border-radius: 0;
  padding: 6px;
}
#content .filedrop .files:not(:empty) + .dropzone { border-top: 1px solid var(--gp-line); }

/* Upstream pins each row to height:25px, which crushes any thumbnail into a
   sliver. Rows size to their content instead. */
#content .filedrop .files .file {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 12px;
  height: auto;
  min-height: 0;
  padding: 7px 9px;
  margin: 0;
  border-radius: var(--gp-r-sm);
}
#content .filedrop .files .file:hover { background: var(--gp-brand-tint); }
/* addNode() emits .filetype but never puts a class on it — it is always empty. */
#content .filedrop .files .filetype { display: none; }
/* A picture should look like the picture. Was max 100x25. */
#content .filedrop .preview {
  order: 1;
  width: 42px;
  height: 42px;
  max-width: 42px;
  max-height: 42px;
  padding: 0;
  float: none;
  flex: none;
  object-fit: cover;
  border-radius: var(--gp-r-sm);
  background: var(--gp-surface-2);
}
/* Non-image uploads leave the <img> with no src; collapse it rather than
   showing a broken-image box. */
#content .filedrop .preview:not([src]),
#content .filedrop .preview[src=""] { display: none; }
#content .filedrop .files .file .filename {
  order: 2;
  flex: 1 1 12rem;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 0;
  font-size: 0.9375rem;
  color: var(--gp-ink);
  overflow: hidden;
}
#content .filedrop .files .file .filename > a,
#content .filedrop .files .file .filename > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#content .filedrop .files .file .filesize {
  margin: 0;
  flex: none;
  font-family: var(--gp-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
  color: var(--gp-ink-3);
}
#content .filedrop .files .file .upload-rate {
  margin: 0;
  float: none;
  font-size: 0.75rem;
  color: var(--gp-ink-3);
}
/* Remove/cancel controls sit at the far end; .pull-right's float is inert in a
   flex row, so they are pushed there instead. */
#content .filedrop .files .file .trash,
#content .filedrop .files .file .cancel {
  order: 3;
  float: none;
  margin-left: auto;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  color: var(--gp-ink-3);
  cursor: pointer;
  transition: background-color var(--gp-t-color), color var(--gp-t-color);
}
#content .filedrop .files .file .trash:hover,
#content .filedrop .files .file .cancel:hover {
  background: var(--gp-err-bg);
  color: var(--gp-err);
}
/* Progress takes its own line under the row. */
#content .filedrop .files .file .progress {
  order: 4;
  flex-basis: 100%;
  height: 4px;
  margin-top: 8px;
  background: var(--gp-surface-2);
  border-radius: var(--gp-r-pill);
  box-shadow: none;
  overflow: hidden;
}
#content .filedrop .files .file .progress-bar {
  background-color: var(--gp-brand);
  box-shadow: none;
  height: 100%;
}

/* Field furniture inside forms */
label.required, span.required { font-weight: 600; }
.form-header h3 { margin-bottom: 2px; }
.form-header > div { color: var(--gp-ink-2); font-size: 0.9375rem; }

.uploads { display: inline-block; padding-right: 20px; }
.uploads label { padding: 3px 10px 3px 3px; width: auto !important; }

.freetext-files {
  padding: 14px 16px;
  margin-top: 12px;
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r-sm);
  background: var(--gp-surface);
}
.freetext-files .file {
  margin-right: 10px;
  display: inline-block;
  width: 48%;
  padding-top: 0.2em;
}
.freetext-files .title { margin-bottom: 0.5em; }

/* =========================================================================
   6. Alerts, notices, and errors
   ========================================================================= */

/* Auto height (upstream clipped at 16px), Font Awesome icons, semantic
   left edge — palette harmonised with the brand: success speaks sage,
   info speaks the staff navy. */
#msg_notice, #msg_warning, #msg_error, #msg_info,
.notice_bar, .warning_bar, .error_bar, .warning-banner {
  position: relative;
  display: block;
  height: auto;
  min-height: 0;
  line-height: 1.5;
  margin: 0 0 16px;
  padding: 12px 16px 12px 42px;
  font-size: 0.9375rem;
  border: 1px solid;
  border-left-width: 3px;
  border-radius: var(--gp-r-sm);
  background-image: none;
}
#msg_notice::before, #msg_warning::before, #msg_error::before,
#msg_info::before, .notice_bar::before, .warning_bar::before,
.error_bar::before, .warning-banner::before {
  position: absolute;
  left: 15px;
  top: 13px;
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  font-size: 15px;
  line-height: 1.2;
}
#msg_notice, .notice_bar {
  color: var(--gp-ok);
  background-color: var(--gp-ok-bg);
  border-color: var(--gp-ok-edge);
  border-left-color: var(--gp-ok);
}
#msg_notice::before, .notice_bar::before { content: "\f058"; }  /* ok-sign */

#msg_warning, .warning_bar, .warning-banner {
  color: var(--gp-warn);
  background-color: var(--gp-warn-bg);
  border-color: var(--gp-warn-edge);
  border-left-color: var(--gp-warn);
}
#msg_warning::before, .warning_bar::before,
.warning-banner::before { content: "\f071"; }                   /* warning */

#msg_error, .error_bar {
  color: var(--gp-err);
  background-color: var(--gp-err-bg);
  border-color: var(--gp-err-edge);
  border-left-color: var(--gp-err);
}
#msg_error::before, .error_bar::before { content: "\f06a"; }     /* excl.   */

#msg_info {
  color: var(--gp-info);
  background-color: var(--gp-info-bg);
  border-color: var(--gp-info-edge);
  border-left-color: var(--gp-info);
}
/* view.inc.php puts its own icon-compass in #msg_info; don't double up. */
#msg_info::before { content: none; }
#msg_info { padding-left: 16px; }
#msg_info .icon-2x { color: var(--gp-info); margin-right: 12px; }
#msg_notice a, #msg_warning a, #msg_error a, #msg_info a { color: inherit; }

/* The banners the header emits sit above the content column. */
.notice_bar, .warning_bar, .error_bar { margin: 16px 0 0; }

.warning {
  background: var(--gp-warn-bg);
  border: 1px solid var(--gp-warn-edge);
  border-radius: var(--gp-r-sm);
  padding: 10px 14px;
  font-style: normal;
  color: var(--gp-ink-2);
}
.warning strong {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.8125rem;
  color: var(--gp-warn);
  font-style: normal;
}

/* Inline field errors. font.error is emitted by the ticket form. */
.error, font.error { color: var(--gp-err); font-size: 0.875rem; }
.error input { border-color: var(--gp-err); }
div.error { margin-top: 4px; }

/* =========================================================================
   7. Landing page
   ========================================================================= */

/* Centered hero, gp.academy style: eyebrow, light headline, the KB search
   as the hero control, then the CTA pill pair, then a warm card holding the
   featured questions. The DOM order (sidebar first, then main-content, then
   the featured-articles block) is untouched — the sidebar's CTA conditionals
   stay in sidebar.tmpl.php — and flex `order` does the arranging. */
#landing_page {
  overflow: visible;
  display: flex;
  flex-direction: column;
}
.main-content { width: auto; }
#landing_page .main-content {
  order: 1;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 26px 0 4px;
}
.hero-eyebrow {
  order: 1;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gp-ink-3);
  margin-bottom: 16px;
}
#landing_page .thread-body {
  order: 2;
  padding: 0;
  background: transparent;
  max-width: var(--gp-measure);
}
#landing_page .thread-body h1 {
  font-size: clamp(2rem, 4.5vw, 2.75rem);
  margin-bottom: 14px;
}
#landing_page .thread-body p { margin-left: auto; margin-right: auto; color: var(--gp-ink-2); }
#landing_page .search-form {
  order: 3;
  width: 100%;
  padding: 18px 0 2px;
  display: flex;
  justify-content: center;
}
#landing_page .search-form form { width: min(580px, 100%); }
#landing_page .search-form .search { flex: 1 1 240px; width: auto; }

/* The sidebar block becomes the hero CTA row + the featured-questions card. */
#landing_page .sidebar {
  order: 2;
  float: none !important;
  width: 100%;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
#landing_page .front-page-button {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin: 14px 0 40px;
}
#landing_page .front-page-button p { margin: 0; }
/* sidebar.tmpl.php puts an inline display:block on the CTA anchors. */
#landing_page .front-page-button .button {
  display: inline-flex !important;
  width: auto;
  min-width: 220px;
}
#landing_page .sidebar .content {
  width: 100%;
  padding: var(--gp-card-pad);
  background: var(--gp-surface-2);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
  display: flex;
  flex-wrap: wrap;
  gap: 22px 56px;
  text-align: left;
}
#landing_page .sidebar .content section { flex: 1 1 240px; min-width: 0; }
/* With the knowledgebase off and no "other resources" pages, sidebar.tmpl.php
   emits <div class="content"></div> with nothing in it. The generic
   `.sidebar .content:empty { display: none }` guard further down could not win
   against the `display: flex` above it — id beats pseudo-class — so the empty
   card still painted as a beige box where the featured questions would be. */
#landing_page .sidebar .content:empty { display: none; }
/* Same scenario, the other half: index.php always emits the wrapper for the
   featured-articles block, and with the knowledgebase off it holds nothing but
   whitespace — leaving this rule's top padding as dead space. Keyed on "has no
   heading and no category" so it also collapses when the KB is on but nothing
   is featured. */
#landing_page > .clear + div:not(:has(h1, .featured-category)) {
  display: none;
}
#landing_page .sidebar section + section {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

#landing_page > .clear { order: 3; }
/* index.php separates the featured-articles block with a .clear plus two
   <br>s; the warm card above already provides the section break. */
#landing_page > .clear + div { order: 4; border-top: 0; padding-top: 34px; margin-top: 0; }
#landing_page > .clear + div > br { display: none; }
#landing_page > .clear + div > h1 { font-size: 1.5rem; margin-bottom: 8px; }
#landing_page h1,
#landing_page h2,
#landing_page h3 { margin-bottom: 12px; }

.search-form { padding: 0 0 24px; }
.search-form form { display: flex; gap: 10px; flex-wrap: wrap; }
.searchbar .search,
.search-form .search {
  display: inline-block;
  width: 400px;
  max-width: 100%;
  flex: 1 1 240px;
  border-radius: var(--gp-r-pill);
  border: 1px solid rgba(27, 34, 48, 0.18);
  padding: 10px 18px;
  box-shadow: none;
  background: var(--gp-surface);
}
.searchbar .search {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 10px;
  flex: none;
}
.search-form .button { flex: none; }

/* Upstream #new_ticket / #check_status blocks — no current template emits
   them, but a customised landing page may; keep them harmless. */
#landing_page #new_ticket,
#landing_page #check_status {
  width: 295px;
  max-width: 100%;
  padding-left: 75px;
  margin-top: 40px;
}
#landing_page #new_ticket {
  background: url('../images/new_ticket_icon.png') top left no-repeat;
}
#landing_page #check_status {
  background: url('../images/check_status_icon.png') top left no-repeat;
}

/* --- Featured KB articles ---------------------------------------------- */
.featured-category {
  margin-top: 4px;
  margin-bottom: 20px;
  width: 49%;
  display: inline-block;
  vertical-align: top;
  padding-right: 28px;
}
.featured-category i {
  color: var(--gp-brand);
  text-shadow: none;
  display: inline-block;
  vertical-align: middle;
  font-size: 1.05em !important;
  margin-right: 8px;
}
.category-name {
  display: inline-block;
  font-weight: 500;
  font-size: 1.05rem;
  letter-spacing: -0.005em;
  color: var(--gp-ink);
}
.article-headline {
  margin-left: 0;
  padding: 13px 0;
  border-top: 1px solid var(--gp-line-soft);
}
.article-headline:first-of-type { margin-top: 10px; }
.article-title { font-weight: 500; line-height: 1.4; }
/* Upstream clipped the teaser with a hard height:3em, which cut text
   mid-word with no ellipsis. Clamp it properly instead. */
.article-teaser {
  font-size: 0.875rem;
  line-height: 1.55;
  height: auto;
  max-height: none;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--gp-ink-3);
  margin-top: 2px;
}
.faq-content .article-title {
  font-size: 1.6rem;
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.025em;
  margin-top: 4px;
}

/* =========================================================================
   8. Sidebar
   ========================================================================= */

.sidebar {
  margin-bottom: 24px;
  margin-left: 36px;
  width: 284px;
}
/* On the knowledgebase pages the sidebar sits inside .span4, so it should fill
   that column instead of holding a fixed width and leaving a gap beside it. */
.span4 .sidebar {
  width: auto;
  margin-left: 0;
}
.front-page-button { display: grid; gap: 10px; margin-bottom: 22px; }
.front-page-button p { margin: 0; }
.front-page-button .button { width: 100%; max-width: none; }

.sidebar .content {
  padding: var(--gp-inset-pad);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
  background: var(--gp-surface);
}
.sidebar .content:empty { display: none; }
.sidebar section .header { margin-bottom: 8px; }
.sidebar section strong {
  display: block;
  margin-bottom: 8px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gp-ink-3);
}
.sidebar section + section {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--gp-line-soft);
}
.sidebar section > div { padding: 4px 0; line-height: 1.45; }
.sidebar .content a { color: var(--gp-brand); }
.sidebar select { width: 100%; max-width: 100%; }

/* =========================================================================
   9. Knowledgebase
   ========================================================================= */

#breadcrumbs {
  color: var(--gp-ink-3);
  font-size: 0.875rem;
  margin-bottom: 16px;
}
#breadcrumbs a { color: var(--gp-ink-2); }

#kb { margin: 4px 0 0; padding: 0; overflow: hidden; }
#kb > li {
  position: relative;
  padding: 22px 0;
  height: auto !important;
  overflow: hidden;
  margin: 0;
  background: none;
  border-bottom: 1px solid var(--gp-line);
  display: block;
  list-style: none;
}
#kb > li h4 { margin-bottom: 2px; }
#kb > li h4 a { font-size: 1.1rem; font-weight: 500; }
#kb > li h4 span { color: var(--gp-ink-3); }
/* Was a 32px folder PNG; now the Font Awesome folder already on the page. */
#kb > li > i {
  display: block;
  width: 34px;
  height: 34px;
  float: left;
  margin-right: 6px;
  background: var(--gp-brand-tint);
  border-radius: 50%;
  color: var(--gp-brand);
  font-size: 15px;
  line-height: 34px;
  text-align: center;
}
#kb > li > i::before { font-family: FontAwesome; content: "\f07b"; }
.rtl #kb > li > i { float: right; margin-right: 0; margin-left: 6px; }
#kb > li > div { margin-left: 48px; }
#kb .faded { color: var(--gp-ink-2); font-size: 0.9375rem; }

.popular-faq { padding: 4px 0 4px 0; line-height: 1.45; }
.popular-faq i { color: var(--gp-ink-3); margin-right: 6px; }

#faq { clear: both; margin: 0; padding: 0; }
#faq ol {
  font-size: 1rem;
  margin: 12px 0 0;
  padding-left: 0;
  border-top: 1px solid var(--gp-line);
}
#faq ol li { list-style: none; margin: 0; padding: 0; color: var(--gp-ink-3); }
#faq ol li a {
  display: block;
  padding: 13px 8px 13px 26px;
  height: auto !important;
  overflow: hidden;
  margin: 0;
  border-bottom: 1px solid var(--gp-line);
  line-height: 1.45;
  background: none;
  position: relative;
  transition: background-color var(--gp-t-color);
}
#faq ol li a::before {
  font-family: FontAwesome;
  content: "\f016";               /* file-alt */
  position: absolute;
  left: 4px;
  top: 13px;
  color: var(--gp-ink-3);
  font-size: 0.9em;
}
#faq ol li a:hover { background-color: var(--gp-brand-tint); text-decoration: none; }
#faq .article-meta { padding: 8px; background: var(--gp-surface-2); }

.faq-content { margin-top: 4px; }
.faq-content .thread-body { background: transparent; }

/* Legacy KB search ids. No current template emits them; harmless to keep. */
#kb-search { padding: 10px 0; overflow: hidden; }
#kb-search div { clear: both; overflow: hidden; padding-top: 5px; }
#kb-search #query, #kb-search #cid { width: 200px; margin-right: 8px; }
#kb-search #topic-id { width: 410px; max-width: 100%; }

/* =========================================================================
   10. Ticket form  (open.inc.php, edit.inc.php, register, profile)
   ========================================================================= */

/* Centred form column, matching the sign-in page. Scoped to "#ticketForm that
   contains a table" so it hits open.inc.php and edit.inc.php but not the bare
   #ticketForm the alerts specimen uses. The fields stay left-aligned inside the
   card — only the column and the page heading are centred. */
/* The head shares the card's column, so the page is one measure from the
   heading down rather than a full-bleed title above a narrow card. The lede
   additionally keeps a reading measure, which on this rung is the narrower of
   the two. */
#content:has(#ticketForm > table) > h1,
#content:has(#ticketForm > table) > p {
  display: block;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
  max-width: var(--gp-w-form);
}
#content:has(#ticketForm > table) > h1 { margin-bottom: 10px; }
#content:has(#ticketForm > table) > p {
  max-width: min(var(--gp-w-form), var(--gp-measure-lede));
}
#ticketForm:has(> table) {
  width: 100%;
  /* Form rung: the editor toolbar and its attachment bar are the widest things
     that must fit, and they cramp at the auth rung below. */
  max-width: var(--gp-w-form);
  margin: var(--gp-card-gap) auto 0;
  padding: var(--gp-card-pad);
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
}
/* The template opens with <td colspan=2><hr>, which is now redundant against
   the card's own top edge. */
#ticketForm:has(> table) > table > tbody:first-of-type > tr:first-child hr { display: none; }
#ticketForm:has(> table) > hr:last-of-type { display: none; }

#ticketForm > table,
#clientLogin table,
table.padded {
  width: 100%;
  max-width: 100%;
}
/* Upstream set table-layout:fixed here, but the first row of every client
   form is a <td colspan="2"><hr>, so fixed layout had no column widths to
   read and split the table 50/50 — leaving a half-width label column.
   Auto layout plus a shrink-to-fit label column instead. */
#ticketForm > table { table-layout: auto; }
#ticketForm > table > tbody > tr > td { padding: 4px 0; }
#ticketForm > table > tbody > tr > td:first-child:not([colspan]) {
  width: 1%;
  white-space: nowrap;
  padding-right: 28px;
  color: var(--gp-ink-2);
}
#ticketForm > table > tbody > tr > td[colspan] { width: auto; white-space: normal; }

#ticketForm div.clear,
#clientLogin div.clear { clear: both; padding: 3px 0; overflow: hidden; }

#ticketForm div label,
#clientLogin div label { display: block; }
#ticketForm div label.required,
#clientLogin div label.required { text-align: left; }
#ticketForm div input,
#clientLogin div input,
#ticketForm div textarea,
#clientLogin div textarea { width: auto; display: block; }
#ticketForm div input[type="file"],
#clientLogin div input[type="file"] { border: 0; }
#ticketForm div select,
#clientLogin div select { display: block; float: none; }

#ticketForm td textarea,
#clientLogin td textarea,
#ticketForm div textarea,
#clientLogin div textarea { width: 100%; max-width: 640px; }

#ticketForm td em,
#clientLogin td em,
#ticketForm div em,
#clientLogin div em { color: var(--gp-ink-3); font-size: 0.875rem; }

#ticketForm label > span:first-child {
  display: inline-block;
  margin-bottom: 6px;
  font-weight: 500;
  color: var(--gp-ink);
}
#ticketForm label > span:first-child.required { font-weight: 600; }

#ticketForm div div.captchaRow,
#clientLogin div div.captchaRow { line-height: normal; }
#ticketForm div div.captchaRow input,
#clientLogin div div.captchaRow input { position: static; top: 0; }
tr.captchaRow td { padding-top: 14px; }
#ticketForm td .captcha,
#clientLogin td .captcha,
#ticketForm div .captcha,
#clientLogin div .captcha {
  width: 88px;
  height: 31px;
  background: var(--gp-ink);
  border-radius: 4px;
  overflow: hidden;
  display: inline-block;
  float: none;
  vertical-align: middle;
  margin-right: 12px;
}
#ticketForm td label.inline,
#clientLogin td label.inline,
#ticketForm div label.inline,
#clientLogin div label.inline { width: auto; padding: 0 10px; display: inline; }

#ticketForm div.error input,
#clientLogin div.error input { border-color: var(--gp-err); }
#ticketForm div.error label,
#clientLogin div.error label { color: var(--gp-err); }

/* Section dividers inside the stacked form tables. */
#ticketForm .form-header,
table.padded h3 { margin-top: 4px; }
table.padded tr > td,
table.padded tr > th { height: auto; padding: 6px 12px 6px 0; }
table.padded h3 { font-size: 1.1rem; }

/* --- Account pages: register.inc.php + profile.inc.php ------------------- */
/* These two mix two row shapes in one table: the user form's rows put the label
   ABOVE the field (one colspan="2" cell holding <label><span>Name</span><br>
   input</label>), while the hand-written Time Zone / Preferred Language /
   password rows are two columns with the label BESIDE the field — and their
   inputs are size="18" against the form's size="40". The result read as two
   different forms stapled together.

   Every row is stacked to the label-above shape, and every control gets one
   width. Done by dropping the table display roles: with any table box left in
   the chain the two-column rows keep a shared column axis, so the label cell
   would still size itself against every other first cell in the table. */
#content:has(table.padded) > h1,
#content:has(table.padded) > p {
  display: block;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
  max-width: var(--gp-w-form);
}
#content:has(table.padded) > h1 { margin-bottom: 10px; }
#content:has(table.padded) > p {
  max-width: min(var(--gp-w-form), var(--gp-measure-lede));
}

/* Profile lands on the form rung, not the page rung it used to occupy: its
   widest row is the time zone picker with Auto Detect beside it (see the
   .action-button rules further down), which needs about 34rem and therefore
   rounds up to 44. At the page rung this card was 1088px wrapping 416px
   fields — 670px of empty white, and the one surface that had escaped the
   scale entirely. */
/* Matched on the form that CONTAINS the padded table, not on any form that
   happens to share a page with one — the alerts specimen has both and was
   being given a form-rung width it has no business with. */
#content > form:has(table.padded) {
  width: 100%;
  max-width: var(--gp-w-form);
  margin: var(--gp-card-gap) auto 0;
  padding: var(--gp-card-pad);
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
}
/* Sign-up sits a rung lower, as the sign-in card's twin: it hides Auto Detect
   (below), so a short text input is the widest thing it has to hold. Keyed on
   the form action because profile.inc.php shares this markup. The head follows
   the card down, or the page would change measure halfway. */
#content > form[action="account.php"]:has(table.padded) {
  max-width: var(--gp-w-auth);
}
#content:has(form[action="account.php"]) > h1,
#content:has(form[action="account.php"]) > p {
  max-width: var(--gp-w-auth);
}

table.padded,
table.padded > tbody,
table.padded > tbody > tr {
  display: block;
  width: 100%;
  max-width: 100%;
}
table.padded > tbody > tr > td {
  display: block;
  width: auto !important;
  height: auto;
  padding: 0;
}
/* Rows carrying a field get the same rhythm as the user form's rows. */
table.padded > tbody > tr { padding-top: 14px; }
table.padded > tbody > tr:first-child { padding-top: 0; }

/* The label cell of a two-column row becomes the heading above its field,
   matched to the <span> the user form emits. :not([colspan]) keeps the section
   -break rows out of it — including the ones whose upstream `colspan=2"` typo
   still registers as an attribute. */
table.padded > tbody > tr > td:first-child:not([colspan]) {
  margin-bottom: 6px;
  font-weight: 500;
  font-size: 0.9375rem;
  color: var(--gp-ink);
}
/* One weight for every label in these forms, so a required field is marked by
   its asterisk rather than by being heavier than its neighbours. */
table.padded label > span:first-child,
table.padded label > span:first-child.required {
  display: inline-block;
  margin-bottom: 6px;
  font-weight: 500;
  font-size: 0.9375rem;
  color: var(--gp-ink);
}

/* One field width throughout — the passwords were half the length of the rest. */
table.padded input[type="text"],
table.padded input[type="password"],
table.padded input[type="email"],
table.padded input[type="url"],
table.padded select,
table.padded .select2-container {
  width: 100% !important;
  max-width: 26rem;
}
/* Phone + Ext share a line. Now that fields fill the card, the Ext box would
   otherwise be pushed onto its own row, so the label becomes a flex line with
   the caption on top and the two inputs beneath it. */
table.padded label:has(input[type="tel"]) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 8px;
}
table.padded label:has(input[type="tel"]) > span:first-child { flex-basis: 100%; }
table.padded label:has(input[type="tel"]) > br { display: none; }
table.padded input[type="tel"] {
  flex: 1 1 8rem;
  width: auto;
  max-width: 18rem;
  min-width: 0;
}
table.padded input[type="tel"] ~ input[type="text"] {
  flex: 0 0 5.5rem;
  width: 5.5rem !important;
  max-width: 5.5rem;
}

/* Time Zone: the picker matches the other fields, so Auto Detect fits beside it. */
table.padded > tbody > tr > td:has(> .select2-container) > .action-button {
  display: inline-flex;
  margin: 0 0 0 8px;
  vertical-align: middle;
}
/* ...but not on sign-up, where the location detection is gone entirely. The
   button comes from include/staff/templates/timezone.tmpl.php, which the
   profile page and the whole staff panel also include, so it cannot be removed
   at the source — it is dropped here for this one form. register.inc.php's
   jstz auto-detect script was deleted outright in the same change, so nothing
   on sign-up reads the visitor's location any more; the field is a plain
   manual picker. */
#content:has(table.padded) > form[action="account.php"] .action-button {
  display: none;
}
/* select2 draws a 28px-tall box with its own border, against 44px inputs either
   side of it. Matched to the fields so the picker is the same height and shape
   as everything else in the form. */
table.padded .select2-container--default .select2-selection--single {
  height: 44px;
  border: 1px solid rgba(27, 34, 48, 0.18);
  border-radius: var(--gp-r-sm);
  background: var(--gp-surface);
}
table.padded .select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 42px;
  padding-left: 13px;
  color: var(--gp-ink);
}
table.padded .select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 42px;
}

/* Section breaks. The user form emits <hr> + .form-header; the hand-written
   rows emit <div><hr><h3>. Given one spacing so they read as one sequence. */
table.padded h3 {
  font-size: 1.0625rem;
  font-weight: 500;
  margin: 0;
}
table.padded hr { margin: 22px 0 14px; }
/* The first section break lands at the very top of the card, where the card's
   own edge already separates things. Its rule was redundant and its margins are
   what made the top padding read deeper than the sides. */
table.padded > tbody > tr:first-child hr { display: none; }
table.padded .form-header { margin-bottom: 0 !important; }
table.padded .form-header > div:empty { display: none; }

/* Inline field errors sit after the control; empty ones must not reserve space. */
table.padded .error { font-size: 0.875rem; }
table.padded div.error:empty { display: none; }

/* The action row under the table. */
#content:has(table.padded) > form > hr { display: none; }
#content:has(table.padded) > form > p:last-child {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  align-items: center;
  margin: 24px 0 0;
}

/* The ticket-form variant of #ticketTable (upstream kept both). */
#ticketTable th.required,
#ticketTable td.required { font-weight: 600; text-align: left; }

/* =========================================================================
   11. Ticket list  (tickets.inc.php)
   ========================================================================= */

/* Inset: a single row of controls, not a block of content. */
.search.well {
  padding: var(--gp-inset-pad);
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
  margin: 0 0 var(--gp-card-gap);
}
#ticketSearchForm { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; float: none; padding: 0; }
#ticketSearchForm input[type="text"] { flex: 1 1 220px; min-width: 0; border-radius: var(--gp-r-pill); padding-left: 18px; }
#ticketSearchForm .pull-right {
  float: none;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.875rem;
  color: var(--gp-ink-2);
}
.search.well + h1 { margin-top: 0 !important; }

/* Page heading rows that carry a floated action cluster. */
#content > h1,
#ticketInfo h1 {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px 14px;
}
#content > h1 > .pull-right,
#ticketInfo h1 > .pull-right { float: none; margin-left: auto; }

.states small { font-size: 0.875rem; font-weight: 500; }
.states i { color: var(--gp-ink-3); margin-right: 2px; }
.state { color: var(--gp-ink-2); }
.active.state {
  font-weight: 600;
  color: var(--gp-brand-strong);
  text-decoration: underline;
  text-decoration-color: var(--gp-brand);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}
i.refresh { color: var(--gp-ink-3); font-size: 0.75em; vertical-align: middle; }
#content > h1 a:hover i.refresh { color: var(--gp-brand); }

/* --- The table ----------------------------------------------------------- */
/* Hairline rules only where they separate data — matches the flat list
   treatment gp.academy uses on its beige sections. */
#ticketTable {
  width: 100%;
  border: 0;
  border-top: 1px solid var(--gp-line);
  margin-top: 4px;
}
#ticketTable caption {
  padding: 0 0 10px;
  text-align: left;
  color: var(--gp-ink-3);
  background: none;
  border: 0;
  caption-side: top;
}
#ticketTable thead th {
  height: auto;
  line-height: 1.4;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--gp-line);
  padding: 11px 12px 11px 0;
  white-space: normal;
  vertical-align: bottom;
}
#ticketTable thead th a { color: var(--gp-ink-3); }
#ticketTable thead th a:hover { color: var(--gp-brand); text-decoration: none; }
#ticketTable thead th i { opacity: 0.5; font-size: 0.9em; }
#ticketTable thead th a:hover i { opacity: 1; }

#ticketTable td {
  padding: 13px 12px 13px 0;
  border: 0;
  border-bottom: 1px solid var(--gp-line-soft);
  vertical-align: middle;
}
#ticketTable tbody tr:hover td { background: var(--gp-brand-tint); }
#ticketTable tr.alt td { background: transparent; }

/* Column voices. The five columns are fixed in the template. */
#ticketTable tbody td:first-child a { font-weight: 500; letter-spacing: -0.01em; }
#ticketTable tbody td:nth-child(2) {
  font-family: var(--gp-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  color: var(--gp-ink-3);
  white-space: nowrap;
}
#ticketTable tbody td:nth-child(3) {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gp-ink-2);
}
#ticketTable tbody td:nth-child(4) { color: var(--gp-ink); }
#ticketTable tbody td:nth-child(4) .link { color: var(--gp-brand); }
/* tickets.inc.php pins the subject cell to an inline max-height:1.2em, which
   clips descenders at any line-height above 1.2. .truncate already keeps it
   to one line, so the cap is redundant — and it needs !important to beat the
   inline style. */
#ticketTable tbody td .truncate {
  max-height: none !important;
  line-height: 1.45;
}
#ticketTable tbody td:nth-child(5) { color: var(--gp-ink-3); font-size: 0.875rem; }
/* The "no records" row spans all five, so keep it plain. */
#ticketTable tbody td[colspan] {
  font: inherit;
  letter-spacing: normal;
  text-transform: none;
  color: var(--gp-ink-3);
  padding: 28px 0;
}

/* --- Source-type and file icons ------------------------------------------ */
.Icon {
  width: auto;
  padding-left: 0;
  background-image: none !important;
  color: var(--gp-brand);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.Icon::before {
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  font-size: 0.9em;
  line-height: 1;
  color: var(--gp-ink-3);
  flex: none;
  transform: translateY(var(--gp-icon-nudge));
}
.Icon.Ticket::before,
.Icon.webTicket::before   { content: "\f0ac"; }   /* globe     */
.Icon.emailTicket::before { content: "\f003"; }   /* envelope  */
.Icon.phoneTicket::before { content: "\f095"; }   /* phone     */
.Icon.otherTicket::before,
.Icon.apiTicket::before    { content: "\f013"; }  /* cog       */
.Icon.attachment::before,
.Icon.file::before         { content: "\f0c6"; }  /* paperclip */
.Icon.refresh::before      { content: "\f021"; }  /* refresh   */
.Icon.thread::before       { content: "\f0e5"; }  /* comment   */
.Icon.thread { font-weight: 600; font-size: 1em; }
.Icon:hover { text-decoration: underline; }
.Icon:hover::before { color: var(--gp-brand); }
.rtl .Icon { padding-left: 0; padding-right: 0; }

/* =========================================================================
   12. Ticket view  (view.inc.php)
   ========================================================================= */

#ticketInfo { width: 100%; }
#ticketInfo h1 {
  padding-bottom: 16px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--gp-line);
}
#ticketInfo h1 b { font-weight: 500; letter-spacing: -0.02em; }
#ticketInfo h1 small {
  font-weight: 400;
  font-size: 1rem;
  color: var(--gp-ink-3);
  letter-spacing: 0.02em;
}
#ticketInfo > tbody > tr > td { padding-right: 28px; }
#ticketInfo > tbody > tr > td:last-child { padding-right: 0; }

.infoTable,
table.custom-data {
  background: none;
  width: 100%;
  margin-top: 0;
}
table.custom-data { margin-top: 20px; }
.infoTable th,
table.custom-data th {
  text-align: left;
  padding: 7px 14px 7px 0;
  width: 34%;
  background: none;
  color: var(--gp-ink-3);
  font-weight: 400;
  font-size: 0.875rem;
  white-space: nowrap;
}
table.custom-data th { width: 30%; }
.infoTable td,
table.custom-data td { padding: 7px 0; color: var(--gp-ink); }
.infoTable tr + tr th,
.infoTable tr + tr td,
table.custom-data tr + tr th,
table.custom-data tr + tr td { border-top: 1px solid var(--gp-line-soft); }

table .headline,
table.custom-data .headline {
  border-bottom: 1px solid var(--gp-line);
  background: none;
  padding: 0 0 8px;
}
.infoTable thead .headline,
table.custom-data thead .headline,
table.custom-data tr:first-child .headline { border-top: 0; }

/* --- Thread --------------------------------------------------------------- */
/* Each entry is a white card on the cream page; the agent's replies carry
   a sage-tinted header so the two voices stay distinguishable without
   shouting. */
#ticketThread {
  z-index: 0;
  position: relative;
  border-bottom: 0;
}
#ticketThread::before { content: none; }

.thread-entry { margin-bottom: 18px; }
.thread-entry::before,
.thread-entry::after { content: none; }      /* old timeline masks */

.thread-entry.avatar { margin-left: var(--gp-gutter); }
.thread-entry.response.avatar { margin-right: var(--gp-gutter); margin-left: 0; }
.thread-entry > .avatar {
  margin-left: calc(-1 * var(--gp-gutter));
  display: inline-block;
  width: 40px;
  height: auto;
  border-radius: 50%;
  overflow: hidden;
}
.thread-entry.response > .avatar {
  margin-left: initial;
  margin-right: calc(-1 * var(--gp-gutter));
}
img.avatar { border-radius: inherit; }
.avatar > img.avatar { width: 100%; height: auto; }

.thread-entry .header {
  position: relative;
  padding: 11px 16px;
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r) var(--gp-r) 0 0;
  background: var(--gp-surface-2);
  font-size: 0.875rem;
  color: var(--gp-ink-2);
  line-height: 1.5;
}
.thread-entry .header b { color: var(--gp-ink); font-weight: 600; }
.thread-entry .header time { font-size: 0.8125rem; color: var(--gp-ink-3); }
/* Retire the CSS-triangle speech tails. */
.thread-entry.avatar .header::before,
.thread-entry.avatar .header::after,
.thread-entry.avatar.message .header::before,
.thread-entry.avatar.message .header::after,
.thread-entry.avatar.response .header::after { content: none; border: 0; }

.thread-entry.message .header { background: var(--gp-surface-2); }
.thread-entry.response .header {
  background: var(--gp-brand-tint);
  border-color: var(--gp-brand-edge);
}
.thread-entry.response .header b { color: var(--gp-brand-strong); }
.thread-entry .header .title {
  max-width: 500px;
  vertical-align: bottom;
  display: inline-block;
  margin-left: 12px;
  font-size: 0.8125rem;
}
.rtl .thread-entry .header .title { margin-left: 0; margin-right: 12px; }

/* css/thread.css loads after this file and pins font-size with !important. */
#content .thread-entry .thread-body,
#content .faq-content .thread-body,
#content #landing_page .thread-body {
  font-size: 1rem !important;
  line-height: 1.62;
  color: var(--gp-ink);
  font-family: var(--gp-sans);
}
#content .thread-body a:not(.button) {
  color: var(--gp-brand) !important;
  text-decoration: underline;
  text-decoration-color: var(--gp-brand-edge);
  text-underline-offset: 0.18em;
}
#content .thread-body a:not(.button):hover {
  color: var(--gp-brand-strong) !important;
  text-decoration-color: currentColor;
}
/* Inset: nested inside a thread entry, under its header. */
.thread-entry .thread-body {
  padding: var(--gp-inset-pad);
  border: 1px solid var(--gp-line);
  border-top: none;
  border-radius: 0 0 var(--gp-r) var(--gp-r);
  background: var(--gp-surface);
}
.thread-entry.response .thread-body { border-color: var(--gp-brand-edge); }

/* Attachment strip pinned to the bottom of the card interior. */
.thread-body .attachments {
  background: var(--gp-page);
  margin: 16px -18px -16px;
  position: static;
  top: 0;
  padding: 10px 18px;
  border-top: 1px solid var(--gp-line);
  border-radius: 0 0 var(--gp-r) var(--gp-r);
  font-size: 0.875rem;
}
.thread-body .attachments .filesize { margin-left: 0.6em; font-size: 0.75rem; }
.thread-body .attachments i { color: var(--gp-ink-3); margin-right: 4px; }
.thread-body .attachments a,
.thread-body .attachments a:hover { text-decoration: none; }
.thread-body .attachments a:hover { text-decoration: underline; }
.thread-body .attachment-info {
  margin-right: 10px;
  display: inline-block;
  width: 48%;
  padding: 2px 0;
}
.thread-body .attachment-info .filename { max-width: calc(100% - 80px); }

/* --- Thread events --------------------------------------------------------- */
/* Hidden from the client view. include/client/templates/thread-entries.tmpl.php
   whitelists six event types for clients — created, closed, reopened, edited,
   collab, merged — so assignment, priority and department changes never reached
   the client anyway. What did reach them was internal bookkeeping: "Created by
   <agent>" on every ticket, plus "Edited by <agent>" whenever staff touched the
   ticket, and collaborator/merge notices. None of that is the requester's
   business, and it sat directly under their own message.

   Done in CSS, so no PHP or logic changed: the events are still rendered and
   still counted by the template's own "no entries have been posted" guard, and
   nothing in js/ references .thread-event or .type-icon. The client print view
   (templates/ticket-print.tmpl.php) renders only M and R entries, so it never
   showed events to begin with.

   To bring them back, delete the single display:none rule at the end of this
   section; the styling in between is left intact. */
.thread-event {
  padding: 0 0 18px;
  margin-left: var(--gp-gutter);
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.875rem;
}
.rtl .thread-event { margin-left: 0; margin-right: var(--gp-gutter); }
.type-icon {
  border-radius: 50%;
  background: var(--gp-surface-2);
  border: 1px solid var(--gp-line);
  width: 26px;
  height: 26px;
  padding: 0;
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  flex: none;
  vertical-align: middle;
}
.type-icon i { color: var(--gp-ink-3); }
.type-icon.dark { border-color: var(--gp-ink-2); background: var(--gp-ink-2); }
.type-icon.dark i { color: #fff; }
.type-icon::after { content: none; }         /* old timeline mask */
.thread-event img.avatar {
  vertical-align: middle;
  border-radius: 4px;
  width: auto;
  max-height: 22px;
  margin: -2px 3px 0;
}
.thread-event .description {
  margin-left: 0;
  padding: 0;
  display: block;
  width: auto;
  line-height: 1.5;
  color: var(--gp-ink-2);
}

/* The rule that hides them — see the note at the top of this section. Placed
   last so it wins on order rather than on specificity, and so it holds for any
   thread the client portal renders, whatever html-id it is given. */
.thread-event { display: none; }

/* --- Reply form -------------------------------------------------------------- */
#reply {
  margin-top: var(--gp-card-gap);
  padding: var(--gp-card-pad);
  background: var(--gp-surface-2);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
}
#reply h2 {
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--gp-line);
}
#reply > table { width: auto; max-width: 100%; }
#reply table td { vertical-align: top; }
#reply textarea { width: 100% !important; }
#reply input[type="text"],
#reply #response_options textarea {
  border: 1px solid rgba(27, 34, 48, 0.18);
  background: var(--gp-surface);
}
#reply > div > p:first-child { margin-top: 0; }
#reply em { color: var(--gp-ink-2); }
#reply .attachments .uploads div { display: inline-block; padding-right: 20px; }
#reply .file {
  display: inline-block;
  padding-left: 20px;
  margin-right: 20px;
  background: url('../images/icons/file.gif') 0 50% no-repeat;
}
#reply .warning-banner { margin-top: 14px; }

/* =========================================================================
   13. Sign in / access link  (login.inc.php, accesslink.inc.php, pwreset)
   ========================================================================= */

/* Focused single column. Both templates that use #clientLogin — login.inc.php
   (.login-row/.login-aside) and accesslink.inc.php (an inline display:table-row
   with .login-box/.instructions) — become one narrow centred card with the form
   on top and the secondary routes stacked beneath a hairline. The old
   side-by-side split gave the weaker column equal visual weight and doubled the
   page's width for no gain. */
#content:has(#clientLogin) > .hero-eyebrow,
#content:has(#clientLogin) > h1,
#content:has(#clientLogin) > p {
  /* display:block undoes the flex heading rule used by the ticket pages;
     a flex container ignores text-align for its items. */
  display: block;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
  /* Head shares the card's column. On this rung the column is already
     narrower than a reading measure, so it needs no separate cap. */
  max-width: var(--gp-w-auth);
}
#content:has(#clientLogin) > .hero-eyebrow { margin-bottom: 12px; }
#content:has(#clientLogin) > h1 { margin-bottom: 10px; }

#clientLogin {
  display: block;
  width: 100%;
  /* Auth rung: every field here is a single short input. */
  max-width: var(--gp-w-auth);
  margin: var(--gp-card-gap) auto 0;
  padding: 0;
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
  box-shadow: none;
  overflow: hidden;
}
.rtl #clientLogin { background-position: 5% 50%; }

/* The row wrappers stack. accesslink sets display:table-row inline. */
.login-row,
#clientLogin > div[style] {
  display: block !important;
  gap: 0;
}

/* #clientLogin carries no padding of its own — these two stacked sections are
   the card's inside, so they take the card padding. Both must use the same
   value or their contents would not line up down the card's edge. */
.login-box {
  display: block;
  width: auto;
  flex: none;
  box-shadow: none;
  padding: var(--gp-card-pad);
  background: none;
  border: 0;
  border-radius: 0;
  vertical-align: top;
}
.rtl .login-box { box-shadow: none; }
.login-box > div { margin-bottom: 14px; }
.login-box > div:last-of-type { margin-bottom: 0; }
.login-box label { display: block; font-weight: 500; font-size: 0.875rem; }
.login-box label input { margin-top: 6px; }
/* Submit fills the card; the password link sits centred beneath it. */
.login-box p {
  margin: 20px 0 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}
#clientLogin input[type="submit"],
#clientLogin .btn { width: 100%; padding: 11px 22px; }
.pwreset-link { display: block; text-align: center; font-size: 0.875rem; }

/* Secondary routes: external auth, then the register prompt. */
/* This section is a band across the card, so its tint spans the full width
   while its CONTENTS stay in the same centred column as the fields above. */
/* .login-aside stacks block children (provider buttons, a rule, the register
   prompt), so it is a centred flex column. .instructions is a run of prose with
   inline links — as a flex column each <a> would become its own line, which is
   exactly what it did — so it stays a block. */
.login-aside {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.login-aside,
#clientLogin .instructions {
  display: block;
  width: auto;
  flex: none;
  padding: var(--gp-card-pad);
  border-top: 1px solid var(--gp-line-soft);
  background: var(--gp-page);
  color: var(--gp-ink-2);
  font-size: 0.9375rem;
  text-align: center;
  vertical-align: top;
}
.rtl #clientLogin .instructions { padding: var(--gp-card-pad); }
.login-aside {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.login-aside > * { width: 100%; }
.login-aside hr {
  width: 100% !important;
  margin: 16px 0;
  border-top-color: var(--gp-line);
}
.register-prompt { margin: 0; }

/* Full-width provider button so it reads as a peer of Sign In, not an afterthought. */
.login-aside .external-auth { display: block; }
.login-aside .external-auth + .external-auth { margin-top: 8px; }
.login-aside a.external-sign-in { display: block; }
.login-aside .external-auth-box { display: flex; width: 100%; }
.login-aside .external-auth-name { flex: 1; justify-content: center; min-width: 0; }

#clientLogin p { clear: both; }
#clientLogin strong {
  display: block;
  margin-bottom: 12px;
  padding: 9px 12px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--gp-err);
  background: var(--gp-err-bg);
  border: 1px solid var(--gp-err-edge);
  border-radius: var(--gp-r-sm);
  text-align: left;
}
#clientLogin strong:empty { display: none; }
#clientLogin #username,
#clientLogin #passwd,
#clientLogin #email,
#clientLogin #ticketno { width: 100%; margin-right: 0; }
#clientLogin input[type="text"],
#clientLogin input[type="password"] { margin-bottom: 0; }
#clientLogin hr { margin: 16px 0; border-top-color: var(--gp-line); }

/* The trailing "first time contacting us" line stays a quiet centred row. */
#content:has(#clientLogin) > p:last-of-type {
  text-align: center;
  max-width: var(--gp-w-auth);
  margin: 20px auto 0;
  font-size: 0.9375rem;
}
/* Staff route: its own card, same width and shape as the client card above it,
   so the two audiences read as two parallel doors rather than a form with an
   afterthought stuck to the bottom. */
.agent-signin {
  width: 100%;
  max-width: var(--gp-w-auth);
  /* Tighter than --gp-card-gap on purpose: this card is a continuation of the
     one above it, and the shorter gap groups the pair. */
  margin: 16px auto 0;
  padding: var(--gp-card-pad);
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-r);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
.agent-signin-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gp-ink-3);
}
/* A navy ghost pill, matching the footer's Staff Sign In: quiet enough not to
   compete with the client card, but still unmistakably a control — agents land
   on this page more than any other. */
.agent-signin-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  padding: 7px 16px;
  background: transparent;
  border: 1px solid var(--gp-navy);
  border-radius: var(--gp-r-pill);
  color: var(--gp-navy) !important;
  font-weight: 500;
  transition: background-color var(--gp-t-color), color var(--gp-t-color);
}
.agent-signin-link::after { content: "\2192"; font-size: 0.9em; }   /* → */
.agent-signin-link:hover {
  background: var(--gp-navy);
  color: #fff !important;
  text-decoration: none;
}
.agent-signin-link:active { transform: scale(0.98); }

.external-auth + .external-auth { margin-top: 8px; }
a.external-sign-in { text-decoration: none; }
a.external-sign-in:hover { text-decoration: none; }
.external-auth-box {
  display: inline-flex;
  align-items: stretch;
  vertical-align: middle;
  border-radius: var(--gp-r-pill);
  border: 1px solid rgba(27, 34, 48, 0.25);
  background: var(--gp-surface);
  overflow: hidden;
  transition: border-color var(--gp-t-color);
}
a.external-sign-in:hover .external-auth-box { border-color: var(--gp-ink); }
.external-auth-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--gp-ink-2);
  width: 42px;
  padding: 0;
  border-right: 1px solid var(--gp-line);
  background: var(--gp-page);
}
.external-auth-name {
  display: inline-flex;
  align-items: center;
  color: var(--gp-ink);
  width: auto;
  min-width: 110px;
  padding: 9px 16px;
  line-height: 1.3;
  font-size: 0.9375rem;
  font-weight: 500;
}
img.sign-in-image {
  border: none;
  max-height: 40px;
  max-width: 200px;
  width: auto;
  height: auto;
}

/* =========================================================================
   14. Odds and ends
   ========================================================================= */

/* Print / Edit chips on the ticket view. */
.action-button {
  border-radius: var(--gp-r-pill);
  -webkit-background-clip: padding-box;
  background-clip: padding-box;
  color: var(--gp-ink-2) !important;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--gp-line);
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 500;
  overflow: hidden;
  background: var(--gp-surface);
  background-image: none;
  padding: 7px 14px;
  text-decoration: none;
  line-height: 1.3;
  margin-left: 6px;
  transition: background-color var(--gp-t-color), border-color var(--gp-t-color);
}
.action-button:hover {
  background: var(--gp-brand-tint);
  border-color: var(--gp-brand-edge);
  color: var(--gp-brand-strong) !important;
  text-decoration: none;
}
.action-button i { color: var(--gp-ink-3); }
.action-button:hover i { color: var(--gp-brand); }
.action-button span,
.action-button a { color: var(--gp-ink-2) !important; display: inline-block; float: none; }
.action-button a { text-decoration: none; }
.image-hover a.action-button:hover,
.image-hover a.action-button { color: initial !important; text-decoration: none; }

.label {
  font-size: 0.6875rem;
  padding: 2px 8px;
  border-radius: var(--gp-r-pill);
  font-weight: 600;
  letter-spacing: 0.03em;
  line-height: 1.5;
  color: #fff;
  vertical-align: baseline;
  white-space: nowrap;
  text-shadow: none;
  background: var(--gp-ink-3);
  display: inline-block;
}
/* The one place gold appears: quiet metadata chips ("Edited"). */
.label-bare {
  background: var(--gp-gold-soft);
  border: 1px solid transparent;
  color: #6d5526;
  text-shadow: none;
}

/* Pagination: the client templates emit bare <a><b>n</b></a>, so there is
   no hook for a proper pager without a markup change. Kept for the
   #pagination markup other surfaces use. */
#pagination { border: 0; margin: 0 0 32px; padding: 0; }
#pagination li { border: 0; margin: 0; padding: 0; font-size: 0.75rem; list-style: none; display: inline; }
#pagination li a { margin-right: 2px; display: block; float: left; padding: 5px 10px; border-radius: var(--gp-r-pill); text-decoration: none; }
#pagination li a:hover { color: var(--gp-brand-strong); background: var(--gp-brand-tint); }
#pagination .previousOff, #pagination .nextOff { color: var(--gp-ink-3); display: block; float: left; font-weight: 600; padding: 5px 8px; }
#pagination .next a, #pagination .previous a { font-weight: 600; }
#pagination .active { color: var(--gp-ink); font-weight: 600; margin-right: 2px; display: block; float: left; padding: 5px 10px; text-decoration: none; }

/* Inline Font Awesome <i> elements set beside text get the same optical
   correction as the ::before glyphs above. Grouped here so the nudge lives in
   one place; .type-icon is excluded because it centres a glyph inside its own
   round chip, where the box centre is the right reference. */
.states i,
.popular-faq i,
.featured-category i,
.action-button i,
.thread-body .attachments i,
#msg_info .icon-2x,
i.refresh {
  position: relative;
  top: var(--gp-icon-nudge);
}

/* =========================================================================
   15. Responsive
   -------------------------------------------------------------------------
   The templates carry width="800"/width="320" table attributes, but
   presentational attributes lose to author CSS — which is what makes a
   fluid layout reachable without markup changes.
   ========================================================================= */

@media (max-width: 1000px) {
  .main-content { margin-right: 0; }
  .sidebar { float: none !important; width: auto; margin-left: 0; }
  .front-page-button { grid-template-columns: 1fr 1fr; }
}

/* --- Nav collapses to a menu ------------------------------------------- */
/* Above this width the bar holds the nav inline; below it, the nav becomes a
   panel that drops out of the bar and the toggle appears.
   
   1150px is measured, not guessed: it is the narrowest viewport where the
   widest bar the templates can emit — logo, four nav pills, and the signed-in
   account cluster — still fits on one row. Below it the row wrapped, which
   left an awkward two-line bar. One breakpoint for both auth states means the
   nav never changes mode just because someone signed in, and there is never
   an in-between state with the inline nav and the toggle both visible. */
@media (max-width: 1150px) {
  .site-bar,
  .agent-bar {
    border-radius: 26px;
    padding: 8px 10px 8px 16px;
    gap: 6px 12px;
  }
  /* Centring is a desktop concern; in the collapsed bar a max-content floor
     would force the account cluster wider than the viewport. */
  #header #logo,
  #header .pull-right { flex: 0 1 auto; min-width: 0; }
  #header .pull-right { margin-left: auto; }
  .nav-toggle-btn { display: inline-flex; }

  #nav {
    order: 5;
    flex-basis: 100%;
    width: 100%;
    display: none;
    flex-direction: column;
    gap: 2px;
    margin: 4px 0 2px;
    padding-top: 8px;
    border-top: 1px solid var(--gp-line);
  }
  #nav-toggle:checked ~ #nav { display: flex; }
  #nav li { width: 100%; }
  #nav li a {
    width: 100%;
    justify-content: flex-start;
    min-height: 46px;
    padding: 11px 14px;
    border-radius: var(--gp-r-sm);
  }
  #nav li a::before { width: 1.1em; text-align: center; }
}

/* Below this width the account cluster is too wide for the bar, so it joins
   the menu panel underneath the nav instead of crowding the logo. */
@media (max-width: 700px) {
  /* With the account cluster out of the bar, the toggle takes over as the
     right-hand anchor — otherwise it sits flush against the logo. */
  .nav-toggle-btn { margin-left: auto; }

  /* The agent strip stacks: label and name on one line, the action a full
     row beneath, matching the full-width controls the menu panel uses. */
  .agent-bar { padding: 12px 16px; row-gap: 11px; }
  .agent-bar-link {
    margin-left: 0;
    width: 100%;
    min-height: 44px;
    justify-content: center;
  }

  #header .pull-right {
    display: none;
    order: 6;
    flex-basis: 100%;
    width: 100%;
    margin: 0;
    padding-top: 10px;
    border-top: 1px solid var(--gp-line);
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  #nav-toggle:checked ~ #header .pull-right { display: flex; }
  #nav-toggle:checked ~ #nav { border-top: 0; padding-top: 4px; }
  #header .pull-right > p { width: 100%; }
  /* Match the full-width nav rows above it. */
  .signin-button { width: 100%; justify-content: center; }
  #header .pull-right > p:has(a):not(:has(.signin-button)) {
    justify-content: center;
    flex-wrap: wrap;
  }
}

@media (max-width: 780px) {
  :root { --gp-pad: 18px; --gp-gutter: 44px; }

  .span4, .span8 { display: block; width: auto; margin: 0; }
  .span4 { margin-top: 28px; }
  .featured-category { width: auto; display: block; padding-right: 0; }

  #ticketInfo > tbody > tr > td {
    display: block;
    width: auto !important;
    padding: 0 0 20px;
  }
  #ticketInfo h1 { display: block; }
  #ticketInfo h1 > .pull-right { display: block; margin: 12px 0 0; }
  .action-button { margin: 0 6px 0 0; }

  .thread-body .attachment-info { width: 100%; margin-right: 0; }
  .freetext-files .file { width: 100%; }

  .footer-inner { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 640px) {
  h1 { font-size: 1.65rem; }
  #content { padding: 22px 0 36px; }

  /* Header */
  #header #logo img { max-height: 34px; max-width: 190px; }
  #header .pull-right,
  #header p { text-align: left; }

  /* Stacked label/value form tables. The rows become plain blocks: with any
     table box left in the chain, an <input size="40">'s intrinsic width
     (~330px) sets the table's min-content and overflows a small phone —
     percentage caps can't shrink a table's min-content, blocks can. */
  #ticketForm > table,
  #ticketForm > table > tbody,
  #ticketForm > table > tbody > tr,
  table.padded,
  table.padded tbody,
  table.padded tr { display: block; width: 100%; table-layout: auto; }
  #ticketForm input[type="text"],
  #ticketForm input[type="password"],
  #ticketForm select { max-width: 100%; }
  #ticketForm > table > tbody > tr > td,
  table.padded tr > td,
  table.padded tr > th {
    display: block;
    width: auto;
    padding: 2px 0;
  }
  #ticketForm > table > tbody > tr > td:first-child:not([colspan]) {
    padding-top: 10px;
    color: var(--gp-ink-3);
    font-size: 0.875rem;
  }
  #ticketForm div textarea,
  #ticketForm td textarea { max-width: none; }

  /* Sign-in panels: login.inc.php uses .login-row (flex, wraps on its own);
     accesslink.inc.php still sets display:table-row/-cell inline. */
  #clientLogin > div > div[style] { display: block !important; }
  #clientLogin > div[style] { display: block !important; }
  .login-box,
  #clientLogin .instructions { display: block; width: auto; }
  .login-box { flex-basis: auto; }
  #clientLogin .instructions { padding: 18px 2px !important; }

  /* Ticket list: five columns will not fit, so let cells wrap and shrink
     rather than hiding a column or forcing a horizontal scroll. */
  /* Auto layout, and drop the template's width="120"/width="320" hints. The
     first three columns hold short atomic values, so pin them to nowrap and
     let auto layout hand the remaining width to subject and department —
     which are the two that can usefully wrap. */
  #ticketTable { font-size: 0.8125rem; table-layout: auto; }
  #ticketTable thead th,
  #ticketTable td { padding: 10px 6px 10px 0; width: auto !important; }
  #ticketTable thead th {
    font-size: 0.625rem;
    letter-spacing: 0.06em;
    white-space: normal !important;
  }
  #ticketTable tbody td:nth-child(1),
  #ticketTable tbody td:nth-child(2),
  #ticketTable tbody td:nth-child(3) { white-space: nowrap; }
  #ticketTable tbody td:nth-child(2) { font-size: 0.6875rem; }
  #ticketTable tbody td:nth-child(4),
  #ticketTable tbody td:nth-child(5) { white-space: normal; overflow-wrap: break-word; }
  /* The subject/department cells hold .truncate divs whose nowrap (plus the
     template's inline max-width:320px) sets the column's min-content to the
     full one-line width — let them wrap here instead. */
  #ticketTable tbody td:nth-child(4) .link,
  #ticketTable tbody td:nth-child(4) .truncate,
  #ticketTable tbody td:nth-child(5) .truncate {
    white-space: normal;
    max-width: none !important;
    display: block;
  }

  /* Search / filter rows go full width */
  #ticketSearchForm .pull-right { margin-left: 0; width: 100%; }
  #ticketSearchForm .pull-right select { flex: 1 1 auto; min-width: 0; }

  /* select2 is initialised with an inline width:350px in class.forms.php */
  .select2-container { width: 100% !important; max-width: 100% !important; }

  #reply { padding: 16px; }
  /* Cards give back some padding at phone widths so the fields keep their room. */
  #ticketForm:has(> table) { padding: 18px 16px 20px; }
  .login-box { padding: 20px 18px; }
  .login-aside,
  #clientLogin .instructions { padding: 18px 18px 20px; }
  .agent-signin { padding: 18px 18px; }
  .thread-entry .header .title { display: none; }   /* duplicates the subject */

  /* CAPTCHA image, field, and hint will not sit on one line at this width. */
  tr.captchaRow td em,
  #ticketForm div .captcha + * { display: block; }
  tr.captchaRow td em { margin-top: 8px; }
  #ticketForm td .captcha { margin-bottom: 8px; }
}

@media (max-width: 420px) {
  .front-page-button { grid-template-columns: 1fr; }
  /* Five columns at 320px: the date wraps, the source-type glyph goes, and
     the whole table steps down a size — the alternative is a horizontal
     scroll, which is worse than a smaller-but-complete row. */
  #ticketTable { font-size: 0.75rem; }
  #ticketTable tbody td:nth-child(2) {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  #ticketTable .Icon { gap: 0; }
  #ticketTable .Icon::before { display: none; }
  #ticketTable thead th,
  #ticketTable td { padding-right: 5px; }
  #ticketTable thead th { letter-spacing: 0.03em; }
  #ticketTable tbody td:nth-child(3) { letter-spacing: 0.04em; font-size: 0.6875rem; }
  /* In the dropped-down menu the glyphs are a useful column, so they stay —
     it is the bar itself that has to shed width at 320px. */
  .site-bar { padding: 8px 8px 8px 12px; gap: 6px 8px; }
  #header #logo img { max-height: 30px; max-width: 150px; }
  .thread-entry.avatar,
  .thread-entry.response.avatar { margin-left: 0; margin-right: 0; }
  .thread-entry > .avatar,
  .thread-entry.response > .avatar { display: none; }
  .thread-event { margin-left: 0; }
  .thread-event, .rtl .thread-event { margin-right: 0; }
  .agent-signin { border-radius: var(--gp-r-sm); }
}

/* Honour a reduced-motion preference. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
