/*
 * IBM Plex, self-hosted from public/vendor/fonts/ - deliberately NOT a Google
 * Fonts <link>. map.html's API responses carry unmasked NRICs, which is the
 * same reason MapLibre is vendored under public/vendor/: a font CDN is a live
 * third-party request issued by an authenticated page, and it would undo the
 * decision already taken for the largest asset on it. There is no build step,
 * so these are plain @font-face rules over four woff2 files.
 *
 * Latin subset only, and only the four weights actually declared below - Sans
 * 400/500/600 for the UI, Mono 400 for coordinates and codes. Any other weight
 * is synthesised by the browser rather than downloaded, which is the intended
 * trade: 86 KB total instead of the ~1 MB a full family costs.
 *
 * font-display: swap - the fallback stack paints immediately and the map is
 * readable before the fonts arrive. This page already spends seconds waiting on
 * ArcGIS; it must not also wait on type.
 *
 * Paths are relative to THIS file (public/css/), so ../vendor/fonts/ resolves
 * the same way for index.html and map.html.
 */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../vendor/fonts/ibm-plex-sans-latin-400-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../vendor/fonts/ibm-plex-sans-latin-500-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../vendor/fonts/ibm-plex-sans-latin-600-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../vendor/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
}

:root {
  --background: 0 0% 100%;
  --foreground: 240 10% 3.9%;
  --primary: 240 5.9% 10%;
  --primary-foreground: 0 0% 98%;
  --border: 240 5.9% 90%;
  --muted: 240 4.8% 95.9%;
  --muted-foreground: 240 3.8% 46.1%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 0 0% 98%;
  --radius: 0.5rem;

  /*
   * ── STATE IDENTITY ──────────────────────────────────────────────────────
   *
   * Perak's flag is white, yellow and black. Taken literally as an interface
   * palette that fails, and every figure here was measured in the browser
   * rather than eyeballed: white on the flag's yellow is 1.98:1, so a gold
   * button cannot carry white text at any size, and a large gold surface
   * competes with #EA580C, the house points on both map pages.
   *
   * Black on gold, however, is 8.95:1 - above AAA. Which is the whole reason
   * this works: the flag's own pairing is the legible one, and it is the
   * inverse of the one a designer reaches for by habit.
   *
   * So the three are identity, not interface. Black is the primary action
   * colour and was ALREADY --primary above, unchanged. White is the surface.
   * Gold appears as an accent only - the brand panel, the focus ring, the
   * mark, small active indicators - and never as a fill behind white text.
   *
   * THE RULE THAT MAKES THIS SAFE: brand colours live on chrome, never on the
   * map canvas. Canvas colour encodes data - boundary hierarchy, cluster
   * density, selection - and a colour that means "ePerak" cannot also mean
   * "this is a mukim". The atlas palette below is untouched by all of this.
   */
  /*
   * #FCD116 - lifted from the state arms themselves (public/img/), where it is
   * 109 of the fills against 72 of #161413 and nothing else of substance. So
   * the interface gold is now the emblem's gold rather than a near miss beside
   * it, which matters on the login page where the two sit centimetres apart.
   */
  --brand: 49 98% 54%;
  /*
   * Gold held dark enough to carry white text - 4.94:1, measured - so it is
   * the one gold that may be used as a fill behind a label.
   *
   * NOTHING USES IT YET. It is declared because the rule above ("gold is an
   * accent, never a fill") needs an answer to "then what do I use when I do
   * need a gold fill", and the dashboard is the next sub-project. Delete it
   * rather than inventing a use, if it is still unused when that lands.
   */
  --brand-strong: 35 92% 33%;
  /*
   * Black, and it does NOT flip in dark mode - which is why it is declared
   * once, here, rather than in both blocks. --brand is a light colour in both
   * themes (it is lifted for dark, not darkened), so anything drawn on it
   * needs a dark foreground either way. This was white for one revision and
   * measured 1.98:1 against the gold behind it: the exact pairing the block
   * above exists to forbid, and invisible to review because the mark is a
   * logo rather than text.
   */
  --brand-foreground: 240 10% 3.9%;
  /*
   * The focus ring, and the lightness is MEASURED rather than picked to look
   * right. WCAG 2.2 wants 3:1 for a non-text indicator against what surrounds
   * it, and against white this hue gives 2.82 at 40% and 3.10 at 38% - the
   * first fails, the second passes by so little that rounding decides it. 36%
   * is 3.42, which is the first value with room in it. Still gold; #B48204
   * does not read as brown until roughly 30%.
   *
   * --brand itself is nowhere near: 1.98 against white. A ring is one more
   * place the flag colour cannot be used raw.
   */
  --ring: 43 96% 36%;

  /*
   * Added for the map chrome. The nine tokens above are untouched and keep
   * their exact values: index.html renders from them and must not drift from
   * map.html, so the atlas palette is a new, additive set rather than a
   * recolouring of the old one.
   *
   * The palette is a printed atlas legend rather than dashboard chrome: warm
   * parchment surfaces, hairline rules, and headings in a muted brown. Stored
   * as bare HSL triplets to match the convention above, so hsl(var(--x)) works
   * and any of these can be lifted into a Tailwind config unchanged.
   */
  --atlas-surface: 40 47% 93%;
  --atlas-surface-raised: 40 50% 96%;
  --atlas-edge: 38 33% 79%;
  --atlas-rule: 40 38% 85%;
  --atlas-ink: 28 17% 15%;
  --atlas-ink-muted: 33 13% 39%;
  --atlas-heading: 36 22% 40%;
  --atlas-accent: 20 62% 38%;
  --atlas-accent-foreground: 40 50% 96%;

  --font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/*
 * :root, not html. Tailwind's Play CDN injects its preflight at runtime, so it
 * lands after this stylesheet in the cascade and its `html { font-family: … }`
 * would win a tie on source order. :root scores (0,1,0) against html's (0,0,1)
 * and wins on specificity instead, which is what makes one declaration here
 * cover both pages without either Tailwind config having to know about fonts.
 */
:root {
  font-family: var(--font-sans);
}

/*
 * ── READING SIZE ────────────────────────────────────────────────────────────
 *
 * The root size, and everything on these pages is expressed in rem, so this
 * one declaration moves the whole scale: Tailwind's utilities are rem-based
 * (text-sm is 0.875rem, not 14px), so text, padding, gaps and control heights
 * all track it together. Changing individual font sizes instead would move the
 * type and leave the boxes around it the same, which is how an interface ends
 * up looking crowded rather than larger.
 *
 * Why it moves at all: 16px is a browser default chosen for 96 DPI. On a 27"
 * 4K panel a CSS pixel is roughly half the physical size it was designed for,
 * and the first thing a reader does is reach for browser zoom - which is a
 * per-site setting they must reapply per device and which no colleague
 * inherits. Making the default comfortable is the fix; zoom then goes back to
 * being what it is for, an occasional adjustment rather than a prerequisite.
 *
 * 18px is 112.5% of 16 and is the desktop value. It sits inside the 110-125%
 * band that reads comfortably at arm's length on a high-density panel without
 * so much reflow that the dashboard's two-column rows collapse.
 *
 * It steps rather than scaling continuously, and it steps UP with width, not
 * down. A phone is held at ~30 cm and a desktop panel sits at ~60 cm, so the
 * small screen is the one that needs the smaller number to fit a usable line
 * length: 16px there is not a compromise, it is the correct value for that
 * distance. clamp() on viewport width was the alternative and is rejected on
 * purpose - a size that changes on every drag of a window edge makes the
 * dashboard's tables reflow continuously while being resized.
 *
 * Anything in px inside a component stops tracking this. That is the reason to
 * keep new work in rem/Tailwind utilities; the existing px values in
 * map-chrome.css are map furniture, sized against the tiles rather than the
 * text, and are meant to stay put.
 */
@media (min-width: 768px) {
  :root {
    font-size: 17px;
  }
}

@media (min-width: 1280px) {
  :root {
    font-size: 18px;
  }
}

/*
 * Driven by the CARTO Dark basemap, not by a dark-mode feature: a dark map
 * under light chrome reads as a rendering fault. There is no toggle, no
 * localStorage, and no prefers-color-scheme default - selecting the dark
 * basemap adds .dark to <html> and selecting another removes it.
 *
 * :root.dark, not .dark: a bare class ties with :root on specificity and wins
 * only by source order, so it would break silently if a later stylesheet
 * restated :root or if these blocks were ever reordered.
 */
:root.dark {
  --background: 240 10% 3.9%;
  --foreground: 0 0% 98%;
  --primary: 0 0% 98%;
  --primary-foreground: 240 5.9% 10%;
  --border: 240 3.7% 15.9%;
  --muted: 240 3.7% 15.9%;
  --muted-foreground: 240 5% 64.9%;
  --destructive: 0 62.8% 30.6%;
  --destructive-foreground: 0 0% 98%;

  /*
   * Gold lifted, not darkened. On a near-black field the light value reads as
   * brown, and the flag colour is the one thing here that must stay
   * recognisable. --brand-strong and --ring move the other way from their
   * light-mode values for the same reason each was chosen: one has to carry
   * white text, the other has to be seen against the page.
   */
  /* The emblem gold again. It is already bright enough for a dark field, so
     unlike the atlas palette this one does not need lifting. */
  --brand: 49 98% 54%;
  --brand-strong: 40 90% 46%;
  --ring: 45 95% 55%;
  /* --brand-foreground is deliberately absent. See its note in :root. */

  /*
   * The dark half of the atlas palette. Not the light one inverted - parchment
   * inverted is a cold grey, which is the thing the warm palette exists to
   * avoid. These are the same hues held into a dark umber so the chrome still
   * reads as the same object under CARTO Dark.
   */
  --atlas-surface: 26 16% 9%;
  --atlas-surface-raised: 27 15% 12%;
  --atlas-edge: 28 16% 22%;
  --atlas-rule: 28 16% 18%;
  --atlas-ink: 36 39% 90%;
  --atlas-ink-muted: 35 18% 60%;
  --atlas-heading: 34 26% 67%;
  --atlas-accent: 21 53% 55%;
  --atlas-accent-foreground: 26 16% 9%;
}
