/* ═══════════════════════════════════════════════════════════════════════════
   NameCrit shared generator stylesheet — schema v1
   Every generator page loads this and nothing else. Transcribed from
   wow-name-generator/index.html, which carried the newest rules (tone die,
   display faces, blood button, consent modal); the six-line differences the
   other pages had were drift, not intent.

   ONE SUBSTITUTION, deliberate: pages used --gold and --accent interchangeably
   for the same job — WoW hardcoded --gold, Valheim set --accent per biome and
   used that. Everything highlight-coloured now reads --accent, which defaults
   to the house gold. A game with a theme overrides it per axis value; a game
   without one never notices.

   ⚠️ This file is styling ONLY. No content, no copy, no per-game rules. The
   editorial is HTML in the page because it is the content that ranks, and a
   crawler that does not execute script must still see it.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  --bg:#0e1015;--panel:#171a23;--panel2:#1e2230;--ink:#e8e6df;--dim:#8b8fa3;
  --gold:#e8b34b;--teal:#4bc8b4;--red:#e05252;--border:#2a2f40;
  --accent:#e8b34b;                        /* themed per axis value; falls back to gold */
  --toneFont:'Segoe UI',system-ui,sans-serif;--toneScale:1;--toneLH:1.35
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--ink);font-family:'Segoe UI',system-ui,sans-serif;
  line-height:1.6;min-height:100vh;transition:background 1s}
.wrap{max-width:780px;margin:0 auto;padding:28px 16px}

/* ── the shared navbar (generated by Process/apply_navbar.js) ── */
.banner{min-height:12vh;min-height:max(12vh,93px);background:linear-gradient(90deg,rgba(14,16,21,0) 0%,rgba(14,16,21,.62) 15%,rgba(14,16,21,.62) 85%,rgba(14,16,21,0) 100%),var(--bg) url('/assets/banner.webp') center/cover no-repeat;border-bottom:1px solid var(--border);display:flex;align-items:center}
.banner-inner{width:100%;max-width:860px;margin:0 auto;padding:8px 18px}
.banner nav{margin-bottom:0}
nav{display:flex;justify-content:space-between;align-items:center}
nav a:not(.logo){color:var(--dim);text-decoration:none;margin-left:18px;font-size:.9rem}
nav a:hover{color:var(--ink)}
nav a.ach{position:relative;display:inline-flex;align-items:center;vertical-align:middle;line-height:0}
nav a.ach img{display:block;width:40px;height:40px}
nav a.ach .achn{position:absolute;top:-2px;right:-6px;min-width:15px;padding:1px 4px;border-radius:8px;background:var(--gold,#e8b34b);color:#412402;font-size:11px;line-height:1.35;font-weight:700;text-align:center}
@media(max-width:700px){
  nav a.ach img{width:34px;height:34px}
  .banner{background-image:linear-gradient(90deg,rgba(14,16,21,.62) 0%,rgba(14,16,21,.62) 100%),url('/assets/banner-mobile.webp');min-height:0;padding:10px 0}
  .banner nav{flex-wrap:wrap;justify-content:center;gap:6px 0}
  .banner nav .logo img{height:42px!important}
  .banner nav a:not(.logo){margin:0 9px;font-size:.85rem}
}
/* ── end shared navbar ── */

/* ── chrome ──────────────────────────────────────────────────────────────── */
nav{display:flex;justify-content:space-between;align-items:center;margin-bottom:28px}
nav .logo{font-weight:800;font-size:1.1rem;text-decoration:none;color:var(--ink)}
nav .logo span{color:var(--accent)}
nav a:not(.logo){color:var(--dim);text-decoration:none;margin-left:16px;font-size:.88rem}
h1{font-size:1.65rem;line-height:1.25}

/* ── the game head ───────────────────────────────────────────────────────────
   One H1 holding three things: the game's own logo, the head term as a small gold
   kicker, and the tagline at display size. Emitted by Process/build_page.js.

   ⚠️ EVERY WORD IS LIVE TEXT. The kicker is demoted VISUALLY and not otherwise —
   nothing is clipped, nothing lives in an alt attribute. Beside a game's logo the
   head term reads as a second title if it is set at the same weight as the tagline,
   which is the only problem being solved here.

   The logo is optional: no file, no <img>, and the grid of kicker-over-tagline still
   reads correctly. A game whose mark is never cleared for use must not look like a
   game whose mark failed to load. */
.gamehead{display:grid;grid-template-columns:auto 1fr;gap:0 20px;align-items:center}
.gamehead .gamemark{grid-row:1/3;height:56px;width:auto;max-width:190px;object-fit:contain}
.gamehead .kicker{grid-column:2;align-self:end;font-size:.8rem;font-weight:700;
  text-transform:uppercase;letter-spacing:.14em;color:var(--accent);line-height:1}
.gamehead .tag{grid-column:2;align-self:start;font-size:1.65rem;line-height:1.22;margin-top:8px}
/* No logo: the two spans collapse into a single column rather than leaving a gutter
   where an image would have been. */
.gamehead:not(:has(.gamemark)){grid-template-columns:1fr}
.gamehead:not(:has(.gamemark)) .kicker,
.gamehead:not(:has(.gamemark)) .tag{grid-column:1}
@media(max-width:560px){
  /* Below this the logo and the tagline are fighting over ~300px and both lose, so the
     mark goes above the words rather than beside them. */
  .gamehead{grid-template-columns:1fr}
  .gamehead .gamemark{grid-row:auto;grid-column:1;height:44px;margin-bottom:12px}
  .gamehead .kicker,.gamehead .tag{grid-column:1}
  .gamehead .tag{font-size:1.4rem}
}
.updated{color:var(--dim);font-size:.8rem;margin-top:6px}
footer{margin-top:56px;border-top:1px solid var(--border);padding-top:18px;color:var(--dim);font-size:.78rem}
footer a{color:var(--dim)}

/* ── controls ────────────────────────────────────────────────────────────── */
.card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px;margin-top:18px}
label{display:block;font-size:.76rem;text-transform:uppercase;letter-spacing:.12em;color:var(--dim);margin-bottom:6px}
select,input[type=text]{width:100%;background:var(--panel2);color:var(--ink);
  border:1px solid var(--border);border-radius:6px;padding:9px;font-size:.95rem}
.row{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:18px;margin-top:14px;align-items:start}
.row:first-child{margin-top:0}

/* THE GENERATOR HEAD — two halves, and the split is deliberate.
   LEFT: everything selectable, stacked, in one column. RIGHT: the die, and nothing else.
   The first attempt used the generic auto-fit .row grid, which flowed "Build me a…" under
   the die and squeezed it to about 170px. The die is the product's face; it gets half the
   card and keeps it. */
.gen{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:22px;align-items:start}
.gen .controls>div+div{margin-top:14px}
.gen .tone{position:sticky;top:0}
/* Fill the half rather than sitting at a fixed 340px inside it. */
.gen .tone .tri svg{width:100%;max-width:none;height:auto;display:block;margin:0 auto}

@media (max-width:640px){
  /* One column on a phone: the die below the controls, not beside them at 45px wide. */
  .gen{grid-template-columns:1fr;gap:18px}
  .gen .tone{position:static}
  .gen .tone .tri svg{max-width:340px}
}
.seg{display:flex;flex-wrap:wrap;gap:8px}
.seg button{background:var(--panel2);border:1px solid var(--border);color:var(--ink);
  padding:7px 13px;border-radius:20px;cursor:pointer;font-size:.88rem}
.seg button.on{background:var(--accent);color:#14161d;border-color:var(--accent);font-weight:600}
.seg button.tog.on{background:var(--teal);border-color:var(--teal)}
details{margin-top:16px}
summary{cursor:pointer;color:var(--teal);font-size:.9rem;user-select:none}
.more{margin-top:14px;display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px}
/* Axis controls are built by generator.js from GAME.axes; these two wrappers are the
   only markup a page has to provide for them. */
#hardWrap>div+div,#deepWrap>div+div{margin-top:14px}
#deepWrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px}
#deepWrap>div+div{margin-top:0}
.caphint,.labelnote{font-size:.74rem;color:var(--dim);margin-top:6px}

/* The generate button. Fixed height on purpose: six display faces have six different
   metrics, and padding-based sizing made the button grow and shrink as tone changed. */
.go{margin-top:20px;width:100%;background:var(--accent);color:#14161d;border:4px solid #000;
  border-radius:10px;height:54px;padding:0 14px;font-weight:700;cursor:pointer;
  display:flex;align-items:center;justify-content:center;line-height:1;
  overflow:hidden;white-space:nowrap;
  font-family:var(--toneFont);font-size:calc(1.05rem*var(--toneScale))}
.go:active{transform:translateY(1px)}
/* Full Send: the whole button is artwork — bar, keyline, gloss and drips in one piece.
   The element goes transparent and the image sits behind the label. Height is FIXED and
   the background stretched to fill, so a narrow screen squeezes the drips horizontally
   rather than shortening them; with 'auto' they got shorter as the viewport narrowed. */
.go.fs{background:transparent;border:none;border-radius:0;color:#fff;position:relative;
  overflow:visible;text-shadow:0 2px 3px rgba(0,0,0,.6);isolation:isolate}
.go.fs::after{content:"";position:absolute;left:0;right:0;top:-1px;height:177px;
  pointer-events:none;z-index:-1;background-repeat:no-repeat;background-position:center top;
  background-size:100.2% 100%;background-image:url("/assets/blood-button.png")}
@media (prefers-reduced-motion:reduce){.go.fs::after{transition:none}}

/* ── the tone die ────────────────────────────────────────────────────────── */
.tri{display:block;margin-top:2px;-webkit-user-select:none;-moz-user-select:none;user-select:none}
.tri svg{touch-action:none;cursor:crosshair;flex:0 0 auto;-webkit-tap-highlight-color:transparent}
.tri svg text{-webkit-user-select:none;user-select:none;pointer-events:none}
.tri svg:focus{outline:2px solid var(--teal);outline-offset:3px;border-radius:6px}
.tri .ro{margin-top:10px;text-align:center}
/* Fixed box. Six faces have six different line-box heights and Full Send runs at a
   different size again — without this the card resized on every tone change. */
.tri .tname{font-family:var(--toneFont);font-size:1.15rem;font-weight:700;color:var(--accent);
  line-height:1.3;white-space:nowrap;transition:color .25s;
  height:34px;display:flex;align-items:center;justify-content:center}
/* Nosifer is a display face — unreadable at body size, and very wide; "Anatomical Full
   Send" is 21 characters. Sized to stay on one line inside the tone column. */
/* The Full Send readout is TEXT, so it takes the signature red rather than the artwork red.
   #a92320 measured 2.67:1 here and failed WCAG AA outright — the same trap as the signature. */
.tri .tname.fs{font-weight:400;font-size:.82rem;line-height:1.3;letter-spacing:0;color:#fa0600}
.tri .tmix{color:var(--dim);font-size:.72rem;margin-top:3px;font-variant-numeric:tabular-nums}

/* ── results and shortlist ───────────────────────────────────────────────── */
ul.results{list-style:none;margin-top:6px}
ul.results li{display:flex;justify-content:space-between;align-items:center;gap:10px;
  background:var(--panel2);border:1px solid var(--border);border-radius:8px;
  padding:10px 14px;margin-top:8px;font-size:1.02rem}
ul.results li .nm{font-family:var(--toneFont);font-size:calc(1.02rem*var(--toneScale));
  line-height:var(--toneLH);display:block}
ul.results li .flavor{display:block;font-size:.75rem;color:var(--dim);margin-top:2px;font-style:italic}
/* Over-cap warning. Pages had two class names for this — .warn on WoW, .over on Valheim.
   One name now; the engine emits .warn. */
ul.results li .warn{color:var(--red);font-style:normal}
ul.results li button{background:none;border:1px solid var(--border);color:var(--teal);
  border-radius:6px;padding:5px 10px;cursor:pointer;font-size:.8rem;white-space:nowrap}
#tray .chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
#tray .chip{background:var(--panel2);border:1px solid var(--border);border-radius:16px;
  padding:5px 12px;font-size:.85rem;display:flex;align-items:center;gap:8px}
#tray .chip b{color:var(--accent);cursor:pointer}
#tray .actions{margin-top:12px;display:flex;gap:10px}
#tray .actions button{background:var(--panel2);border:1px solid var(--border);color:var(--teal);
  border-radius:6px;padding:7px 12px;cursor:pointer;font-size:.84rem}

/* ── toast ───────────────────────────────────────────────────────────────── */
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:26px;background:#20242f;
  border:1px solid var(--accent);color:var(--ink);padding:12px 18px;border-radius:8px;
  font-size:.9rem;box-shadow:0 6px 24px rgba(0,0,0,.5);opacity:0;transition:opacity .3s;
  pointer-events:none;max-width:90vw}
.toast b{color:var(--accent)}
.toast.show{opacity:1}

/* ── the crude-corner consent modal ──────────────────────────────────────── */
.fsmask{position:fixed;inset:0;background:rgba(6,8,12,.78);display:none;align-items:center;
  justify-content:center;padding:20px;z-index:60}
.fsmask.on{display:flex}
.fsbox{background:var(--panel);border:1px solid var(--red);border-radius:12px;max-width:430px;
  padding:22px;box-shadow:0 18px 50px rgba(0,0,0,.6)}
.fsbox h3{color:var(--red);font-size:1.15rem;margin-bottom:10px;letter-spacing:.01em}
.fsbox p{color:#c9c7bf;font-size:.92rem}
.fsbox p+p{margin-top:9px}
.fsbtns{display:flex;gap:10px;margin-top:18px;flex-wrap:wrap}
.fsbtns button{flex:1 1 150px;border-radius:8px;padding:11px 14px;font-size:.92rem;
  cursor:pointer;border:1px solid var(--border)}
.fsbtns .yes{background:var(--red);border-color:var(--red);color:#fff;font-weight:700}
.fsbtns .no{background:var(--panel2);color:var(--ink)}

/* THE SIGNATURE. Third-person self-reference, in the die's own face and blood red — see
   VOICE.md 3.1. Sparing by rule: it is a spike, and a spike used twice on a page is a texture.
   #fa0600 rather than the #a92320 sampled from the die artwork, which measures 2.67:1 here and
   fails WCAG AA as body text; this is the same hue and saturation pushed to full saturation at 4.61:1.
   Sized at .82em with its own line-height because Nosifer's ink area is far taller than the
   body text and at 1em it shoves the surrounding lines apart. Single weight only — asking for
   bold gets a synthesised one that thickens the drips into mud. */
.dice{font-family:'Nosifer',cursive;color:#fa0600;font-size:1.08em;line-height:1;
  letter-spacing:.01em;white-space:nowrap}

/* ── the editorial ───────────────────────────────────────────────────────── */
article{margin-top:48px;color:#c9c7bf;font-size:.95rem}
article h2{color:var(--ink);font-size:1.25rem;margin:28px 0 8px}
article p+p{margin-top:10px}
article ul{margin-top:10px;padding-left:20px}
article li+li{margin-top:6px}
.note{background:var(--panel);border-left:3px solid var(--teal);padding:12px 16px;
  border-radius:0 8px 8px 0;margin-top:14px;font-size:.9rem;color:var(--dim)}

@media (max-width:700px){
  .wrap{padding:20px 14px}
  nav{flex-wrap:wrap;justify-content:center;gap:10px 0;margin-bottom:22px}
  nav .logo img{height:58px!important}
  nav a:not(.logo){margin:0 9px}
  h1{font-size:1.4rem}
  .card{padding:16px}
  /* 16px minimum stops iOS Safari zooming the whole page on input focus */
  select,input[type=text]{font-size:16px;padding:11px}
  .seg button{padding:10px 15px;font-size:.9rem}
  .go{height:58px;padding:0 12px}
  .tri .tname.fs{font-size:.72rem}
  ul.results li{padding:12px}
  ul.results li>div{min-width:0;overflow-wrap:anywhere}
  ul.results li button{padding:9px 12px}
  #tray .actions{flex-wrap:wrap}
  #tray .actions button{padding:10px 12px}
  #tray .chip{padding:7px 12px}
  article h2{font-size:1.15rem}
}

/* ── THE RATINGS PROMPT ──────────────────────────────────────────────────────
   Shipped 24 Aug 2026 with its markup and WITHOUT these rules, so the prompt
   rendered as raw browser defaults on every generator page: system buttons, a
   monospace textarea, everything inline. Exactly the failure commit e6e14a8
   recorded for the navbar — "the generator pages received the markup while
   assets/generator.css had no .banner rules at all". Markup shipping without its
   styling is the same half-a-change as versioning two assets out of five.

   Deliberately quiet. This is a prompt the visitor did not ask for, appearing
   after ten rolls, and it must read as an aside rather than a demand — a loud
   modal-looking block here would cost more goodwill than the answer is worth.
   The pair buttons reuse .seg's pill shape so the control vocabulary matches
   the tone die rather than inventing a second language for one panel. */
.ncrate{border-color:var(--border);border-left:3px solid var(--accent)}
.ncrate-q{margin:0 0 14px;color:var(--dim);font-size:.92rem;line-height:1.5;max-width:60ch}

/* Two independent axes — quality and funniness — so they sit on their own rows.
   They are two questions, not four points on one scale, and a single row of four
   buttons would read as one choice. */
.ncrate-ax{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.ncrate-ax button{background:var(--panel2);border:1px solid var(--border);color:var(--ink);
  padding:7px 13px;border-radius:20px;cursor:pointer;font-size:.88rem;
  font-family:inherit;line-height:1.2}
.ncrate-ax button:hover{border-color:var(--accent)}
.ncrate-ax button.on{background:var(--accent);color:#14161d;border-color:var(--accent);
  font-weight:600}

/* Submittable with everything empty (Lenny, 24 Aug), so the textarea must not
   look compulsory. Vertical resize only: horizontal dragging breaks the card. */
#ncRateText{display:block;width:100%;box-sizing:border-box;margin:12px 0 12px;
  background:var(--panel2);color:var(--ink);border:1px solid var(--border);
  border-radius:6px;padding:10px;font-family:inherit;font-size:.9rem;line-height:1.45;
  resize:vertical;min-height:64px}
#ncRateText::placeholder{color:var(--dim);opacity:1}
#ncRateText:focus{outline:none;border-color:var(--accent)}

.ncrate button#ncRateSend,.ncrate button#ncRateNo{background:var(--panel2);
  border:1px solid var(--border);color:var(--teal);border-radius:6px;padding:8px 14px;
  cursor:pointer;font-size:.86rem;font-family:inherit}
.ncrate button#ncRateSend{border-color:var(--teal)}
.ncrate button#ncRateSend:hover{background:var(--teal);color:#14161d}
/* "Leave it" is dimmed, not hidden. Declining must be as easy as answering, or
   the prompt is a nag and the data it collects is resentment. */
.ncrate button#ncRateNo{color:var(--dim);margin-left:8px}
.ncrate button#ncRateNo:hover{color:var(--ink);border-color:var(--dim)}

@media (max-width:560px){
  .ncrate button#ncRateSend,.ncrate button#ncRateNo{padding:10px 14px}
  .ncrate-ax button{padding:9px 14px}
}

/* ── the "Taken?" check (18 Sep 2026) ──────────────────────────────────────
   Three states, and the neutral one is deliberately NOT green. The endpoint can prove a
   name is taken and cannot prove one is free, so "No record" must never wear the colour
   of a success. Amber reads as "we don't know", which is the truth. */
.chk{margin-left:8px;font-size:.78rem;padding:6px 10px;white-space:nowrap}
.chk.taken{border-color:#8a3b3b;color:#e59a9a}
.chk.unknown{border-color:#8a6a2a;color:#e8b34b}
.chk[disabled]{opacity:.6}

/* ── lock-and-reroll (18 Sep 2026) ───────────────────────────────────────────
   Every part of a generated name is a tap target that pins it. The dotted rule is the
   affordance, and it is always visible because a phone has no hover to reveal it. A
   pinned part takes the axis accent and a padlock, so it reads as held on every row. */
ul.results li .nm .pt{cursor:pointer;border-bottom:1px dotted var(--dim);transition:color .15s,border-color .15s}
ul.results li .nm .pt:hover{border-bottom-color:var(--ink)}
ul.results li .nm .pt:focus-visible{outline:1px dashed var(--dim);outline-offset:2px}
ul.results li .nm .pt.on{color:var(--accent);border-bottom:2px solid var(--accent)}
ul.results li .nm .pt.on::before{content:"\1F512";font-size:.6em;vertical-align:.25em;margin-right:.2em}
#startsWith:disabled{opacity:.45;cursor:not-allowed}

/* ⚠️ Make the `hidden` attribute actually hide, 23 Sep 2026. It did not, and that is how the
   Dungeon Crawler Carl page shipped its suppressed "More options" drawer FULLY VISIBLE for an
   hour: `.more` sets display:grid, which beats the browser's own [hidden]{display:none}, so the
   attribute was decorative. Declared here AFTER .more — equal specificity, later wins — rather
   than with !important, so a deliberate inline style can still override it.
   Safe for the one other user of the attribute: achievements.js toggles .achn by
   removeAttribute/setAttribute, never by style, so this strengthens that behaviour. */
[hidden]{display:none}
