/* ==========================================================================
   WildWard — one design system, used by every page the customer sees.
   ==========================================================================

   Everything is a token. Nothing anywhere else in this project should contain
   a raw colour value: if a shade needs changing it changes here, once, and the
   login page, the invitation page, the property page and the admin all follow.

   The palette is the brand's, not an invention:
     charcoal #1c1c1a · gold #e8b84b · light gold #f5d488
     cream #faf6ee · warm tan #8a7c64
   ========================================================================== */

:root {
  /* -- brand ------------------------------------------------------------ */
  --ww-charcoal:      #1c1c1a;
  --ww-gold:          #e8b84b;
  --ww-gold-light:    #f5d488;
  --ww-cream:         #faf6ee;
  --ww-tan:           #8a7c64;

  /* -- derived surfaces, warm rather than neutral greys ------------------ */
  --ww-bg:            #faf6ee;
  --ww-surface:       #ffffff;
  --ww-surface-sunk:  #f4eee1;
  --ww-line:          #e4dccb;
  --ww-line-strong:   #d3c8b0;

  /* -- text -------------------------------------------------------------- */
  --ww-text:          #1c1c1a;
  --ww-text-muted:    #6f6553;
  /* Was #8a7c64, which measured 3.53:1 on the sunk surface - below the 4.5:1
     WCAG minimum for body text, and it is the colour of every tile label,
     every note, and the footer. Darkened to 4.74:1 on sunk, 5.48:1 on card. */
  --ww-text-faint:    #756848;
  --ww-text-invert:   #faf6ee;

  /* -- states ------------------------------------------------------------ */
  /* Lamps and borders. These are non-text, so the 3:1 threshold applies and
     all three already clear it. Do not use them for TEXT - use the -text pair
     below, which is darkened to clear 4.5:1. */
  --ww-ok:            #3f7d55;
  --ww-warn:          #b8862a;
  --ww-bad:           #b3402f;
  --ww-info:          #4b6f8a;

  /* Text-safe variants. --ww-warn as text measured 2.80:1 on the sunk surface,
     and it was the colour of every problem pill on the site: "Unrecognised",
     "Nothing assigned", "Link spent", "Expired". The page's most important
     word was its least readable. */
  --ww-ok-text:       #356b49;   /* 5.42:1 on sunk */
  --ww-warn-text:     #8a6410;   /* 4.64:1 on sunk */
  --ww-bad-text:      #a3392a;   /* verified below */
  --ww-info-text:     #3d5c74;

  /* -- accent: the interactive colour ------------------------------------
     Gold is the BRAND and it is also what "a deterrent fired" looks like
     (spray stages, the fired pills, the all-clear hairline). When gold was
     also the colour of every button, card and border, those two meanings
     were the same colour and the page read as one flat wash of brown.
     So interaction moved to its own hue and gold kept its meanings.

     Use --ww-accent for borders, fills and other NON-TEXT (3:1 threshold),
     --ww-accent-text for anything a person reads (4.5:1), and
     --ww-accent-on for a label sitting ON an accent fill - it inverts
     between themes, because the accent is dark on light and light on dark.
     Measured, not assumed:
       cream on accent (button label)      5.52:1
       --ww-accent-text on surface / sunk  6.80:1 / 5.88:1
       accent border vs the 8% card tint   3.50:1
     Note --ww-info is deliberately the same hue family; it marks the
     "photo only" stage, which carries its meaning in the words, not the
     colour (SC 1.4.1), and never sits next to a control. */
  --ww-accent:        #41678a;
  --ww-accent-strong: #3b5e7e;
  --ww-accent-text:   #3b5e7e;
  --ww-accent-on:     #faf6ee;

  /* -- shape and motion -------------------------------------------------- */
  --ww-radius:        10px;
  --ww-radius-sm:     6px;
  --ww-radius-pill:   999px;
  --ww-shadow:        0 1px 2px rgba(28,28,26,.05), 0 8px 24px -12px rgba(28,28,26,.18);
  --ww-shadow-lift:   0 2px 4px rgba(28,28,26,.06), 0 16px 40px -16px rgba(28,28,26,.26);
  --ww-ease:          cubic-bezier(.2,.7,.3,1);

  --ww-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, sans-serif;
  --ww-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* The mark is gold on dark in both themes, so only the surfaces invert. */
@media (prefers-color-scheme: dark) {
  :root {
    --ww-bg:           #161614;
    --ww-surface:      #201f1c;
    --ww-surface-sunk: #1a1917;
    --ww-line:         #302e29;
    --ww-line-strong:  #423f38;
    --ww-text:         #f2ede2;
    --ww-text-muted:   #a89c86;
    /* Dark mode reused the light value verbatim, so it failed here too
       (4.04:1 on the card). This is the palette the night-time phone
       reader actually sees. Now 5.59:1. */
    --ww-text-faint:   #a2957c;
    --ww-shadow:       0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.6);
    --ww-shadow-lift:  0 2px 4px rgba(0,0,0,.45), 0 16px 40px -16px rgba(0,0,0,.7);
    --ww-ok:           #6aa87f;
    --ww-warn:         #d6a63f;
    --ww-bad:          #d9705e;
    --ww-info:         #7ba3c0;
    /* On dark the state colours are already light enough to serve as text. */
    --ww-ok-text:      #7cb98f;
    --ww-warn-text:    #e0b455;
    --ww-bad-text:     #e28a79;
    --ww-info-text:    #8fb3ce;
    /* The accent inverts: light on dark. --ww-accent-on inverts with it -
       cream on this blue is 2.45:1 and would have shipped an unreadable
       button label. Charcoal on it is 6.45:1 (7.69:1 at the gradient's
       lighter end). --ww-accent-text: 8.33:1 on card, 8.88:1 on sunk. */
    --ww-accent:       #7fa3c4;
    --ww-accent-strong:#8fb2d1;
    --ww-accent-text:  #9dbcd8;
    --ww-accent-on:    #1c1c1a;
  }
}

/* ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  font-family: var(--ww-font);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ww-text);
  background: var(--ww-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* A faint warm wash, so a full-bleed page is never a flat slab of one colour. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(90rem 50rem at 50% -20%, rgba(232,184,75,.10), transparent 60%),
    radial-gradient(60rem 40rem at 100% 100%, rgba(232,184,75,.05), transparent 55%);
  z-index: 0;
}

/* -- layout ---------------------------------------------------------------- */

.ww-page {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 1.5rem;
  gap: 2rem;
}

.ww-centre {
  display: grid;
  place-items: center;
  width: 100%;
}

.ww-card {
  width: 100%;
  max-width: 26rem;
  background: var(--ww-surface);
  border: 1px solid var(--ww-line);
  border-radius: var(--ww-radius);
  box-shadow: var(--ww-shadow);
  padding: 2rem;
}
.ww-card--wide { max-width: 34rem; }

/* -- the mark -------------------------------------------------------------- */

.ww-mark { display: block; }
.ww-mark--sm { width: 34px; height: auto; }
.ww-mark--md { width: 46px; height: auto; }

.ww-brandbar {
  display: flex;
  align-items: center;
  gap: .7rem;
  justify-content: center;
  margin-bottom: 1.75rem;
}
.ww-brandbar__text { line-height: 1.15; }
.ww-brandbar__name {
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -.015em;
  color: var(--ww-text);
}
.ww-brandbar__tag {
  font-size: .58rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ww-text-faint);
  font-weight: 600;
}

/* -- type ------------------------------------------------------------------ */

.ww-h1 {
  font-size: 1.55rem;
  line-height: 1.2;
  letter-spacing: -.02em;
  font-weight: 620;
  margin: 0 0 .5rem;
  color: var(--ww-text);
}
.ww-h2 {
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ww-text-faint);
  margin: 0 0 .8rem;
}
.ww-lede { margin: 0 0 1.5rem; color: var(--ww-text-muted); }
.ww-note { font-size: .85rem; color: var(--ww-text-muted); margin: 0; }
.ww-quiet { font-size: .8rem; color: var(--ww-text-faint); }
.ww-mono { font-family: var(--ww-mono); font-size: .875em; }

.ww-rule {
  border: 0;
  border-top: 1px solid var(--ww-line);
  margin: 1.5rem 0;
}

.ww-sidenote {
  border-left: 2px solid var(--ww-gold);
  padding: .1rem 0 .1rem .9rem;
  font-size: .875rem;
  color: var(--ww-text-muted);
  margin: 1.25rem 0 0;
}

/* -- forms ----------------------------------------------------------------- */

.ww-field { margin-bottom: 1.1rem; }

.ww-label {
  display: block;
  font-size: .82rem;
  font-weight: 600;
  color: var(--ww-text);
  margin-bottom: .35rem;
}

/* Django renders these widgets, so they are matched by element rather than by
   class. That way the built-in password-reset form - whose markup this project
   does not control - is styled identically to the ones it does. */
.ww-card input[type="text"],
.ww-card input[type="email"],
.ww-card input[type="password"],
.ww-card input:not([type]),
.ww-input {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: var(--ww-text);
  background: var(--ww-surface-sunk);
  border: 1px solid var(--ww-line-strong);
  border-radius: var(--ww-radius-sm);
  padding: .6rem .75rem;
  transition: border-color .15s var(--ww-ease), box-shadow .15s var(--ww-ease),
              background .15s var(--ww-ease);
}
.ww-card input[type="text"]:hover,
.ww-card input[type="email"]:hover,
.ww-card input[type="password"]:hover,
.ww-input:hover { border-color: var(--ww-tan); }
.ww-card input[type="text"]:focus,
.ww-card input[type="email"]:focus,
.ww-card input[type="password"]:focus,
.ww-input:focus {
  /* WCAG 2.2 SC 2.4.11 wants the focus indicator at >=3:1 against what is
     around it. The old ring - gold at 25% alpha - composited to #f9edd2 on
     white, which is 1.16:1. Invisible. The border swap from #d3c8b0 to gold
     was 1.11:1, a pure hue change at the same lightness, so a keyboard user
     tabbing from Email to Password got no perceptible signal at all, and
     `outline: none` had already removed the browser's own.

     Now a solid two-tone ring: a charcoal halo against the pale field plus
     the gold band, which reads on either background and does not rely on
     hue discrimination. */
  outline: none;
  background: var(--ww-surface);
  border-color: var(--ww-charcoal);
  box-shadow: 0 0 0 2px var(--ww-surface), 0 0 0 4px var(--ww-charcoal);
}
.ww-card input::placeholder,
.ww-input::placeholder { color: var(--ww-text-faint); }

.ww-help { font-size: .78rem; color: var(--ww-text-faint); margin: .35rem 0 0; }

.ww-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  font: inherit;
  font-size: .95rem;
  font-weight: 620;
  letter-spacing: .005em;
  color: var(--ww-accent-on);
  /* Accent -> accent-strong, i.e. light to DARK. The old gold gradient ran
     the other way; mixing this blue toward white instead put the label at
     4.23:1 on the top edge. This way the lightest point is the accent
     itself, where the label measures 5.52:1. */
  background: linear-gradient(180deg, var(--ww-accent), var(--ww-accent-strong));
  border: 1px solid rgba(28,28,26,.14);
  border-radius: var(--ww-radius-sm);
  padding: .7rem 1.1rem;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(28,28,26,.12);
  transition: transform .12s var(--ww-ease), box-shadow .15s var(--ww-ease),
              filter .15s var(--ww-ease);
}
/* .ww-btn is used on <button> AND on <a>. An anchor inherits the page's link
   underline, so without this the button reads as an underlined link sitting
   inside a gold box. */
.ww-btn, .ww-btn:hover { text-decoration: none; }
.ww-btn:hover { filter: brightness(1.04); box-shadow: var(--ww-shadow-lift); }
.ww-btn:active { transform: translateY(1px); box-shadow: 0 1px 2px rgba(28,28,26,.2); }
.ww-btn:focus-visible {
  /* Gold ring on a gold button was 1.41:1 inside and 1.31:1 outside. The ring
     must contrast with BOTH edges, so it is charcoal with a light gap. Still
     correct now the button is accent blue: the 2px surface gap means the
     charcoal ring never touches the fill, and it measures 17:1 against that
     gap and 16:1 against the page behind it. */
  outline: none;
  box-shadow: 0 0 0 2px var(--ww-surface), 0 0 0 4px var(--ww-charcoal);
}

.ww-link {
  color: var(--ww-text);
  text-decoration-color: var(--ww-line-strong);
  text-underline-offset: 3px;
  transition: text-decoration-color .15s var(--ww-ease);
}
.ww-link:hover { text-decoration-color: var(--ww-accent); }

/* -- messages -------------------------------------------------------------- */

.ww-errors {
  border-left: 2px solid var(--ww-bad);
  background: color-mix(in srgb, var(--ww-bad) 7%, transparent);
  border-radius: 0 var(--ww-radius-sm) var(--ww-radius-sm) 0;
  padding: .6rem .8rem;
  margin: .5rem 0 0;
  font-size: .86rem;
  color: var(--ww-text);
}
.ww-errors ul { margin: 0; padding-left: 1.1rem; }

/* -- pills ----------------------------------------------------------------- */

.ww-pill {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-size: .7rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: .28rem .7rem;
  border-radius: var(--ww-radius-pill);
  border: 1px solid var(--ww-line-strong);
  background: var(--ww-surface-sunk);
  color: var(--ww-text-muted);
}
.ww-pill__dot { width: .45rem; height: .45rem; border-radius: 50%; background: currentColor; }
.ww-pill--live  { color: var(--ww-ok-text);   border-color: color-mix(in srgb, var(--ww-ok) 40%, var(--ww-line)); }
.ww-pill--warn  { color: var(--ww-warn-text); border-color: color-mix(in srgb, var(--ww-warn) 40%, var(--ww-line)); }
.ww-pill--gold  { color: #8a6a12; border-color: var(--ww-gold); background: color-mix(in srgb, var(--ww-gold) 12%, var(--ww-surface)); }
@media (prefers-color-scheme: dark) {
  .ww-pill--gold { color: var(--ww-gold-light); }
}

/* -- list of properties ---------------------------------------------------- */

.ww-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.ww-list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .85rem 1rem;
  border: 1px solid var(--ww-line);
  border-radius: var(--ww-radius-sm);
  background: var(--ww-surface-sunk);
  text-decoration: none;
  color: var(--ww-text);
  transition: border-color .15s var(--ww-ease), transform .12s var(--ww-ease),
              box-shadow .15s var(--ww-ease);
}
.ww-list a:hover {
  border-color: var(--ww-gold);
  transform: translateY(-1px);
  box-shadow: var(--ww-shadow);
}
.ww-list__name { font-weight: 600; }
.ww-list__host { font-family: var(--ww-mono); font-size: .78rem; color: var(--ww-text-faint); }

/* -- footer ---------------------------------------------------------------- */

.ww-foot {
  text-align: center;
  font-size: .74rem;
  color: var(--ww-text-faint);
  letter-spacing: .02em;
}
.ww-foot a { color: inherit; text-decoration-color: var(--ww-line-strong); }

@media (max-width: 30rem) {
  .ww-card { padding: 1.5rem 1.25rem; }
  .ww-h1 { font-size: 1.35rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* Django's own error markup, brought into the system rather than left default. */
.ww-card ul.errorlist {
  list-style: none;
  margin: .4rem 0 0;
  padding: .55rem .8rem;
  border-left: 2px solid var(--ww-bad);
  border-radius: 0 var(--ww-radius-sm) var(--ww-radius-sm) 0;
  background: color-mix(in srgb, var(--ww-bad) 8%, transparent);
  font-size: .85rem;
  color: var(--ww-text);
}
.ww-card ul.errorlist li + li { margin-top: .25rem; }
.ww-card .ww-errors ul.errorlist { border: 0; background: none; padding: 0; margin: 0; }

/* Django's help_text for the password fields is a <ul> of rules. */
.ww-card .ww-help ul { margin: .3rem 0 0; padding-left: 1.05rem; }

/* -- focus, everywhere else -----------------------------------------------
   Only inputs and .ww-btn had a focus style. Every link, the property
   chooser tiles, and both logout controls fell back to the UA outline - or,
   where a rule had already set `outline: none`, to nothing. A keyboard user
   choosing between two properties got a thin system outline where a mouse
   user got a designed hover state.

   :focus-visible, not :focus, so a mouse click does not leave a ring behind. */

a:focus-visible,
button:focus-visible,
.ww-link:focus-visible,
.ww-list a:focus-visible,
.ww-topbar__brand:focus-visible,
.ww-topbar__out:focus-visible,
.ww-logout__plain:focus-visible {
  outline: 2px solid var(--ww-charcoal);
  outline-offset: 2px;
  border-radius: var(--ww-radius-sm);
}

/* On the charcoal topbar a charcoal outline is invisible, so invert it. */
.ww-topbar__brand:focus-visible,
.ww-topbar__out:focus-visible {
  outline-color: var(--ww-cream);
}

@media (prefers-color-scheme: dark) {
  a:focus-visible,
  button:focus-visible,
  .ww-link:focus-visible,
  .ww-list a:focus-visible,
  .ww-logout__plain:focus-visible {
    outline-color: var(--ww-cream);
  }
  /* The element selectors matter here. Inputs carry NO .ww-input class - they
     are styled by `.ww-card input[type=...]` - so a dark override written only
     against .ww-input applied to nothing, and the light rule's charcoal ring
     stayed in force: a charcoal ring on a near-black card, i.e. invisible.
     Caught by focusing a field and looking at the screenshot. */
  .ww-card input[type="text"]:focus,
  .ww-card input[type="email"]:focus,
  .ww-card input[type="password"]:focus,
  .ww-card input:not([type]):focus,
  .ww-input:focus,
  .ww-btn:focus-visible {
    border-color: var(--ww-cream);
    box-shadow: 0 0 0 2px var(--ww-surface), 0 0 0 4px var(--ww-cream);
  }
}

/* -- messages -------------------------------------------------------------
   messages.success() was being set by the invitation flow and rendered by
   nothing: no customer-facing template looped over `messages`, so a person
   accepting an invitation for an address they already had a login for was
   dumped on the login page with no explanation, and the message sat unread
   in their session. Both shells render them now. */

.ww-messages { list-style: none; margin: 0 0 1.25rem; padding: 0; display: grid; gap: .5rem; }
.ww-messages__item {
  font-size: .86rem;
  line-height: 1.5;
  padding: .6rem .8rem;
  border-radius: var(--ww-radius-sm);
  border-left: 2px solid var(--ww-info);
  background: color-mix(in srgb, var(--ww-info) 8%, transparent);
  color: var(--ww-text);
}
.ww-messages__item--success { border-left-color: var(--ww-ok); background: color-mix(in srgb, var(--ww-ok) 8%, transparent); }
.ww-messages__item--warning { border-left-color: var(--ww-warn); background: color-mix(in srgb, var(--ww-warn) 10%, transparent); }
.ww-messages__item--error   { border-left-color: var(--ww-bad); background: color-mix(in srgb, var(--ww-bad) 8%, transparent); }

/* Inline text links sit at about 20px tall. Same treatment: the tap area is
   extended past the painted text so a thumb finds it, without changing how
   the sentence looks. Only standalone links get this - not links inside a
   paragraph of prose, where overlapping tap areas would be worse than small
   ones. */
.ww-quiet .ww-link,
.ww-link--standalone {
  position: relative;
  display: inline-block;
  min-height: 24px;
  line-height: 24px;
}
.ww-quiet .ww-link::after,
.ww-link--standalone::after { content: ""; position: absolute; inset: -10px -6px; }

/* -- log out ---------------------------------------------------------------
   These live in brand.css, NOT app.css.

   app.css is loaded only by wildward/_app.html - the signed-in shell. The
   property chooser and the no-properties page extend wildward/_base.html,
   which does not load it, so their logout control rendered as a bare grey
   operating-system button on a page that is otherwise fully branded. Any
   class used by a _base.html page has to be defined here.

   The control is a <form> and a <button> because Django 5 accepts only POST
   for logout; a submit button inherits none of the page's typography and
   arrives with a platform background and border, so those are reset. */

.ww-logout { display: inline; margin: 0; }
.ww-logout button {
  font: inherit;
  font-size: .8rem;
  line-height: inherit;
  background: none;
  cursor: pointer;
}

/* The chooser pages want a plain text link, not a pill. */
.ww-logout__plain {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  border: 0;
  padding: 0;
  color: var(--ww-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--ww-line-strong);
}
.ww-logout__plain:hover { text-decoration-color: var(--ww-gold); }
/* Extends the tap area past the painted text without changing how it looks. */
.ww-logout__plain::after { content: ""; position: absolute; inset: -10px -8px; }
