/* ============================================================================
   gebiz.ai shared stylesheet
   ----------------------------------------------------------------------------
   There is no build step here. Every page still carries its own inline <style>
   block, and this file is linked IMMEDIATELY BEFORE that block on every page.

   That ordering is the whole migration strategy: at equal specificity the
   later rule wins, so every pre-existing inline rule keeps overriding the
   shared one and nothing regresses on the day this file lands. Page-specific
   CSS is then deleted incrementally, and each deletion reveals the shared
   rule underneath.

   Two consequences to remember when editing:
     - Adding a rule here does NOT change a page that already declares the
       same selector. To adopt a shared rule, delete the page's version.
     - Never reach for !important to force adoption. Delete the inline rule.

   No @import (serialises requests). No @layer (complicates the override
   story above). Plain custom properties only.
   ========================================================================= */


/* ---------------------------------------------------------------- fonts --
   Self-hosted. We deliberately do NOT link fonts.googleapis.com: cookies.html
   section 3 promises users there are no third-party trackers, and a Google
   Fonts request would leak every visitor's IP to Google. Self-hosting is a
   compliance requirement here, not a preference.

   Latin subsets only. All site copy is ASCII plus curly quotes and "S$".
   Anything outside the range falls back to the system stack, which is fine.
   ------------------------------------------------------------------------ */

@font-face {
  font-family: "Source Sans 3";
  src: url(/fonts/source-sans-3-latin-vf.woff2) format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Source Serif 4";
  src: url(/fonts/source-serif-4-latin-600.woff2) format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Metric-matched fallbacks. font-display:swap paints the system face first and
   swaps in the webfont a moment later; without these overrides that swap
   reflows the page.

   size-adjust is MEASURED, not guessed: it is the ratio of the webfont's
   advance width to the fallback's over a sample of real page copy
   (Source Sans 3 / Helvetica Neue = 92.2%, Source Serif 4 / Georgia = 93.8%).
   The ascent/descent pairs are then scaled so the resulting line box matches
   the webfont's measured normal line height (1.42em sans, 1.38em serif).

   Re-run `node tools/measure-font-metrics.js` if either font is replaced. */
@font-face {
  font-family: "SS3 Fallback";
  src: local("Helvetica Neue"), local("Arial");
  size-adjust: 92.2%;
  ascent-override: 111%;
  descent-override: 43%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "SS4 Fallback";
  src: local("Georgia"), local("Times New Roman");
  size-adjust: 93.8%;
  ascent-override: 110%;
  descent-override: 37%;
  line-gap-override: 0%;
}


/* --------------------------------------------------------------- tokens -- */

:root {
  /* -- Colour. ONE accent, locked site-wide. The dashboard's second blue
        (#1a56db, 49 occurrences against the brand's 10) is a defect, not a
        palette. Do not add a second accent. ------------------------------ */
  --brand-800: #003d6b;
  --brand-700: #00507f;
  --brand-600: #0061a4;   /* THE accent */
  --brand-500: #1a7cc4;
  --brand-100: #dceaf6;
  --brand-050: #f1f7fb;

  --ink-900: #0f1b2a;     /* headings */
  --ink-700: #33465c;     /* body */
  --ink-500: #64748b;     /* muted */
  --ink-400: #94a3b8;     /* placeholder */

  --line: #e2e8f0;
  --line-strong: #cbd5e1;

  --surface: #ffffff;
  --surface-sunken: #f6f8fb;

  --pos-600: #15803d;  --pos-050: #f0fdf4;
  --warn-600: #a16207; --warn-050: #fffbeb;
  --neg-600: #b91c1c;  --neg-050: #fef2f2;

  /* -- Type. 11 steps, replacing the 44 distinct rem values previously in
        use (ten of which sat between 0.70rem and 0.90rem in 0.02rem steps).

        SCALE RULE, so nobody reintroduces 0.79rem:
          above 16px  -> 1.25 major third, rounded to whole pixels
                         (16 -> 21 -> 26 -> 32 -> 42)
          16px and below -> quantised to whole pixels (11/12/13/14), because
                         sub-16px type landing on fractional pixels renders
                         soft.
     ------------------------------------------------------------------ */
  --font-sans: "Source Sans 3", "SS3 Fallback", system-ui, -apple-system,
    BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-serif: "Source Serif 4", "SS4 Fallback", Georgia, serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --t-11: 0.6875rem;
  --t-12: 0.75rem;
  --t-13: 0.8125rem;
  --t-14: 0.875rem;
  --t-16: 1rem;
  --t-18: 1.125rem;
  --t-21: 1.3125rem;
  --t-26: 1.625rem;
  --t-32: 2rem;
  --t-42: 2.625rem;
  --t-display: clamp(2.375rem, 4.2vw, 3.25rem);

  --lh-tight: 1.12;
  --lh-snug: 1.3;
  --lh-normal: 1.5;
  --lh-relaxed: 1.65;

  --w-body: 400;
  --w-med: 500;
  --w-semi: 600;
  --w-bold: 700;

  /* -- Space. 4px base. Replaces 60+ ad-hoc padding pairs including 7/9/11/13px. */
  --s-1: 4px;   --s-2: 8px;   --s-3: 12px;  --s-4: 16px;
  --s-5: 20px;  --s-6: 24px;  --s-8: 32px;  --s-10: 40px;
  --s-12: 48px; --s-16: 64px; --s-20: 80px; --s-24: 96px;

  --section-y: clamp(56px, 7vw, 96px);
  --gutter: clamp(20px, 5vw, 64px);
  --measure: 68ch;

  /* -- Radius. 4 values, replacing 12. Pills and avatars use --r-full,
        always. Nothing else is ever round. ------------------------------ */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-full: 999px;

  /* -- Depth. Two-layer (contact + wide soft); a single hard shadow is what
        reads as dated. ------------------------------------------------- */
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .04), 0 1px 3px rgba(15, 23, 42, .06);
  --shadow-md: 0 2px 4px rgba(15, 23, 42, .03), 0 6px 16px rgba(15, 23, 42, .06);
  --shadow-lg: 0 4px 8px rgba(15, 23, 42, .04), 0 16px 40px rgba(15, 23, 42, .09);
  --shadow-brand: 0 2px 4px rgba(0, 97, 164, .12), 0 8px 24px rgba(0, 97, 164, .18);
  --ring: 0 0 0 3px rgba(0, 97, 164, .28);

  /* -- Z. 6 slots, replacing the 20/50/100/200/201/1000 mix. */
  --z-sticky: 100;
  --z-dropdown: 200;
  --z-overlay: 900;
  --z-modal: 1000;
  --z-toast: 1100;

  /* -- Legacy aliases. ~600 existing var(--sg)/var(--border) references
        across the inline blocks keep resolving through these. Pages that
        redeclare them in their own :root still win (later source order),
        which is intended: this is a safety net, not an override. -------- */
  --sg: var(--brand-600);
  --sg2: var(--brand-800);
  --text: #1e293b;
  --muted: var(--ink-500);
  --bg: var(--surface-sunken);
  --card: var(--surface);
  --border: var(--line);
  --green: var(--pos-600);
  --red: #dc2626;
}


/* ---------------------------------------------------------------- reset -- */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--t-16);
  font-weight: var(--w-body);
  line-height: var(--lh-normal);
  color: var(--ink-700);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, svg, video { max-width: 100%; }
img { height: auto; }

/* font-family only, not the `font` shorthand: `font: inherit` would also
   reset every control's font-size to the body's 16px, silently resizing
   buttons and inputs that currently rely on the browser default. Pages that
   care already set their own size; all we need here is the new typeface. */
button, input, select, textarea { font-family: inherit; color: inherit; }

/* Negative tracking on headings is the single highest-leverage typographic
   fix; system-default tracking at display sizes reads loose and amateur.

   Deliberately NO `color` here. An explicit colour on h1-h4 beats inheritance
   regardless of specificity, so setting it would black out every heading that
   currently inherits white from a dark parent (the CTA band, the dashboard
   sidebar) and brown from the disclaimer. Headings inherit their colour. */
h1, h2, h3, h4 { font-weight: var(--w-bold); }
h1 { letter-spacing: -.03em;  line-height: var(--lh-tight); }
h2 { letter-spacing: -.022em; line-height: var(--lh-tight); }
h3 { letter-spacing: -.012em; line-height: var(--lh-snug); }

/* Every dollar amount, tender count and date on this site sits in a column
   that needs to line up. */
th, td, .num, .tabular { font-variant-numeric: tabular-nums; }


/* ------------------------------------------------------------- a11y --- */

:focus-visible {
  outline: 2px solid var(--brand-600);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Only suppress the ring for pointer users who did not tab here. */
:focus:not(:focus-visible) { outline: none; }

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

.skip-link {
  position: absolute; left: var(--s-2); top: -3rem;
  background: var(--surface); color: var(--brand-600);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-sm);
  box-shadow: var(--shadow-md); z-index: var(--z-toast);
  transition: top .12s ease;
}
.skip-link:focus { top: var(--s-2); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}


/* ----------------------------------------------------------- primitives --
   Nothing on the site uses these yet. They are the adoption target for the
   6 card treatments, 18 near-duplicate pills, 6 copy-pasted tab components
   and 7 ad-hoc button classes currently in the codebase. Class names use --
   modifiers so none of them can collide with the ~190 existing names.
   ------------------------------------------------------------------------ */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  padding: 9px var(--s-5);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-size: var(--t-14);
  font-weight: var(--w-semi);
  letter-spacing: -.006em;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  background: none;
  transition: background .16s ease, border-color .16s ease,
              color .16s ease, box-shadow .16s ease;
}
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.btn--primary   { background: var(--brand-600); border-color: var(--brand-600); color: #fff; box-shadow: var(--shadow-sm); }
.btn--primary:hover:not(:disabled)   { background: var(--brand-700); border-color: var(--brand-700); }
.btn--secondary { border-color: var(--brand-600); color: var(--brand-600); background: var(--surface); }
.btn--secondary:hover:not(:disabled) { background: var(--brand-050); }
.btn--ghost     { color: var(--ink-500); }
.btn--ghost:hover:not(:disabled)     { background: var(--surface-sunken); color: var(--ink-700); }
.btn--danger    { background: var(--neg-600); border-color: var(--neg-600); color: #fff; }

.btn--sm    { padding: 5px var(--s-3); font-size: var(--t-13); }
.btn--lg    { padding: 13px var(--s-8); font-size: var(--t-16); border-radius: var(--r-md); }
.btn--block { display: flex; width: 100%; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-6);
  box-shadow: var(--shadow-sm);
}
.card--flush  { padding: 0; overflow: hidden; }
.card--sunken { background: var(--surface-sunken); box-shadow: none; }

.pill {
  display: inline-flex; align-items: center; gap: var(--s-1);
  padding: var(--s-1) var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--ink-500);
  font-size: var(--t-13);
  font-weight: var(--w-med);
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.pill--on   { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.pill--pos  { background: var(--pos-050);  border-color: transparent; color: var(--pos-600); }
.pill--warn { background: var(--warn-050); border-color: transparent; color: var(--warn-600); }
.pill--neg  { background: var(--neg-050);  border-color: transparent; color: var(--neg-600); }
.pill--static { cursor: default; }

/* Underline tabs (panel switching). */
.tabs { display: flex; gap: var(--s-6); border-bottom: 1px solid var(--line); }
.tab {
  padding: var(--s-3) 0;
  margin-bottom: -1px;
  border: none; border-bottom: 2px solid transparent;
  background: none; cursor: pointer;
  font-size: var(--t-14); font-weight: var(--w-semi);
  color: var(--ink-500);
  transition: color .14s ease, border-color .14s ease;
}
.tab:hover { color: var(--ink-700); }
.tab--on   { color: var(--brand-600); border-bottom-color: var(--brand-600); }

/* Enclosed segmented control (billing period, status filters). */
.segmented {
  display: inline-flex;
  padding: var(--s-1);
  gap: var(--s-1);
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.segmented__btn {
  padding: 5px var(--s-4);
  border: none; border-radius: 5px;
  background: none; cursor: pointer;
  font-size: var(--t-13); font-weight: var(--w-semi);
  color: var(--ink-500);
  transition: background .14s ease, color .14s ease;
}
.segmented__btn[aria-selected="true"], .segmented__btn.is-on {
  background: var(--surface); color: var(--ink-900); box-shadow: var(--shadow-sm);
}

/* Label ABOVE input, error BELOW. Never placeholder-as-label. */
.field { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-4); }
.label { font-size: var(--t-13); font-weight: var(--w-semi); color: var(--ink-700); }
.input, .select, .textarea {
  width: 100%;
  padding: 10px var(--s-3);
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: var(--t-14);
  color: var(--ink-900);
  transition: border-color .14s ease, box-shadow .14s ease;
}
.input::placeholder, .textarea::placeholder { color: var(--ink-400); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--brand-600); box-shadow: var(--ring);
}
.textarea { min-height: 96px; resize: vertical; line-height: var(--lh-normal); }
.help  { font-size: var(--t-12); color: var(--ink-500); }
.field--error .input { border-color: var(--neg-600); }
.field--error .help  { color: var(--neg-600); }

.table { width: 100%; border-collapse: collapse; font-size: var(--t-14); }
.table th {
  padding: var(--s-3) var(--s-4);
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line);
  text-align: left;
  font-size: var(--t-12);
  font-weight: var(--w-bold);
  color: var(--ink-500);
  text-transform: uppercase;
  letter-spacing: .5px;
  white-space: nowrap;
}
.table td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--line); vertical-align: top; }
.table tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: var(--surface-sunken); }

.badge {
  display: inline-flex; align-items: center; gap: var(--s-1);
  padding: 2px var(--s-2);
  border-radius: var(--r-full);
  font-size: var(--t-11); font-weight: var(--w-semi);
  background: var(--surface-sunken); color: var(--ink-500);
}

.kpi__label { font-size: var(--t-12); color: var(--ink-500); text-transform: uppercase; letter-spacing: .4px; }
.kpi__value { font-size: var(--t-26); font-weight: var(--w-bold); color: var(--ink-900); font-variant-numeric: tabular-nums; line-height: 1.1; }
.kpi__delta { font-size: var(--t-13); color: var(--ink-500); }

.empty { padding: var(--s-12) var(--s-6); text-align: center; color: var(--ink-500); font-size: var(--t-14); }

.link { color: var(--brand-600); text-decoration: none; }
.link:hover { text-decoration: underline; }
.link-back {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--ink-500); font-size: var(--t-14); text-decoration: none;
}
.link-back:hover { color: var(--brand-600); }


/* ------------------------------------------------- document page shell --
   The five policy/FAQ pages were a frozen copy of an older stylesheet: the
   same .wrap/.logo/.card/.back/table rules pasted into each file, carrying
   border-radius:14px and box-shadow:0 2px 12px rgba(0,0,0,.04) long after the
   rest of the site moved on.

   Scoped to body.doc rather than published as bare .wrap/.card, because
   private/gbsupadmin.html and public/reset-password.html use .card for
   something else entirely and must not inherit this.
   -------------------------------------------------------------------- */

body.doc { background: var(--surface-sunken); color: var(--ink-700); line-height: var(--lh-relaxed); }
.doc .wrap { max-width: 820px; margin: 0 auto; padding: clamp(32px, 5vw, 56px) var(--s-5) var(--s-20); }
.doc .logo { display: flex; align-items: center; margin-bottom: var(--s-8); }
.doc .logo a { display: flex; align-items: center; }
.doc .logo img { height: 30px; width: auto; display: block; }

.doc h1 { font-family: var(--font-serif); font-weight: 600; font-size: clamp(1.7rem, 3vw, 2.1rem);
          letter-spacing: -.016em; color: var(--ink-900); margin: 0 0 6px; }
.doc .updated { color: var(--ink-500); font-size: var(--t-13); margin: 0 0 var(--s-8); }

.doc .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
             padding: clamp(24px, 4vw, 40px); box-shadow: var(--shadow-sm); }

.doc .card h2 { font-size: var(--t-18); font-weight: 700; letter-spacing: -.012em;
                color: var(--ink-900); margin: var(--s-8) 0 var(--s-3); }
.doc .card h2:first-child { margin-top: 0; }
.doc .card p, .doc .card li { font-size: var(--t-16); color: var(--ink-700); margin: 0 0 var(--s-3); max-width: 74ch; }
.doc .card ul { padding-left: var(--s-6); margin: 0 0 var(--s-4); }
.doc .card a { color: var(--brand-600); }

.doc table { width: 100%; border-collapse: collapse; margin: var(--s-3) 0 var(--s-5); font-size: var(--t-14); }
.doc th, .doc td { text-align: left; padding: var(--s-3) var(--s-3); border-bottom: 1px solid var(--line); vertical-align: top; }
.doc th { color: var(--ink-500); font-weight: 600; font-size: var(--t-13); }
/* Wide tables scroll in their own container so the page body never does. */
.doc .tbl-scroll { overflow-x: auto; contain: paint; }

/* overflow-wrap is load-bearing: a long unbroken token (a cookie name) inside
   inline <code> pushed cookies.html 21px past the viewport at 390px wide. */
.doc code { font-family: var(--font-mono); font-size: .88em; background: var(--surface-sunken);
            padding: 1px 5px; border-radius: 4px; overflow-wrap: anywhere; }

.doc .back { display: inline-flex; align-items: center; gap: var(--s-2); margin-top: var(--s-8);
             font-size: var(--t-14); color: var(--ink-500); text-decoration: none; }
.doc .back:hover { color: var(--brand-600); }


/* ----------------------------------------------------- status notice --
   Two jobs in one bar, both deliberate.

   1. Beta. The service is under test and the data can be incomplete or
      delayed; saying so up front is honest and lowers the stakes of any
      accuracy complaint.
   2. Independence. This sentence already exists at the foot of every page,
      but a visitor checking whether this is an official government service
      never scrolls that far. At the top it is unmissable, which is the
      entire point of having it.

   This re-introduces a full-width bar above the nav, which the redesign
   deliberately removed as dead chrome. It is back because this content is
   load-bearing, not decorative. Do not restyle it into something quieter.
   -------------------------------------------------------------------- */

.notice-bar {
  background: var(--warn-050);
  border-bottom: 1px solid #f0d9a0;
  color: #6b4d09;
  padding: 9px var(--gutter);
  font-size: var(--t-13);
  line-height: 1.5;
  text-align: center;
}
.notice-bar strong { font-weight: 700; }
.notice-bar b {
  display: inline-block;
  background: #6b4d09;
  color: #fff;
  font-size: var(--t-11);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: var(--r-full);
  margin-right: 8px;
  vertical-align: 1px;
}
@media (max-width: 720px) {
  .notice-bar { font-size: var(--t-12); padding: 8px var(--s-4); text-align: left; }
}


/* ------------------------------------------- open data licence notice --
   The Singapore Open Data Licence is what lets this product republish the
   awarded-tender records commercially. It is granted on condition that every
   product using the data carries "a conspicuous notice acknowledging the
   source of the datasets and including a link to the most recent version of
   this Licence". This is that notice. Do not remove it while the product
   still ships data.gov.sg data.
   -------------------------------------------------------------------- */

.odl {
  font-size: var(--t-12);
  line-height: 1.6;
  color: var(--ink-500);
}
.odl a { color: inherit; text-decoration: underline; }
.odl a:hover { color: var(--brand-600); }


/* -------------------------------------------------------------- layout -- */

.wrap-page { max-width: 1200px; margin: 0 auto; padding-inline: var(--gutter); }
.wrap-read { max-width: var(--measure); margin: 0 auto; }
.stack-2 > * + * { margin-top: var(--s-2); }
.stack-4 > * + * { margin-top: var(--s-4); }
.stack-6 > * + * { margin-top: var(--s-6); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
