/* ============================================================
   GigOpsAi — Brand Tokens
   Drop this file into your project and import it first in your
   main CSS (or link it before all other stylesheets in HTML).

   Design language: "road case". The reference points are the
   printed artefacts of the touring industry — day sheets, freight
   manifests, settlement statements, flight-case stencils, amp-panel
   silkscreen. That means: hard edges, structure from rules rather
   than glow, condensed caps for labels, and monospaced figures that
   line up in a column. Deliberately NOT the soft rounded-and-blurred
   house style: no gradient fills, no frosted panels, no bloom
   shadows, no pill-shaped everything.
   ============================================================ */

/* ── Fonts ──
   IBM Plex Sans is the workhorse: an engineered grotesque with flat
   terminals and open counters that survives 11–13px table text far
   better than a geometric sans. Plex Sans Condensed carries every
   heading and uppercase label, so heading/body contrast comes from
   WIDTH, not just weight — the thing a single-typeface UI can never
   do. DM Mono stays for figures, codes and timestamps. Inter is the
   wordmark only; Caveat draws a typed signature in GigOps Sign.

   Self-hosted from /fonts (no third-party request on any page, and the
   CSP allows fonts from this origin only). Latin and Latin Extended
   subsets, each loaded only when a page uses its characters; Plex Sans
   and Inter are variable files covering their weight range. The faces
   are under the SIL Open Font License (fonts/OFL-web-fonts.txt). With
   font-display: swap the text shows at once in the system stack. */
@font-face { font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('/fonts/ibm-plex-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('/fonts/ibm-plex-sans-latin.woff2') format('woff2');
  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: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-500-latin.woff2') format('woff2');
  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: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-600-latin.woff2') format('woff2');
  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: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Sans Condensed'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/fonts/ibm-plex-sans-condensed-700-latin.woff2') format('woff2');
  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: 'DM Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/dm-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'DM Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/dm-mono-400-latin.woff2') format('woff2');
  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: 'DM Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/dm-mono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'DM Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/dm-mono-500-latin.woff2') format('woff2');
  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: 'Inter'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  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: 'Caveat'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/caveat-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Caveat'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/caveat-latin.woff2') format('woff2');
  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; }

/* ── Core Tokens ── */
:root {
  /* Colors */
  --color-primary:        #3B6CF6;   /* Signal Blue — CTAs, links, icon fill */
  --color-primary-dark:   #1C3D8A;   /* Signal Blue Dark — pressed states, headings */
  --color-primary-light:  #5B8BF5;   /* Sky Pulse — hover states, accents */
  --color-primary-tint:   #EEF3FF;   /* Cloud Tint — backgrounds, badge fills */
  --color-primary-border: #C5D4FA;   /* Outline buttons, input focus rings */

  /* Logo (GigOps / TourOps Signal Blue): gradient stops and wordmark face */
  --logo-1:               #1C3D8A;   /* gradient start, top left */
  --logo-2:               #3B6CF6;   /* gradient 60% stop and wordmark accent */
  --logo-3:               #5B8BFF;   /* gradient end, bottom right */

  --color-dark:           #0A0F1E;   /* Stage Dark — primary text, dark surfaces */
  --color-bg:             #F5F7FF;   /* Off White — page background */
  --color-surface:        #FFFFFF;   /* Cards, modals */
  --color-border:         #C8D2E8;   /* Dividers, card borders — a real rule, not a hairline */
  --color-rule:           #97A6C4;   /* Emphatic rule: section heads, table heads */
  --color-muted:          #556385;   /* Secondary text, labels (6.0:1 on white, 5.6:1 on Off White) */
  --color-subtle:         #5E6C93;   /* Tertiary text, placeholders (4.6:1 or better on every ground) */

  /* Status */
  --color-success:        #1E7B4B;
  --color-success-tint:   #E6F5EE;
  --color-warning:        #C4460A;
  --color-warning-tint:   #FFF3EE;
  --color-neutral-tint:   #F0F2F7;

  /* Shared by every page (the SPA, GigOps Crew, the console and the public
     pages restate them per theme where they have a dark one). */
  --on-pri:               #ffffff;   /* text and icons on a solid accent or danger fill */
  --scrim:                rgba(10,15,30,0.5);    /* behind a modal or a gate */

  /* Typography */
  --font-sans:   'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-cond:   'IBM Plex Sans Condensed', 'IBM Plex Sans', -apple-system, 'Segoe UI', sans-serif;
  --font-mono:   'DM Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-logo:   'Inter', 'IBM Plex Sans', -apple-system, 'Segoe UI', sans-serif;   /* wordmark only */

  --text-display:  700;   /* Headlines — set heavy and condensed, never hairline */
  --text-body:     400;   /* Body copy */
  --text-medium:   500;   /* Subheadings, nav */
  --text-semibold: 600;   /* Buttons, labels */

  --size-display: 2rem;     /* 32px */
  --size-h1:      1.75rem;  /* 28px */
  --size-h2:      1.375rem; /* 22px */
  --size-h3:      1.125rem; /* 18px */
  --size-body:    1rem;     /* 16px */
  --size-small:   0.875rem; /* 14px */
  --size-label:   0.6875rem;/* 11px */

  --leading-tight:  1.15;
  --leading-normal: 1.6;
  --tracking-wide:  0.08em;

  /* Spacing scale */
  --space-1:   4px;
  --space-2:   8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  24px;
  --space-6:  32px;
  --space-7:  40px;
  --space-8:  56px;
  --space-9:  80px;

  /* Radius — near-square by intent. The old scale topped out at 22px and
     put cards, buttons, inputs and icon tiles on the same soft curve, which
     is what makes an interface read as generic. Here the radius is small
     enough to be structural (a milled edge, not a bubble) and each step
     means something: controls, containers, then the one platform-mandated
     app-icon shape. */
  --radius-sm:   2px;    /* inputs, chips, badges */
  --radius-md:   3px;    /* buttons, cards */
  --radius-lg:   4px;    /* panels, modals */
  --radius-pill: 999px;  /* reserved: avatars and status dots only */
  --radius-app:  22px;   /* iOS app-icon mask — a platform requirement, not a style */

  /* Shadows — reserved for things that genuinely float above the page
     (modals, menus, toasts). Cards get a border, not a bloom. Neutral and
     tight rather than a wide blue haze, so elevation reads as a cast
     shadow instead of a glow. */
  --shadow-sm:  0 1px 2px rgba(10,15,30,0.10);
  --shadow-md:  0 2px 6px rgba(10,15,30,0.14);
  --shadow-lg:  0 6px 18px rgba(10,15,30,0.20);
}


/* ── Kiosk dark ──
   The parked-device pages (the gate scanner /scan, the gear station
   /gear-scan, the catering kiosk) stay on Stage Dark whatever the device's
   theme: a dark screen is easier on the eye at a dim gate or door, at night,
   and the camera preview reads better on it. They opt in with
   <html class="kiosk-dark"> and use the SPA's token names, so their accent
   is the brand's and moves with it. */
.kiosk-dark {
  color-scheme: dark;
  --bg:     var(--color-dark);      /* Stage Dark */
  --bg2:    #141B2E;
  --bg3:    #1E2740;
  --border: #2A3450;
  --text:   var(--color-bg);        /* Off White */
  --text2:  #9FB0D0;
  --text3:  #8492B2;                /* 4.7:1 on --bg3, 5.5:1 on --bg2 */
  --blue:   var(--color-primary);
  --green:  #1EBA7A;
  --amber:  #F59E0B;
  --red:    #EF4444;
  /* Solid verdict and button fills; each holds --on-pri at the large-text
     bar or better (the verdicts are set at 27px and up). */
  --ok-fill:    #16A34A;
  --warn-fill:  #D97706;
  --red-fill:   #B42318;            /* 6.6:1 */
  --muted-fill: #475569;
  --gbg:    rgba(30,186,122,.14);
  --abg:    rgba(245,158,11,.13);
  --bbg:    color-mix(in srgb, var(--blue) 15%, transparent);
  --blue-line: color-mix(in srgb, var(--blue) 55%, transparent);
  --teal:   #2DD4BF;
  --scrim:  rgba(0,0,0,0.62);
}

/* ── Keyboard focus ──
   One visible ring on every page for whatever the keyboard is on, in the
   page's accent (--blue, so a product flavor's colour; the brand primary
   where a page has no --blue). A page may set --focus-outline. Written as
   element:focus-visible so it outranks a component's "outline: none"; a
   mouse click does not show it. */
button:focus-visible, a:focus-visible, summary:focus-visible,
[role="button"]:focus-visible, [role="tab"]:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
  outline: 2px solid var(--focus-outline, var(--blue, var(--color-primary)));
  outline-offset: 2px;
}

/* ============================================================
   Typography Utilities
   Headings are condensed and set tight; body is the regular width.
   Keep that split — it is the whole reason the interface reads as
   designed rather than defaulted.
   ============================================================ */

body {
  font-family: var(--font-sans);
  font-size: var(--size-body);
  font-weight: var(--text-body);
  line-height: var(--leading-normal);
  color: var(--color-dark);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
}

.text-display {
  font-family: var(--font-cond);
  font-size: var(--size-display);
  font-weight: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: -0.015em;
  color: var(--color-dark);
}

.text-h1 {
  font-family: var(--font-cond);
  font-size: var(--size-h1);
  font-weight: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
}

.text-h2 {
  font-family: var(--font-cond);
  font-size: var(--size-h2);
  font-weight: var(--text-semibold);
  line-height: var(--leading-tight);
  letter-spacing: 0;
}

.text-h3 {
  font-family: var(--font-cond);
  font-size: var(--size-h3);
  font-weight: var(--text-semibold);
}

.text-body   { font-size: var(--size-body); font-weight: var(--text-body); }
.text-small  { font-size: var(--size-small); }
.text-muted  { color: var(--color-muted); }
.text-subtle { color: var(--color-subtle); }
.text-primary-color { color: var(--color-primary); }

/* Figures, codes, timestamps, currency. Tabular so columns align. */
.text-figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.text-label {
  font-family: var(--font-cond);
  font-size: var(--size-label);
  font-weight: var(--text-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-muted);
}


/* ============================================================
   Wordmark
   Usage: <span class="wordmark">GigOps.<span class="wordmark__ai">AI</span></span>
   Flavors: <span class="wordmark">Tour<span class="wordmark__ai">Ops</span></span>
   Inter Light base word, Inter Bold accent in the flavor color.
   ============================================================ */

.wordmark {
  font-family: var(--font-logo);
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--color-dark);
}

.wordmark__ai {
  font-weight: 700;
  color: var(--logo-2);
}


/* ============================================================
   Logo mark
   A rounded square (25% corner radius) filled corner to corner with a
   three-stop gradient: dark, the wordmark accent at 60%, light. A pale
   dot (white at 78%) sits top right. The mark is fixed brand art, so its
   colors come from --logo-1/2/3, not from the UI accent; each product
   flavor sets its own trio (Product flavors, below).

  ICON SVG (copy this block; the same art is /favicon.svg):

  <svg width="64" height="64" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg" aria-label="GigOps.AI">
    <defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#1C3D8A"/><stop offset="0.6" stop-color="#3B6CF6"/><stop offset="1" stop-color="#5B8BFF"/>
    </linearGradient></defs>
    <rect width="320" height="320" rx="80" fill="url(#g)"/>
    <circle cx="230" cy="90" r="30" fill="#fff" fill-opacity="0.78"/>
  </svg>
   ============================================================ */

.brand-icon {
  position: relative;
  border-radius: 25%;
  background: linear-gradient(135deg, var(--logo-1) 0%, var(--logo-2) 60%, var(--logo-3) 100%);
}

.brand-icon::before {
  content: '';
  position: absolute;
  left: 62.5%; top: 18.75%;
  width: 18.75%; height: 18.75%;
  border-radius: 50%;
  background: rgba(255,255,255,0.78);
}


/* ============================================================
   Product flavors
   body[data-flavor] picks the product: the SPA sets it on sign-in
   (_applyFlavor), the CAD editor from the company. These rules sit on
   body, a closer ancestor than :root, and are more specific than
   body.light-mode, so they win over a page's own light and dark sets.
   ============================================================ */
/* TourOps keeps the GigOps Signal Blue (each page's own palette).
   FestivalOps re-skins the PRIMARY accent to green, leaving the semantic
   --green (success) intact. Only the de-facto primary tokens are remapped
   (--blue / --bbg / --focus-ring), per light + dark, plus the logo colours;
   the accent outlines (--blue-line) follow --blue on their own. */
body.light-mode[data-flavor="festival"] {
  --blue:       #047857;   /* emerald-700 — solid primary buttons hold white text */
  --bbg:        #E3F5EF;   /* pale emerald tint */
  --focus-ring: rgba(4,120,87,0.5);
}
body[data-flavor="festival"]:not(.light-mode) {
  --blue:       #059669;   /* emerald-600 for dark surfaces */
  --bbg:        rgba(16,185,129,0.14);
  --focus-ring: rgba(16,185,129,0.5);
}

/* ── LOGO ─────────────────────────────────────── */
/* The logo mark is fixed brand art, not a UI accent: a rounded square with
   a corner-to-corner gradient (dark, the wordmark accent at 60%, light) and
   a pale dot top right. --logo-2 is also the wordmark accent in light mode.
   GigOps / TourOps keep the Signal Blue defaults from gigopsai-brand.css,
   FestivalOps is emerald, VenueOps brick; the other flavors follow the same
   dark / accent / light recipe. The mark itself is drawn there too. */
body[data-flavor="festival"] { --logo-1: #03543F; --logo-2: #047857; --logo-3: #10B981; }
body[data-flavor="venue"]    { --logo-1: #7C2D12; --logo-2: #B5451B; --logo-3: #DF7149; }
body[data-flavor="coral"]    { --logo-1: #9A2A1E; --logo-2: #E35749; --logo-3: #F58A70; }
body[data-flavor="promoter"] { --logo-1: #3B1685; --logo-2: #6D28D9; --logo-3: #8B5CF6; }
body[data-flavor="action"]   { --logo-1: #7C2D12; --logo-2: #C2410C; --logo-3: #F97316; }

/* CoralOps re-skins the PRIMARY accent to a warm coral (pink/orange) — named
   for the reef, distinct from the Signal Blue engine base and the FestivalOps
   emerald. Kept saturated enough that solid primary buttons still hold white
   text (~3.7:1, matching the engine blue); the lighter, warmer feel comes
   from the pale --bbg tint. Same token-only approach (--blue / --bbg /
   --focus-ring per light + dark); the
   semantic --green/--red are left untouched. */
body.light-mode[data-flavor="coral"] {
  --blue:       #E35749;   /* living coral — solid primary buttons hold white text */
  --bbg:        #FDECE8;   /* pale coral wash */
  --focus-ring: rgba(227,87,73,0.5);
}
body[data-flavor="coral"]:not(.light-mode) {
  --blue:       #E2553E;   /* coral for dark surfaces (still holds white text) */
  --bbg:        rgba(226,85,62,0.16);
  --focus-ring: rgba(226,85,62,0.5);
}

/* VenueOps re-skins the PRIMARY accent to a warm brick — the house, not the
   road — distinct from Signal Blue, the FestivalOps emerald and the CoralOps
   coral. Light brick holds white button text at ~6:1, the dark one at ~3.9:1
   (the engine's own bar). Same token-only approach as the other flavors. */
body.light-mode[data-flavor="venue"] {
  --blue:       #A8432A;   /* brick — solid primary buttons hold white text */
  --bbg:        #F8E9E2;   /* pale brick wash */
  --focus-ring: rgba(168,67,42,0.5);
}
body[data-flavor="venue"]:not(.light-mode) {
  --blue:       #CF5F36;   /* brick for dark surfaces (still holds white text) */
  --bbg:        rgba(207,95,54,0.16);
  --focus-ring: rgba(207,95,54,0.5);
}

/* PromoterOps re-skins the PRIMARY accent to violet — the money side of the
   show, distinct from Signal Blue, the FestivalOps emerald, the CoralOps
   coral and the VenueOps brick. Light violet holds white button text at
   ~7:1, the dark one at the engine's own bar. The semantic --purple (On
   hold pills, owner and legal badges) moves to fuchsia here: left violet it
   was the primary itself in dark mode and a shade from it in light, so a
   pill read as a button. Its text holds 5.4:1 or better on the pill tint. */
body.light-mode[data-flavor="promoter"] {
  --blue:       #6D28D9;   /* violet-700 — solid primary buttons hold white text */
  --bbg:        #EFEAFD;   /* pale violet wash */
  --focus-ring: rgba(109,40,217,0.5);
  --purple:     #86198F;   /* fuchsia-800 */
  --pbg:        rgba(134,25,143,0.1);
}
body[data-flavor="promoter"]:not(.light-mode) {
  --blue:       #8B5CF6;   /* violet-500 for dark surfaces */
  --bbg:        rgba(139,92,246,0.16);
  --focus-ring: rgba(139,92,246,0.5);
  --purple:     #E879F9;   /* fuchsia-400 */
  --pbg:        rgba(232,121,249,0.14);
}
/* ActionOps re-skins the PRIMARY accent to a high-contrast orange — reads on
   snow, on a dark ops-room screen and on a tablet in sunlight — distinct from
   Signal Blue, the FestivalOps emerald, the CoralOps coral and the VenueOps
   brick. Light orange holds white button text at ~5.4:1, the dark one at
   ~3.4:1 (the engine's own bar). Same token-only approach as the other
   flavors; --green/--red semantic tokens untouched. The brand icon carries a
   skateboard (a masked inline SVG on top of the gradient). */
body.light-mode[data-flavor="action"] {
  --blue:       #C2410C;   /* orange — solid primary buttons hold white text */
  --bbg:        #FDEBDD;   /* pale orange wash */
  --focus-ring: rgba(194,65,12,0.5);
}
body[data-flavor="action"]:not(.light-mode) {
  --blue:       #EA580C;   /* orange for dark surfaces (still holds white text) */
  --bbg:        rgba(234,88,12,0.16);
  --focus-ring: rgba(234,88,12,0.5);
}
body[data-flavor="action"] .brand-icon::before { display: none; }
body[data-flavor="action"] .brand-icon::after {
  content: '';
  position: absolute; inset: 2px;
  background: #fff;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M3.5 10.5c0-1.4 1.1-2.5 2.5-2.5h12c1.4 0 2.5 1.1 2.5 2.5v.5c0 1.4-1.1 2.5-2.5 2.5H6c-1.4 0-2.5-1.1-2.5-2.5z' transform='rotate(-12 12 11)'/><circle cx='8' cy='16.5' r='2'/><circle cx='16.5' cy='14.5' r='2'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M3.5 10.5c0-1.4 1.1-2.5 2.5-2.5h12c1.4 0 2.5 1.1 2.5 2.5v.5c0 1.4-1.1 2.5-2.5 2.5H6c-1.4 0-2.5-1.1-2.5-2.5z' transform='rotate(-12 12 11)'/><circle cx='8' cy='16.5' r='2'/><circle cx='16.5' cy='14.5' r='2'/></svg>") center / contain no-repeat;
}


/* ============================================================
   Buttons
   Flat fills. A gradient on a button is decoration standing in for
   hierarchy; the hierarchy here is fill vs. outline vs. bare.
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px 20px;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--size-small);
  font-weight: var(--text-semibold);
  line-height: 1;
  cursor: pointer;
  border: none;
  transition: background-color 0.12s ease;
  text-decoration: none;
}

.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--color-primary);
  color: #ffffff;
}
.btn-primary:hover { background: var(--color-primary-dark); }

.btn-outline {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid var(--color-primary-border);
}
.btn-outline:hover { background: var(--color-primary-tint); }

.btn-ghost {
  background: transparent;
  color: var(--color-muted);
  border: 1px solid var(--color-border);
}
.btn-ghost:hover { background: var(--color-neutral-tint); }

.btn-sm { padding: 7px 14px; font-size: var(--size-label); }
.btn-lg { padding: 13px 28px; font-size: var(--size-body); }


/* ============================================================
   Cards
   Border, no shadow. Depth comes from the rule and the fill, so a
   card that IS raised (a menu, a modal) can use a shadow and
   actually read as raised.
   ============================================================ */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

.card-sm { padding: var(--space-4); }
.card-lg { padding: var(--space-6); border-radius: var(--radius-lg); }

/* Opt in for genuinely floating surfaces only. */
.card-raised { box-shadow: var(--shadow-lg); }


/* ============================================================
   Badges / Status Pills
   Squared tags with a status bar down the left edge — a flag on a
   printed line, not a pill. Condensed caps keep them short.
   ============================================================ */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 9px 3px 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
  font-family: var(--font-cond);
  font-size: 11px;
  font-weight: var(--text-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.35;
}

.badge::before {
  content: '';
  display: inline-block;
  align-self: stretch;
  width: 3px;
  background: currentColor;
}

.badge-live       { background: var(--color-success-tint); color: var(--color-success); }
.badge-scheduled  { background: var(--color-primary-tint);  color: var(--color-primary-dark); }
.badge-review     { background: var(--color-warning-tint);  color: var(--color-warning); }
.badge-draft      { background: var(--color-neutral-tint);  color: var(--color-muted); }


/* ============================================================
   Metric / Stat Cards
   Ruled off the top like a column on a settlement sheet, figures in
   the mono face. No tinted tile: a row of soft coloured boxes with
   big round numbers in them is exactly the "10K+ Users" look, and it
   flattens real reporting into marketing.
   ============================================================ */

.metric-card {
  background: transparent;
  border-top: 2px solid var(--color-rule);
  border-radius: 0;
  padding: var(--space-3) 0 0;
}

.metric-card__label {
  font-family: var(--font-cond);
  font-size: var(--size-label);
  font-weight: var(--text-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-muted);
}

.metric-card__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.625rem;
  font-weight: 500;
  color: var(--color-dark);
  margin-top: var(--space-1);
  letter-spacing: -0.03em;
}

.metric-card__value--accent { color: var(--color-primary); }


/* ============================================================
   Form Elements
   ============================================================ */

.input {
  width: 100%;
  padding: 9px 12px;
  font-family: var(--font-sans);
  font-size: var(--size-small);
  color: var(--color-dark);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  outline: none;
  transition: border-color 0.12s;
}

.input:focus {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}

.input::placeholder { color: var(--color-subtle); }


/* ============================================================
   Nav / Header pattern
   Opaque, with a hard rule underneath. The translucent blurred bar
   is the frosted-glass tell, and it costs legibility over dense
   tables for nothing.
   ============================================================ */

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-4) var(--space-6);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-rule);
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: auto;
  list-style: none;
}

.nav__link {
  font-family: var(--font-cond);
  font-size: var(--size-small);
  font-weight: var(--text-medium);
  color: var(--color-muted);
  text-decoration: none;
  transition: color 0.12s;
}

.nav__link:hover { color: var(--color-dark); }
.nav__link--active { color: var(--color-primary); }


/* ============================================================
   Divider
   ============================================================ */

.divider {
  height: 1px;
  background: var(--color-border);
  border: none;
  margin: var(--space-6) 0;
}


/* ============================================================
   House rules — read before adding to this file
   ──────────────────────────────────────────────────────────
   1. Link this file BEFORE the page's own stylesheet:
        <link rel="stylesheet" href="gigopsai-brand.css">
   2. Headings and uppercase labels take var(--font-cond); body copy
      takes var(--font-sans); figures, codes and timestamps take
      var(--font-mono). Never set a heading in the body face — the
      width contrast is the identity.
   3. No gradient fills. Flat colour, or a rule, or nothing.
   4. No backdrop-filter. Surfaces are opaque.
   5. Shadows are for things that float (modal, menu, toast). A card
      in the page flow gets a border.
   6. Radius comes from the scale and stops at 4px. --radius-pill is
      for avatars and status dots; --radius-app is the iOS icon mask.
   7. No hover lift or scale. Hover changes colour.
   8. Tokens only — never a hard-coded hex.
   ============================================================ */
