/* dialog.css — the shared modal and account-dialog primitives, loaded by
   every page (trainer, guide, landing). Extracted verbatim from style.css in
   landing phase 6 so the landing can host the real account dialog without
   pulling in the whole trainer stylesheet. Colors are tokens only.

   The .zoom[hidden] rule is load-bearing: an author `display` beats the
   hidden attribute's UA rule (bugs.md, 2026-08-11) — do not remove it. */

.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}

/* Works on both <button class="btn"> and <a class="btn"> (the intro page uses links). */
.btn{
  background:var(--accent);color:#fff;border:0;border-radius:9px;padding:10px 18px;
  font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;line-height:1.3
}
.btn:hover{filter:brightness(1.08)}
.btn.ghost{background:var(--panel2);color:var(--ink);border:1px solid var(--line)}
.btn.sm{padding:7px 13px;font-size:13px}
.btn:disabled{opacity:.4;cursor:default}

.zoom{
  position:fixed;inset:0;background:rgba(0,0,0,.62);backdrop-filter:blur(3px);
  display:grid;place-items:center;padding:20px;z-index:100;
}
/* An author `display` beats the hidden attribute's UA rule, so a persistent
   dialog toggled with `hidden` would stay on screen. This is what makes
   element.hidden actually work. */
.zoom[hidden]{display:none}
.zoom-panel{
  background:var(--panel);border:1px solid var(--line);border-radius:18px;
  padding:28px 26px 22px;max-width:440px;width:100%;text-align:center;position:relative;
  max-height:88vh;overflow-y:auto;
  box-shadow:0 24px 64px -16px var(--shadow2);
}
.zoom-x{
  position:absolute;top:12px;right:12px;background:none;border:0;color:var(--dim);
  font-size:22px;line-height:1;cursor:pointer;padding:6px 10px;border-radius:9px;
}
.zoom-x:hover{color:var(--ink);background:var(--panel2)}

.acct{max-width:400px;text-align:left;padding:30px 28px 24px}
.acct h3{margin:0 0 6px;color:var(--ink);text-transform:none;letter-spacing:-.01em;
  font-size:21px;font-weight:700}
.acct p{font-size:13px;color:var(--dim);margin:0 0 18px;line-height:1.6}
.acct label{display:block;font-size:12px;font-weight:600;color:var(--dim);margin:0 0 6px}
.acct input{
  width:100%;background:var(--panel2);border:1px solid var(--line);color:var(--ink);
  border-radius:10px;padding:11px 13px;font-size:14px;margin-bottom:14px;font-family:inherit;
  transition:border-color .15s,box-shadow .15s;
}
.acct input:hover{border-color:var(--line2)}
/* Focus is FOCUS, in the link blue — never the vermilion accent. The old rule
   painted the focused field brand-red, and since the dialog focuses the email
   field the moment it opens, the very first thing anyone saw was what read as
   a validation error on an empty form. accent2 is the same hex in both themes,
   so the fixed-alpha halo holds in dark and light alike. */
.acct input:focus{
  outline:none;border-color:var(--accent2);
  box-shadow:0 0 0 3px rgba(74,158,255,.18);
}
/* "Continue with Google", above the email field, then a labelled rule.
   Full width because it is the primary path for most people, but .ghost so it
   reads as an alternative to the accent-colored submit button rather than
   competing with it. The mark's own colors are inline in account.js — a third
   party's brand is not part of this palette (docs/decisions/0008). */
.acct .oauth{
  width:100%;display:flex;align-items:center;justify-content:center;gap:10px;
  margin:0 0 16px;padding:12px 14px;border-radius:10px;font-size:14px;
  transition:border-color .15s,background .15s;
}
/* brightness() is invisible on a near-white ghost button in the light theme,
   so hover is a border-and-surface shift instead. */
.acct .oauth:hover{filter:none;border-color:var(--line2);background:var(--panel)}
.acct .oauth svg{width:19px;height:19px;flex:none}
/* Keyboard focus has to be visible on a control that is now the first thing in
   the panel and the first thing Tab reaches. */
.acct .oauth:focus-visible{outline:2px solid var(--accent2);outline-offset:2px}

.orbar{display:flex;align-items:center;gap:12px;margin:0 0 16px;color:var(--dim);font-size:12px}
/* Rules drawn with pseudo-elements rather than a border on the word, so the
   two halves stay equal at any panel width and the label stays centred. */
.orbar::before,.orbar::after{content:"";flex:1;height:1px;background:var(--line)}

/* Errors arrive as a tinted chip, not a bare red line — easier to spot, and
   the tint tokens already carry the dark/light split. Empty collapses to
   nothing (the old reserved min-height held a permanent blank stripe in the
   middle of the form) — but via zeroed box, never display:none: this is the
   aria-live region, and a screen reader will not announce text that appears
   inside a node that was undisplayed a moment ago. */
.acct .err{
  background:var(--bad-tint);color:var(--bad-deep);
  border:1px solid var(--bad-tint);border-radius:9px;
  padding:9px 12px;margin:0 0 14px;font-size:12.5px;line-height:1.5;
}
.acct .err:empty{padding:0;border:0;margin:0}

/* A label with a control opposite it — "Password … Forgot?", "New password …
   Show". Baseline alignment, not center: the two have different type sizes and
   aligning their boxes would leave the small one visibly high. */
.labelrow{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin:0 0 4px}
.labelrow label{margin:0}

/* Reads as a link, behaves as a button. Both of these switch view inside the
   dialog and navigate nowhere, so an <a> would be a link to nothing — which is
   the exact reason "Forgot password?" was held back until this shipped. */
.linkish{
  background:none;border:0;color:var(--accent2);font:inherit;font-size:12px;
  cursor:pointer;padding:0;white-space:nowrap
}
.linkish:hover{text-decoration:underline}
.linkish:focus-visible{outline:2px solid var(--accent2);outline-offset:2px;border-radius:3px}

/* Password strength. Advice, never a gate — the only hard rule is the
   10-character minimum, which the server enforces too.

   The score is carried by three things at once: how many bars are filled, what
   colour they are, and the word beside them. Colour alone would say nothing to
   a red-green colourblind reader, and the bars alone say nothing to a screen
   reader — which is what the label is for (role="status" in account.js). */
.pwmeter{display:flex;align-items:center;gap:9px;margin:-4px 0 12px}
/* Load-bearing, exactly as the note at the top of this file describes: the rule
   above sets `display`, which beats the hidden attribute's UA stylesheet, so
   without this the meter would sit on screen with an empty field. */
.pwmeter[hidden]{display:none}
.pwbars{display:flex;gap:3px;flex:1;min-width:0}
.pwbars i{flex:1;height:3px;border-radius:2px;background:var(--line)}
.pwlabel{font-size:11.5px;color:var(--dim);flex:none}

.pwmeter.s1 .pwbars i:nth-child(-n+1){background:var(--bad)}
.pwmeter.s2 .pwbars i:nth-child(-n+2){background:var(--warn)}
.pwmeter.s3 .pwbars i:nth-child(-n+3){background:var(--good)}
.pwmeter.s4 .pwbars i{background:var(--good)}
.pwmeter.s1 .pwlabel{color:var(--bad)}
.pwmeter.s2 .pwlabel{color:var(--warn)}
.pwmeter.s3 .pwlabel,.pwmeter.s4 .pwlabel{color:var(--good)}

/* Something went right — "your password is set, now sign in". The counterpart
   to .err, chip and all, and it has to out-specify `.acct p`. */
.acct .note{
  background:var(--good-tint);color:var(--good-deep);
  border:1px solid var(--good-tint);border-radius:9px;
  padding:9px 12px;margin:0 0 14px;font-size:12.5px;line-height:1.5;
}

/* The form's own actions stack: a full-width primary, the mode switch as a
   centred line under it. Scoped to the FORM — the signed-in panel's .row
   (sync + sign out) stays a horizontal pair. */
.acct form .row{flex-direction:column;align-items:stretch;gap:4px}
.acct form .row .btn{width:100%;padding:12px 16px;border-radius:10px;font-size:14.5px}
.acct .switch{align-self:center}

/* ---- the sign-in gate ----------------------------------------------------
   On a page that needs an account, the dialog IS the page: everything else is
   hidden until there is one. Set by an inline snippet in app.html's <head> so
   the trainer never flashes into view, and removed by js/account.js.

   Content hiding, not access control. The HTML this hides has already been
   delivered, and every lesson bundle under /content/v1/ is a public file —
   docs/bugs.md names exactly what stays fetchable. Do not read this rule as
   securing anything.

   The background matters: body children are hidden before js/account.js has
   built the dialog, so without an explicit token colour that gap paints as the
   browser's own canvas — the bug already logged for the landing on 2026-08-13,
   in a place where it would look like a white flash on a dark theme. */
html.gated body > *:not([data-acct-dialog]){display:none}
html.gated body{background:var(--bg);min-height:100vh}
.acct .switch{background:none;border:0;color:var(--accent2);font-size:13px;cursor:pointer;padding:8px 0 0}
.acct .switch:hover{text-decoration:underline}
.acct .who{font:600 14px var(--jp);color:var(--ink);word-break:break-all}
.syncrow{
  display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dim);
  border-top:1px solid var(--line);margin-top:14px;padding-top:12px;flex-wrap:wrap;
}
.syncdot{width:7px;height:7px;border-radius:99px;background:var(--dim);flex:none}
.syncdot.ok{background:var(--good)} .syncdot.off{background:var(--warn)}

/* The leaderboard controls on the signed-in panel. A quiet box: this is a
   setting, not a call to action — the landing page does the selling. */
.boardbox{border-top:1px solid var(--line);margin-top:14px;padding-top:12px}
.boardbox .labelrow span{font-size:12px;font-weight:600;color:var(--dim)}
.checkline{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink);
  margin:8px 0 10px;cursor:pointer}
.checkline input{width:auto;margin:0;accent-color:var(--accent)}
.boardbox input[type="text"]{margin-bottom:10px}
