/* The way in: one look for every page that asks who you are.
 *
 * Created 27 October 2026. The owner picked the website's sign-in design and
 * asked that the rest follow it -- "i want signup page also same like this /
 * and other pages also same ... login related pages should share same UI".
 * Before this, each of them had grown its own: three different buttons, three
 * different input heights, three ideas of what a heading looks like.
 *
 * WHY A FILE OF ITS OWN, and not styles.css. That stylesheet is five thousand
 * lines of generic names and has already produced four collisions, two of them
 * rules both called .modal. Everything here is prefixed au- and lives apart,
 * so nothing in it can reach the application's screens and nothing there can
 * reach these.
 *
 * WHO CAN USE IT. The desktop agent serves a fixed file list (uiserver.ASSETS)
 * and this file is not on it, so a page the agent BUNDLES -- index.html --
 * cannot link it without an agent release. index.html's own sign-in card is
 * therefore styled in styles.css, which is bundled, to the same measurements.
 * Every page here is served by the real server, where a new file is free.
 *
 * THE FONTS ARE SELF-HOSTED, in auth-fonts.css, because the live CSP is
 * default-src 'self': a fonts.googleapis.com link is refused over HTTPS and
 * obeyed on loopback, so the fault would only ever appear in production.
 */

:root {
  --au-ink: #111114;
  --au-text: #1e2430;
  --au-muted: #64748b;
  --au-line: #e2e8f0;
  --au-field: #ffffff;
  --au-bg: #ffffff;
  --au-good: #0f8a66;
  --au-bad: #c2410c;
  --au-focus: rgba(17, 17, 20, .13);
  --au-serif: "Fraunces", Georgia, "Times New Roman", serif;
  --au-sans: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.au-page * { box-sizing: border-box; }

.au-page {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--au-bg);
  color: var(--au-text);
  font: 15px/1.6 var(--au-sans);
  -webkit-font-smoothing: antialiased;
}

/* ── The bar ─────────────────────────────────────────────────────────── */
.au-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 22px 40px;
  flex: none;
}
.au-mark { height: 34px; width: auto; display: block; }
.au-word {
  font-size: 21px; font-weight: 700; letter-spacing: -.03em; color: var(--au-ink);
}
.au-word span { color: #4338ca; }

/* ── The two halves ──────────────────────────────────────────────────── */
/* The form sits left and the picture right, and the picture is decoration:
   it is the first thing to go when the window is too short or too narrow,
   because nothing in it is needed to sign in. */
.au-stage {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 40px;
  width: min(1280px, calc(100vw - 80px));
  margin: 0 auto;
  padding: 0 0 40px;
}
/* The form sits on the RIGHT and the figure on the left, asked for on
   28 October. Done with grid `order` rather than by moving the markup: the
   form comes first in every one of these six documents, which is the order
   it should be read and tabbed through, and that is worth keeping whichever
   side it is drawn on. Changing it here moves all six at once. */
.au-col {
  order: 2;
  max-width: 440px; width: 100%;
  justify-self: start;
  padding-left: 8px;
}

/* Two fields on one line. The signup form is four fields, five rule chips, a
   timezone, a consent box and a button; one per line ran 87px past the bottom
   of a 1920x950 screen, and the owner's requirement is that it "fit in one
   full page". Two short related fields side by side buy that back, and they
   are the two that belong together anyway. Below 560px they stack. */
.au-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
@media (max-width: 560px) { .au-row { grid-template-columns: 1fr; } }
/* The figure is sized by the room there is, in BOTH directions.
 *
 * It used to be sized on width alone and then hidden outright on a short
 * screen -- so on 1280x627, which is a 1920x1080 display at 150% Windows
 * scaling and what the owner actually runs, it vanished and left half the
 * page empty. The form's height is what makes these pages tight, not the
 * figure's: at 627 there is room for a 460px picture beside a form that
 * needs 600. So it stays, and shrinks to whatever height is going.
 *
 * It is still the first thing to go when there is genuinely no room -- see
 * the narrow rule below -- because nothing in it is needed to sign in. */
.au-art { order: 1; justify-self: center; align-self: center; position: relative; }
/* The figure's wrapper takes the size; the parts inside are all relative to
   it. min(350px, 29vw) is the website's own figure width. */
.au-art .cd { width: min(350px, 29vw); }
.au-art img { display: block; width: 100%; height: auto; }

/* ── Type ────────────────────────────────────────────────────────────── */
.au-title {
  font-family: var(--au-serif);
  font-weight: 400;
  font-size: clamp(30px, 2.6vw, 42px);   /* 33px at 1280, measured off the website's own sign-in */
  line-height: 1.04;
  letter-spacing: -.01em;
  color: var(--au-ink);
  margin: 0 0 6px;
}
.au-sub {
  margin: 0 0 26px;
  color: var(--au-muted);
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 42ch;
}

/* ── Fields ──────────────────────────────────────────────────────────── */
.au-field { margin-bottom: 16px; }
.au-label {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 7px;
}
.au-label label, .au-field > label {
  font-size: 14px; font-weight: 500; color: var(--au-text);
}
.au-field input {
  width: 100%; height: 49px; padding: 0 16px;
  border: 1px solid var(--au-line); border-radius: 12px;
  background: var(--au-field); color: var(--au-text);
  font-size: 15px; font-family: inherit;
  transition: border-color .14s, box-shadow .14s;
}
.au-field input::placeholder { color: #9aa6b6; }
.au-field input:focus {
  outline: none;
  border-color: var(--au-ink);
  box-shadow: 0 0 0 4px var(--au-focus);
}
.au-wrap { position: relative; }
.au-wrap input { padding-right: 50px; }
.au-peek {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  border: 0; background: none; cursor: pointer; color: var(--au-muted);
  padding: 8px; border-radius: 8px; line-height: 0;
}
.au-peek:hover { color: var(--au-ink); }
.au-peek:focus-visible { outline: 2px solid var(--au-ink); outline-offset: 1px; }
.au-peek svg { width: 18px; height: 18px; display: block; }

.au-aside {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 13.5px; font-weight: 600; color: var(--au-ink);
}
.au-aside:hover { text-decoration: underline; }

/* ── The rules a password has to meet ────────────────────────────────── */
/* A row of quiet chips that fill in, rather than a list that reads as a
   telling-off before anything has been typed. */
.au-rules {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 7px;
}
.au-rules li {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  border: 1px solid var(--au-line); color: var(--au-muted);
  font-size: 12.5px;
  transition: color .14s, background .14s, border-color .14s;
}
.au-rules li::before {
  content: ""; width: 13px; height: 13px; border-radius: 50%; flex: none;
  border: 1.5px solid currentColor; opacity: .45;
  transition: opacity .14s, background .14s, border-color .14s;
}
/* ── A rule you have not met yet, and a field you have not filled ────
 *
 * The owner, 28 October 2026, looking at /start: "remove those highlighed and
 * add them as warings when the user dont follow them" -- and "missing fields
 * should be highlighted red also warning".
 *
 * So the five password rules are no longer a checklist sitting under the
 * field from the moment the page loads. They are hidden until one of them is
 * BROKEN, and then only the broken ones appear, in the warning colour. A rule
 * that is satisfied says nothing, because there is nothing to say.
 *
 * The list stays complete in the markup. security.py enforces all five, so a
 * rule dropped from here would not be relaxed, it would be hidden -- the form
 * would fall silent on a password the server then refuses.
 */
.au-rules { display: none; }
.au-rules.show { display: flex; }
/* Met is not "green", it is "not worth saying". */
.au-rules.show li.met { display: none; }
.au-rules.show li {
  color: var(--au-bad);
  background: color-mix(in srgb, var(--au-bad) 8%, transparent);
  border-color: color-mix(in srgb, var(--au-bad) 30%, transparent);
}
/* The dot becomes an exclamation rather than an empty circle: the chip is
   telling you something is missing, not offering you a box to tick. */
.au-rules.show li::before {
  opacity: 1; border: 0; border-radius: 1px;
  width: 2px; height: 6px; margin-right: 1px;
  background: currentColor;
  /* the dot under the stroke, so the mark reads as an exclamation */
  box-shadow: 0 4px 0 0 currentColor;
}

/* A field that is wrong says so twice: the border and label turn red, and a
   line of words appears underneath. The colour on its own reports that
   something is wrong without saying what, and reports nothing at all to
   somebody who cannot see it. */
.au-field.bad > label { color: var(--au-bad); }
.au-field.bad input { border-color: var(--au-bad); }
.au-field.bad input:focus {
  border-color: var(--au-bad);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--au-bad) 18%, transparent);
}
.au-note {
  display: none; margin: 7px 0 0;
  font-size: 12.5px; line-height: 1.45; color: var(--au-bad);
}
.au-field.bad .au-note { display: block; }

.au-rules li.met {
  color: var(--au-good);
  background: color-mix(in srgb, var(--au-good) 9%, transparent);
  border-color: color-mix(in srgb, var(--au-good) 28%, transparent);
}
.au-rules li.met::before {
  opacity: 1; border-color: var(--au-good); background: var(--au-good);
  /* Drawn into the dot rather than swapped for an icon, so nothing shifts by
     a pixel as the rules fill in. */
  background-image:
    linear-gradient(45deg, transparent 46%, #fff 46%, #fff 60%, transparent 60%),
    linear-gradient(-45deg, transparent 52%, #fff 52%, #fff 66%, transparent 66%);
}

/* ── Terms ───────────────────────────────────────────────────────────── */
.au-terms {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 18px 0 0; font-size: 13.5px; color: var(--au-muted); line-height: 1.5;
}
.au-terms input {
  width: 17px; height: 17px; margin: 2px 0 0; flex: none;
  accent-color: var(--au-ink); cursor: pointer;
}
.au-terms label { cursor: pointer; }
.au-terms a { color: var(--au-ink); font-weight: 600; }

/* ── The action ──────────────────────────────────────────────────────── */
.au-go {
  width: 100%; margin-top: 20px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 15px 24px; border: 0; border-radius: 12px;
  background: linear-gradient(to bottom right, #3c3c44, #141418);
  color: #fff; font: inherit; font-size: 15px; font-weight: 600;
  cursor: pointer;
  box-shadow: 0 10px 24px -12px rgba(0, 0, 0, .55);
  transition: filter .14s, transform .08s, opacity .14s;
}
.au-go:hover:not(:disabled) { filter: brightness(1.25); }
.au-go:active:not(:disabled) { transform: translateY(1px); }
.au-go:focus-visible { outline: 2px solid var(--au-ink); outline-offset: 3px; }
.au-go:disabled { opacity: .6; cursor: not-allowed; }
.au-go svg { width: 16px; height: 16px; }

.au-msg { margin-top: 14px; font-size: 13.5px; line-height: 1.5; color: var(--au-bad); }
.au-msg:empty { display: none; }
.au-msg.good { color: var(--au-good); }

/* ── What this product promises, where the password is handed over ───── */
.au-ticks {
  list-style: none; margin: 18px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 22px;
  font-size: 13px; color: var(--au-muted);
}
.au-ticks li { display: inline-flex; align-items: center; gap: 8px; }
.au-ticks li::before {
  content: ""; width: 13px; height: 9px; flex: none;
  border-left: 2px solid var(--au-ink); border-bottom: 2px solid var(--au-ink);
  transform: rotate(-45deg) translate(1px, -2px);
}

.au-foot { margin: 20px 0 0; font-size: 14px; color: var(--au-muted); }
.au-foot a, .au-foot button {
  color: var(--au-ink); font-weight: 600; text-decoration: none;
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
}
.au-foot a:hover, .au-foot button:hover { text-decoration: underline; }

.au-hidden { display: none !important; }

/* ── Narrow and short ────────────────────────────────────────────────── */
/* The picture goes first, and on a short window it goes at any width: the
   owner asked for this to sit on one screen without scrolling, and a
   decorative figure is the one thing here that can be given up to keep it. */
/* Narrow OR short: the picture goes, and the grid goes with it.
 *
 * These two conditions were separate rules, and the short one hid the figure
 * without collapsing the column it sat in. On a 1280x627 viewport -- which is
 * what a 1920x1080 screen at 150% Windows scaling actually gives a browser,
 * and what the owner was looking at -- that left the form crushed into the
 * left half with the right half empty, and the page still scrolled. Reported
 * 28 October with six screenshots.
 *
 * Hiding a grid item does not take its track away. Both conditions have to
 * do both things, which is why they share one rule now rather than sitting
 * apart where only one of them was complete. */
/* The height threshold is 520, not 760. The figure sizes itself to the room
   there is now, so at 627 it simply draws smaller -- and a form flanked by a
   picture reads far better than one marooned in the middle of an empty
   screen. Below 520 there is room for neither and the column collapses. */
@media (max-width: 1020px), (max-height: 520px) {
  .au-stage {
    grid-template-columns: minmax(0, 1fr);
    width: min(560px, calc(100vw - 40px));
  }
  .au-art { display: none; }
  .au-col { max-width: none; justify-self: stretch; padding-left: 0; }
  .au-bar { padding: 20px 24px; }
}
/* A short window. Hiding the picture does not help here -- the form is the
   tall thing, not the figure beside it -- so this takes the air out of the
   form instead, in the order it can best be spared: the standfirst first,
   then the gaps, then the field height. Measured: 1920x800 ran 83px past the
   bottom before this and sits inside it after.
   Below about 700px of viewport the form genuinely does not fit, and it
   scrolls. That is the right answer there: a signup form squeezed until the
   fields are unusable serves nobody, and this is a page somebody visits once. */
/* A short screen gets a little back, not a lot.
 *
 * Two tiers used to live here, and between them they took the fields to 42px,
 * the chips to 12px and the bar to 10px of padding -- all to make the page
 * fit 627. Set beside the website's own sign-in it looked like a page that
 * had been squeezed rather than designed, and the owner said so.
 *
 * Measured against that page on 28 October: its document is 1043px tall in a
 * 627px viewport. It scrolls, and it is the better page for not caring. The
 * fields stay 49px, the heading stays large, the spacing stays generous --
 * what gives is the air between blocks, and only some of it.
 *
 * What still has to hold is that the PRIMARY ACTION is reachable without
 * scrolling. Everything below it -- the promises, the alternate link -- may
 * fall past the fold, because nobody is looking for those before they have
 * typed anything. */
@media (max-height: 760px) {
  .au-stage { align-items: start; padding-top: 6px; padding-bottom: 18px; }
  /* Beside the heading, not halfway down a page that scrolls: with the
     stage taller than the screen, centring put the figure below the fold. */
  .au-art { align-self: start; margin-top: 8px; }
  .au-bar { padding: 14px 40px 10px; }
  .au-sub { margin-bottom: 16px; }
  /* 13px until 28 October. At 1280x627 -- a 1920x1080 screen at the 150%
     Windows scaling the owner runs -- the button's bottom edge came out at
     631, four pixels under the fold, so the form was entirely in view
     except the last sliver of the button. Four fields, three pixels each. */
  .au-field { margin-bottom: 10px; }
  .au-go { margin-top: 14px; }
  .au-ticks { margin-top: 14px; }
  .au-foot { margin-top: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .au-go:active:not(:disabled) { transform: none; }
}

/* ── "You are already signed in, as this person" ─────────────────────── */
/* Used by browsersignin.html, where somebody who is already signed in has
   nothing to type and only a decision to make: authorise this computer, or
   use a different account. Carried over from that page's own stylesheet
   rather than invented, so the card keeps the shape it had -- the avatar
   that showed an initial still shows one, and a long address still gets an
   ellipsis instead of pushing the card wider.

   Drafted alongside the reskin and added BEFORE it, because a class the
   markup uses and the stylesheet has never heard of produces an unstyled
   row with no error anywhere. That is the same shape of fault as the
   toggled classes: silent, and invisible until somebody is looking at it. */
.au-who {
  display: flex; align-items: center; gap: 13px;
  padding: 14px; margin-bottom: 20px;
  border: 1px solid var(--au-line); border-radius: 12px;
  background: color-mix(in srgb, var(--au-line) 22%, transparent);
}
.au-avatar {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--au-ink); color: #fff;
  font-size: 15px; font-weight: 700;
}
.au-who-text { min-width: 0; line-height: 1.4; }
.au-who-text b { display: block; font-size: 14.5px; font-weight: 650; }
.au-who-text span {
  display: block; font-size: 13px; color: var(--au-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── The classes the scripts toggle ──────────────────────────────────── */
/* These go in BEFORE any page is reskinned, not after.
 *
 * Every rule here exists because a script on one of these pages turns a class
 * on and expects the stylesheet to answer. Reskin a page onto auth.css without
 * carrying its rule across and the toggle silently does nothing: the message
 * never appears, the spinner never clears, the card stays blank. There is no
 * error anywhere -- the class is set, it just means nothing.
 *
 * That is not hypothetical. #handover.on was dropped in a restyle of
 * appsignin.html and the sign-in card was blank in production for about an
 * hour. The check that missed it asked whether the stylesheet CONTAINED ".on",
 * and ".online" contains it. test_a_toggled_class_has_a_rule.js exists because
 * of that, and requires a real rule rather than a substring.
 *
 * Taken from each page's own stylesheet, so the behaviour is carried over
 * rather than guessed:
 *     signup.html         .msg.show        { display: block; }
 *     welcome.html        .wc-go.hide      { display: none; }
 *                         .wc-msg.show     { display: block; }
 *     reset.html          .rp-msg.show     { display: block; }
 *     appsignin.html      .msg.show        { display: block; }
 *                         #handover.on     { display: block; }
 *                         .foot.online .dot{ background: var(--good); }
 *                         .foot.offline .dot{ background: var(--bad); }
 *     browsersignin.html  -- toggles no classes at all
 */

/* A message that is written then revealed. auth.css hides an EMPTY .au-msg,
   which covers the pages that only set textContent; these pages set a class
   as well, and both have to work or the message stays invisible. */
.au-msg { display: none; }
.au-msg.show { display: block; }
.au-msg:not(:empty) { display: block; }

/* Something taken away once it has been used -- welcome.html hides its button
   after the address is confirmed, so the page does not invite a second go. */
.hide, .au-go.hide, .au-hide { display: none; }

/* The desktop hand-over panel: hidden until the shell says it has a session.
   Kept as an id rule because appsignin.js toggles the id, and the id is the
   contract. */
#handover { display: none; }
#handover.on { display: block; }

/* The footer's connection dot. Three states and only two classes: no class at
   all means "not yet known", which must not look like either answer. */
.au-foot-state .dot { width: 8px; height: 8px; border-radius: 50%;
                      display: inline-block; background: var(--au-muted); }
.au-foot-state.online .dot { background: var(--au-good); }
.au-foot-state.offline .dot { background: var(--au-bad); }

/* ── One eye, not two ────────────────────────────────────────────────── */
/* Edge and IE draw their own reveal button inside a password field, and
   ::-ms-clear draws an X beside it that offers to discard what somebody has
   typed. Every page here already has a Show control of its own, so the
   native pair is a second eye next to the first.

   The rule lived in styles.css, which these pages loaded until they moved
   onto this stylesheet on 28 October -- so every one of them grew a second
   eye at that moment, /start included. Caught by
   test_one_eye_on_a_password_field.js, which exists because the duplicate
   was reported once already.

   Written against the input rather than the button, because the
   pseudo-element belongs to the input. */
input[type="password"]::-ms-reveal,
input[type="password"]::-ms-clear {
  display: none;
  width: 0;
  height: 0;
}

/* ── The clock detective ─────────────────────────────────────────────── */
/* Ported from the website's ClockDetective component, 28 October 2026. The
   owner, looking at the two side by side: "left side its an image not
   animation". It was the bare .webp; the website wraps it in a faint clock
   face, an orbiting ball, hands that turn, and a tilted label.
   All of it is SVG and CSS -- animateMotion for the ball, a keyframe for the
   hands -- so none of it needed React. The numbers are the component's own,
   including the tick marks, which come from the same formula it uses. */
.au-art .cd { position: relative; }
.au-art .cd > img { position: relative; z-index: 10; display: block; width: 100%;
  filter: drop-shadow(0 30px 45px rgba(40, 30, 15, .18)); }

/* The faint clock behind the figure's head. */
.cd-face { position: absolute; left: 50%; top: 3%; z-index: 0;
  width: 90%; transform: translateX(-50%); color: #dcdbe6;
  pointer-events: none; }
.cd-face circle { stroke: currentColor; stroke-width: 1; fill: none; }
.cd-face line { stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }

/* The orbit, and the ball that runs round it. */
.cd-orbit { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%;
  overflow: visible; pointer-events: none; }

/* The hands, over the clock in the figure's face. */
.cd-hands { position: absolute; left: 53%; top: 23.3%; z-index: 20; width: 34%;
  transform: translate(-50%, -50%); pointer-events: none; }
.clock-hand { transform-box: view-box; transform-origin: 50px 50px; }
.ch-hour { animation: cd-spin 108s linear infinite; }
.ch-min  { animation: cd-spin 36s linear infinite; }
.ch-sec  { animation: cd-spin 6s linear infinite; }
@keyframes cd-spin { to { transform: rotate(360deg); } }

/* The label, upper-left and tilted with the orbit. */
.cd-label { position: absolute; left: -18%; top: 6%; z-index: 20;
  transform: rotate(-16deg);
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  line-height: 1.7; letter-spacing: .14em; color: #8b8a95; }

@media (prefers-reduced-motion: reduce) {
  .ch-hour, .ch-min, .ch-sec { animation: none; }
  .cd-orbit animateMotion { display: none; }
}
