/* ---------------------------------------------------------------------------
   SG90's Puzzles & Survival Tools -- the shared visual identity.

   One source, consumed two ways:
     - the static tools <link> this file and alias their own names onto it,
       so the hundreds of var(--x) uses inside each tool never get touched
     - src/app/globals.css imports it at build time and re-exposes it to
       Tailwind through @theme inline

   Dark only, on purpose. All three tools were built dark -- the hive grid and
   the calculator's textures assume it -- and a light variant would only hold
   the family together for half of visitors.

   Single palette across every surface. Tools are told apart by name and (on
   the hub) artwork, not by each owning a different hue, so nothing here is
   per-app.
--------------------------------------------------------------------------- */

:root {
  color-scheme: dark;

  /* --- neutrals ---------------------------------------------------------
     Converges four near-identical backgrounds (#070a0e, #0c0d0f, #0a0a0f,
     #0a0a0a) onto one ramp. Slightly blue-leaning rather than pure grey so
     it sits with the accent instead of fighting it. */
  --bg: #0a0b0f;
  --bg-raised: #0f1116;
  --surface: #13151c;
  --surface-2: #1a1d26;
  --surface-3: #222634;
  /* Card/section borders are decorative separation, so WCAG 1.4.11's 3:1 does
     not apply to them -- but it does apply to anything that identifies a
     control. --border-input is the one that has to clear 3:1, because it is
     what tells you where a text field begins. Measured against both --bg and
     --surface: 3.69:1 and 3.43:1. */
  --border: #272b36;
  --border-strong: #363b4a;
  --border-input: #626b82;

  /* Checked against the LIGHTEST surface these can land on (--surface-3, the
     draft-badge tint), not just against the page -- that is the worst case,
     and --text-muted originally failed it at 3.98:1 while passing everywhere
     else. Sized so a token is safe wherever it is used rather than only where
     it was first used. */
  --text: #e9ebf2;
  --text-dim: #a2a9bd;
  --text-muted: #8b92a6;

  /* --- accent -----------------------------------------------------------
     Gold. Reads as Wasteland King without being red -- and it can't be red,
     because buttonDanger is, and a red brand colour would stop destructive
     controls looking destructive in a data-dense admin.

     Two values of the one hue, because no single gold can do both jobs on a
     near-black page. --accent is the light tone, and is the only one safe as
     TEXT (9.3:1 on a card). --accent-solid is the deep tone for filled
     buttons and panels, carrying white (5.3:1) -- as text it measures only
     3.46:1 and misses AA, so never use it as one.

     The solid hover goes DARKER, which is backwards from the usual instinct.
     Lightening a dark fill drops the contrast of the white sitting on it:
     #a86e20 measured 4.27:1 and failed. Darkening moves the other way and
     still reads clearly as a state change. */
  --accent: #e8b04a;
  --accent-hover: #f0c470;
  --accent-solid: #96601a;
  --accent-solid-hover: #7d5015;
  --on-accent-solid: #ffffff;
  --accent-dim: rgba(232, 176, 74, 0.13);
  --accent-glow: rgba(232, 176, 74, 0.32);
  --accent-border: rgba(232, 176, 74, 0.42);

  /* --- supporting hues --------------------------------------------------
     The "more colour, still one scheme" half. Semantic first (status,
     danger, success) but also the ramp anything decorative should draw
     from, so pages get colour without inventing new ones per page. */
  --cyan: #22d3ee;
  --violet: #a78bfa;
  --success: #34d399;
  /* Orange, not amber. Amber (#fbbf24) measured deltaE 10.8 against the gold
     accent -- close enough to read as the same colour, and LOCKED badges sit
     directly beside accent text in the events list. Orange puts it at 25.1,
     further apart than crimson and danger already are (15.9). */
  --warning: #fb923c;
  --danger: #fb7185;
  /* Wasteland King's own red, kept as an available colour rather than the
     brand one -- it reads as "war" on a hero panel, but it can't lead, or
     destructive controls stop looking destructive. Lifted once from #e8384f,
     which missed AA on a card at 4.44:1.

     Deliberately NOT lifted again to clear 4.5:1 on --surface-3, where it
     sits at 4.17:1. It is only ever large display text on a hero panel, and
     1.4.3 asks 3:1 of large text, so it already passes there. Lifting it to
     #f25a6e did clear 4.5 everywhere -- and put it deltaE 9.3 from --danger,
     which is the same colour to the eye. Distinguishable from the destructive
     red matters more here than a threshold this use never has to meet. */
  --crimson: #ef4a60;

  /* --- WK alliance grades -----------------------------------------------
     The five state-points tiers, coloured so a grade is recognisable at a
     glance on the WK Grade page.

     Not literal metals, deliberately. Platinum and silver are near-identical
     in life, and rendering them faithfully put them deltaE 10.6 apart -- the
     same colour, to the eye, on the one page whose entire job is telling
     grades apart. Pushing platinum cool and diamond blue spreads the set to
     25.0 at its closest pair while each still reads as its own tier.

     Gold is the accent itself: the grade and the brand colour genuinely are
     the same gold, so giving them separate values would be a lie the eye
     would catch. All five clear 4.5:1 on --surface-3, the lightest surface a
     grade can land on. */
  --grade-bronze: #e08a52;
  --grade-silver: #aeb6c4;
  --grade-gold: var(--accent);
  --grade-platinum: #7fe3d4;
  --grade-diamond: #63b3ff;

  --cyan-dim: rgba(34, 211, 238, 0.14);
  --violet-dim: rgba(167, 139, 250, 0.14);
  --success-dim: rgba(52, 211, 153, 0.14);
  --warning-dim: rgba(251, 146, 60, 0.14);
  --danger-dim: rgba(251, 113, 133, 0.14);

  /* --- type -------------------------------------------------------------
     Was five display faces across four products (Geist, Rajdhani, Syne,
     Cinzel, Inter). Rajdhani already appeared in two of the three tools and
     suits the game, so it leads; Inter carries body text because it stays
     readable at the sizes the admin tables use. */
  --font-display: "Rajdhani", system-ui, sans-serif;
  --font-ui: "Inter", system-ui, -apple-system, sans-serif;
  --font-mono: "DM Mono", ui-monospace, "SF Mono", monospace;

  /* --- shape ------------------------------------------------------------ */
  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;
  --r-full: 999px;

  --ring: 0 0 0 1px var(--accent-border), 0 0 0 4px var(--accent-dim);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-raised: 0 8px 24px rgba(0, 0, 0, 0.45);
}

/* ---------------------------------------------------------------------------
   The page backdrop -- a faint grid under two soft pools of gold.

   Started life inside the WK Points Calculator, was copied onto the hub, and
   is now here so every surface gets the same one. The calculator's copy was
   still tinted red from before the palette was unified, which is exactly the
   drift that having two copies produces.

   A ::before rather than a background-image on body, for two reasons. Body's
   background would scroll with a long admin table, and re-tiling a 45px grid
   down a 4000px page is both ugly and wasteful; this stays put. And it avoids
   `background-attachment: fixed`, which iOS Safari handles badly.

   Deliberately barely visible -- 7% and 5% gold, and grid lines at 1.4% white.
   It should read as texture on an almost-black page, never as a pattern
   competing with a roster table.
--------------------------------------------------------------------------- */

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse at 15% 0%, rgba(232, 176, 74, 0.07) 0%, transparent 55%),
    radial-gradient(ellipse at 85% 100%, rgba(232, 176, 74, 0.05) 0%, transparent 55%),
    repeating-linear-gradient(0deg, transparent, transparent 44px, rgba(255, 255, 255, 0.014) 44px, rgba(255, 255, 255, 0.014) 45px),
    repeating-linear-gradient(90deg, transparent, transparent 44px, rgba(255, 255, 255, 0.014) 44px, rgba(255, 255, 255, 0.014) 45px);
}

/* ---------------------------------------------------------------------------
   The site strip -- the one piece of chrome every surface shares.

   Lives here rather than in its own file so the three static tools pick it up
   from the <link> they already have, and the app gets it through globals.css's
   import. One request, one place to restyle.

   Prefixed sg- throughout: this stylesheet is loaded into three tools that
   were written independently and have their own class names, so anything
   generic (.nav, .header, .brand) would eventually collide with one of them.
--------------------------------------------------------------------------- */

/* Fixed, not in normal flow, and this is not cosmetic. The Hive Mapper's
   body is `display:flex; flex-direction:row` -- dropping the strip in as a
   child made it a COLUMN beside the sidebar rather than a bar above it, and
   shoved the whole tool sideways. A tool's body layout is its own business, so
   the strip stays out of it entirely and the page is offset instead.

   The offset is `.sg-has-strip body { padding-top }` below. All three tools
   and the app set box-sizing:border-box globally, so a body already sized
   `height:100vh` (the mapper) keeps its full-viewport height and simply loses
   40px from its content box, which is exactly what's wanted. */
.sg-strip {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 16px;
  height: 40px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-ui);
  font-size: 13px;
  /* The tools set their own body font-size and line-height; pin both so the
     strip is identical across all four surfaces regardless of what it lands in. */
  line-height: 1;
  /* Above anything a tool draws -- the mapper has floating panels and the
     calculator has sticky headers, both of which would otherwise cross it. */
  z-index: 9999;
}

/* Keyed off the strip actually being present rather than a class someone has
   to remember to set. That matters because the strip is deliberately absent
   inside /wk/admin, where the app's own bar absorbs it -- with a class, the
   offset would linger there and leave a 40px gap under nothing. */
body:has(> .sg-strip) {
  box-sizing: border-box;
  padding-top: 40px;
}

.sg-strip__brand {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.sg-strip__brand:hover { color: var(--accent); }
.sg-strip__mark {
  width: 16px;
  height: 16px;
  border-radius: 3px;
  background: var(--accent-solid);
  display: inline-block;
  flex: none;
}

/* --- tools dropdown -------------------------------------------------------
   The five tools used to sit inline across the strip. That worked until the
   account block arrived on the right: at ~860px the two together overran the
   bar and clipped the current tab mid-word. Rather than keep trading width
   between them, the tools fold behind the wordmark -- the same move the admin
   bar already makes (src/components/tools-menu.tsx), for the same reason.

   Written as plain classes, not Tailwind, because public/tools/nav.js styles
   the four static tools from this file and has no build step to compile
   utilities. The app's strip uses these same classes so the two stay
   identical. The admin's ToolsMenu keeps its own Tailwind copy: different bar,
   different sizing, and it predates this. */
.sg-strip__menu { position: relative; flex: none; }
.sg-strip__menubtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 8px;
  margin-left: -8px;            /* optical: keep the mark on the page's edge */
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .15s, color .15s;
}
.sg-strip__menubtn:hover { background: var(--surface-2); color: var(--accent); }
.sg-strip__menubtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sg-strip__chev {
  font-size: 10px;
  color: var(--text-muted);
  transition: transform .15s;
}
.sg-strip__menubtn[aria-expanded="true"] .sg-strip__chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .sg-strip__chev { transition: none; } }

.sg-strip__menupanel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 232px;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
}
.sg-strip__menuitem {
  display: block;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.sg-strip__menuitem:hover { background: var(--surface-2); }
.sg-strip__menuitem:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.sg-strip__menuitem[aria-current="page"] { color: var(--accent); font-weight: 600; }
.sg-strip__menuitem--hub { color: var(--text-dim); }
.sg-strip__menusep { height: 1px; margin: 4px 0; background: var(--border); }

/* --- account, pinned right -------------------------------------------------
   Sign-in state belongs to the site, not to whichever tool you happen to be
   standing in. It lived inside the Hero Speciality planner first, which meant
   four other tools could save nothing and never said why, and a signed-in
   visitor had no way to tell which account they were on or to leave it.

   flex: none so it never shrinks when __links overflows and scrolls; the links
   give up space first, because the account is one short string and they are a
   list that already scrolls internally. */
.sg-strip__account {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  white-space: nowrap;
}
.sg-strip__user {
  color: var(--text-muted);
  /* An email can be long; the strip is 40px and must not wrap. */
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Sign out has to be a <button> because it POSTs with a CSRF token, but it
   should carry a link's weight, not a button's. */
.sg-strip__signout {
  background: none;
  border: 0;
  padding: 6px 9px;
  border-radius: var(--r-sm);
  font: inherit;
  color: var(--text-dim);
  cursor: pointer;
  transition: color .15s, background-color .15s;
}
.sg-strip__signout:hover { color: var(--accent); background: var(--accent-dim); }
.sg-strip__signout[disabled] { opacity: .5; cursor: default; }
.sg-strip__signin {
  display: inline-block;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  color: var(--accent);
  background: var(--accent-dim);
  border: 1px solid var(--accent-border);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .15s;
}
.sg-strip__signin:hover { background: var(--accent-glow); }
.sg-strip__signout:focus-visible,
.sg-strip__signin:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* The address is the first thing to go when space is tight. It used to go at
   1100px, back when five tool links sat inline and left the account block
   nothing to work with. Folding the tools into the dropdown freed roughly
   400px, so the strip is now a ~200px button and a ~260px account block and
   the address survives down to phone widths. Sign out always stays; it is the
   control, and which account you are on is one click away on the account
   page. */
@media (max-width: 600px) {
  .sg-strip__user { display: none; }
}
