/*
  Aethera Kāinga.

  BLACK AND WHITE, INVERTED: black is the primary and white is what is set on
  it. Kāinga sits above Tera Drive and Tōnui rather than beside them, so it
  wears neither one's colour — and with the marae drawings carrying every
  product's identity, a coloured button competing with them would be a second
  voice in a room that only needs one.

  THE TOKEN NAMES SURVIVED THE INVERSION because they were never named after
  the colours. Ink is what you write WITH and paper is what you write ON; the
  ink is now white and the paper is now black, and every rule that asked for
  one of them still asks for the right thing.

  What colour would do, weight and contrast do instead: the current tab is the
  bright one, the action you are being offered is the filled one. Nothing is
  told apart by hue, which also means nothing is lost to anyone who cannot
  separate two hues.

  Dark only. This is the hub's own chassis, and it is deliberately not the
  console's — see the note above the drawings for what that costs and buys.
*/

:root {
  /*
    `color-scheme` is not decoration: it tells the browser to draw the
    checkbox, the scrollbars and the focus rings for a dark page. Without it
    the terms checkbox stays a light-mode control on a black card.
  */
  color-scheme: dark;

  --ink: #ffffff;
  --ink-pressed: #d8dcdd;
  --paper: #0b0c0d;

  /* The ground is barely a shade off true black — the glass sits on it. */
  --ground: #0b0c0d;

  /*
    ===========================================================
    THE KORU LINE — Tera's signature, and now Kāinga's too
    ===========================================================

    A round-capped line with a ball at each end. It is the same shape the app
    bends into the hero ring's arcs and shrinks into the nav bar's selection
    indicator; here it is that second job, laid out straight.

    The rules are stated in the SAME TERMS as the two places that already own
    them — `tera-drive/src/components/ui/KoruLine.tsx` and
    `tera-console/ring.js` — so the three can be compared by eye and by the
    guard in check-kainga.js:

        CAP_RADIUS = STROKE * 0.75
        CAP_INSET = CAP_RADIUS - STROKE / 2

    WHAT THE INVARIANT BUYS is one shape rather than two. The line draws its
    own round cap — a half-disc of stroke/2 on its centre line. A ball sitting
    flush with the line's BOTTOM edge has its centre exactly `cap - stroke/2`
    above that centre line, so the cap is internally tangent to it: swallowed
    whole, no seam, at any size. Break it and the line visibly pokes out from
    behind the ball, which the handover says is the defect this language
    notices fastest.

    The balls therefore stand ON the line, never threaded through it, and the
    line is inset by exactly CAP_INSET so the balls sit flush with the ends of
    the whole shape.
  */
  --koru-stroke: 3px;
  --koru-cap: calc(var(--koru-stroke) * 0.75);
  --koru-inset: calc(var(--koru-cap) - var(--koru-stroke) / 2);

  --text: #f3f5f5;
  --text-secondary: #a7b0b2;
  /*
    The quiet grey is 5.8:1 on the ground and still clears 4.5:1 on a glass
    panel, which sits a little lighter. It is used at 12 and 13 pixels for the
    lines under things, and that is exactly the size that needs the headroom.

    INVERTING IS NOT SYMMETRICAL: the grey that read as quiet on white is
    nearly invisible on black, so these are re-picked against the new ground
    rather than arithmetically flipped.
  */
  --quiet: #8d9698;
  --line: rgba(255, 255, 255, 0.14);
  /*
    ERRORS ARE INK, NOT RED. In a page with no hue at all, one red line would
    be the loudest thing on screen and would read as a system warning rather
    than "this field". They are set in the ink at weight instead, beside the
    field they are about — which is where the eye already is.
  */
  --danger: #ffffff;

  --radius: 18px;
  --radius-small: 10px;
}

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

/* `hidden` has to win against the flex and grid displays set below. */
[hidden] {
  display: none !important;
}

html {
  background: var(--ground);
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/*
  THE GROUND, drawn once and fixed. Three washes wide enough that no edge of
  any one of them is findable — the page should feel lit rather than
  decorated. It is the only ornament in the product, so it stays under 8%
  opacity and never moves.
*/
.field {
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(70vw 55vh at 12% -5%, rgba(255, 255, 255, 0.055), transparent 60%),
    radial-gradient(60vw 50vh at 95% 8%, rgba(255, 255, 255, 0.045), transparent 62%),
    radial-gradient(80vw 60vh at 50% 108%, rgba(255, 255, 255, 0.06), transparent 65%),
    var(--ground);
}

/* --------------------------------------------------------------- surfaces */

/*
  ONE GLASS, USED EVERYWHERE. Panels are the same material as the top bar
  because they are the same idea — a pane held above the ground, not a box
  drawn on it. `backdrop-filter` is the whole effect; the white underneath is
  the fallback for browsers without it, and the design survives its absence.
*/
.glass {
  background: rgba(255, 255, 255, 0.055);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  backdrop-filter: blur(20px) saturate(1.2);
  /*
    ON BLACK, THE EDGE DOES THE WORK A SHADOW DID. A drop shadow under a pale
    panel separated it from a pale ground; under a dark panel on a dark ground
    there is nothing for a shadow to darken. The lit top edge is what says the
    pane is held above the page — the shadow stays only to sit it down.
  */
  border: 1px solid rgba(255, 255, 255, 0.11);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 10px 30px -12px rgba(0, 0, 0, 0.6);
}

.card {
  border-radius: var(--radius);
  padding: 22px;
}

/* ---------------------------------------------------------------- top bar */

/*
  THE NAME SITS IN THE MIDDLE OF THE BAR.

  A GRID OF THREE, NOT A FLEX ROW, and that is the whole reason this works.
  Centring in a flex row means pushing with auto margins, which centres the
  brand against WHATEVER IS BESIDE IT — so the lockup would sit true when
  signed out and drift left the moment a nav and an account chip appeared on
  one side. Three tracks with the outer two at 1fr each are symmetrical by
  construction: the middle is the middle of the BAR, whatever the sides are
  carrying, and it does not move when somebody signs in.

  The DOM order is left alone — brand first, so it is still the first thing
  a keyboard reaches — and the tracks are assigned rather than reordered.
*/
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 22px;
  padding: 12px 24px;
  background: rgba(11, 12, 13, 0.72);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  backdrop-filter: blur(18px) saturate(1.2);
  border-bottom: 1px solid var(--line);
}

.brandmark {
  grid-column: 2;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  text-decoration: none;
}

/*
  THE MARK TAKES THE COLOUR OF THE TEXT BESIDE IT, because it is a mask over
  `currentColor` rather than a coloured picture. The same 10 KB file serves
  the bar, the sign-in card and the favicon's job at any size.
*/
.mark {
  flex: none;
  width: 30px;
  height: 26px;
  background-color: currentColor;
  -webkit-mask: url(brand/aethera-mark.png) center / contain no-repeat;
  mask: url(brand/aethera-mark.png) center / contain no-repeat;
}

.wordmark {
  font-size: 17px;
  letter-spacing: -0.2px;
  color: var(--text);
}

.wordmark b {
  font-weight: 800;
}

/* First track, hard left. `margin-left: auto` was what pushed these away
   from a left-aligned brand; with the brand in the middle track there is
   nothing to push away from and it would shove the nav into the centre. */
.tabs {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  display: flex;
  gap: 18px;
}

.tabs a {
  padding: 4px 10px 11px;
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 14px;
}

/* Hover brightens the word. The pill it used to grow was a second gesture
   competing with the koru for the same sentence. */
.tabs a:hover {
  color: var(--text);
}

/*
  THE CURRENT TAB CARRIES THE KORU. This is the app's own nav indicator doing
  the same job here, which is why it is a koru and not the generic underline
  it would otherwise be mistaken for: the shape is the product's, the geometry
  is governed, and it says "this one" in the family's own vocabulary.

  The line and the balls are one element each — `::before` is the line, so it
  can keep its rounded caps, and `::after` carries both balls as two
  background circles. The caps MUST stay round: a square-ended line would put
  its corners outside the ball and surface from behind it.
*/
.tabs a.here {
  color: var(--ink);
  font-weight: 600;
}

.tabs a,
.segmented button {
  position: relative;
}

.tabs a.here::before,
.segmented button[aria-selected="true"]::before {
  content: '';
  position: absolute;
  left: var(--koru-inset);
  right: var(--koru-inset);
  bottom: 0;
  height: var(--koru-stroke);
  border-radius: calc(var(--koru-stroke) / 2);
  background: currentColor;
}

/* The two balls, each standing on the line's bottom edge. */
.tabs a.here::after,
.segmented button[aria-selected="true"]::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--koru-cap) * 2);
  background:
    radial-gradient(circle closest-side, currentColor 99%, transparent 100%)
      left bottom / calc(var(--koru-cap) * 2) calc(var(--koru-cap) * 2) no-repeat,
    radial-gradient(circle closest-side, currentColor 99%, transparent 100%)
      right bottom / calc(var(--koru-cap) * 2) calc(var(--koru-cap) * 2) no-repeat;
}

.chip {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px 4px 4px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
}

.chip:hover {
  border-color: rgba(255, 255, 255, 0.45);
}

.chip-initial {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  font-weight: 700;
}

.tabs + .chip {
  margin-left: 0;
}

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

main {
  flex: 1;
  width: 100%;
  max-width: 1040px;
  margin: 0 auto;
  padding: 40px 24px 64px;
}

h1 {
  margin: 0 0 8px;
  font-size: 30px;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.5px;
}

.lede {
  margin: 0 0 26px;
  max-width: 62ch;
  color: var(--text-secondary);
}

.quiet {
  color: var(--quiet);
  font-size: 13px;
}

.note {
  margin: 20px 2px 0;
  max-width: 68ch;
  color: var(--quiet);
  font-size: 13px;
}

/* ----------------------------------------------------------------- welcome */

.welcome {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 52px;
  align-items: start;
  padding-top: 28px;
}

/*
  THE PITCH SITS AGAINST THE FORM, not above where the copy used to start.
  With three lines instead of thirteen, top-aligning left the headline
  hanging off the top of a much taller card — which reads as text that ran
  out rather than as a composition. Centred, the two halves face each other.
*/
.welcome-pitch { align-self: center; }

.welcome-pitch h1 {
  font-size: 40px;
  letter-spacing: -1px;
}

.welcome-pitch p {
  max-width: 46ch;
  color: var(--text-secondary);
}

/*
  THE PRODUCT NAMES SIT UNDER THE HEADLINE AS A CAPTION, not as a sentence.
  They are a list of three things, so they are set like one — spaced, quiet,
  and not competing with the forty-pixel line above them. With the two
  paragraphs gone the column is mostly air, which is the point: a front door
  should be read in about two seconds, and the only thing that has to be
  read is what is in the form.
*/
.welcome-products {
  margin-top: 18px;
  font-size: 15px;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
}

.auth-card {
  padding: 26px;
}

/*
  ONE WAY OF SAYING "THIS ONE", everywhere in the product. This was a pill in
  a track, which is a second selection idiom for the same idea and a shape
  from no particular product. It is now the two words with the koru under the
  chosen one — the same indicator as the nav, and the two never appear on
  screen together anyway.
*/
.segmented {
  display: flex;
  gap: 24px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--line);
}

.segmented button {
  padding: 0 2px 12px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
}

.segmented button:hover {
  color: var(--text);
}

.segmented button[aria-selected="true"] {
  color: var(--text);
  font-weight: 600;
}

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

label {
  display: block;
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
}

input[type="text"],
input[type="email"],
input[type="password"] {
  display: block;
  width: 100%;
  margin-top: 5px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: rgba(255, 255, 255, 0.07);
  color: var(--text);
  font: inherit;
}

input:focus-visible,
button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

input:disabled {
  color: var(--quiet);
  background: rgba(255, 255, 255, 0.03);
}

.check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-weight: 400;
  color: var(--text-secondary);
  font-size: 13px;
}

.check input {
  margin: 2px 0 0;
}

.hint {
  margin: -6px 0 16px;
  color: var(--quiet);
  font-size: 13px;
}

.error {
  margin: 0 0 14px;
  color: var(--danger);
  font-size: 13px;
  font-weight: 600;
}

.saved {
  margin: 0 0 14px;
  color: var(--ink);
  font-size: 13px;
}

.mode {
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  color: var(--quiet);
  font-size: 12px;
}

.button,
.button-quiet {
  display: inline-block;
  padding: 10px 18px;
  border-radius: var(--radius-small);
  border: 1px solid transparent;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.button {
  background: var(--ink);
  color: var(--paper);
}

.button:hover {
  background: var(--ink-pressed);
}

.button:disabled {
  opacity: 0.6;
  cursor: default;
}

.button-quiet {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.32);
  color: var(--ink);
}

.button-quiet:hover {
  background: rgba(255, 255, 255, 0.09);
}

form .button,
form .button-quiet {
  width: 100%;
}

/* ---------------------------------------------------------------- products */

.products {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(264px, 1fr));
  gap: 18px;
}

.product {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}

/*
  THE DRAWING IS THE TILE. It runs to the card's own edges rather than
  sitting in a box inside one — a picture with a margin around it inside a
  panel reads as an attachment, and this is the front of the house.

  FITTED WHOLE, NEVER CROPPED. `cover` would fill the frame more handsomely
  and would cut the top off a wharenui to do it. `contain` keeps the drawing
  intact whatever proportion it arrives in, and the frame's own shade shows
  in the gap.
*/
.product-art {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  background: rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid var(--line);
}

/*
  A DRAWING MADE ON WHITE PAPER, SHOWN ON A BLACK PAGE.

  While the page was white, `multiply` was the whole trick: white paper
  multiplied into a white tile disappears and only the ink is left. On black
  that same rule erases the drawing instead — everything multiplied by black
  is black — so the pair is inverted along with the rest of the product.

  `invert(1)` turns black ink on white paper into white ink on black paper;
  `screen` then drops that black paper, since anything screened with black
  leaves the backdrop alone. What is left on the tile is the line work in
  white, which is what the rest of this page is set in. Transparent PNGs
  behave the same way — the filter leaves alpha alone.

  A DRAWING THAT IS ALREADY LIGHT ON DARK would come out as a negative, so it
  is exempted rather than re-drawn: `artAsDrawn: true` in catalogue.js hangs
  `as-drawn` on the frame and the image is shown exactly as supplied. Use it
  for artwork made for a dark page, or for a drawing you want kept on its
  white paper like a print on a wall.
*/
.product-art img {
  /* Inline images sit on a text baseline and leave a descender's worth of
     gap under them — enough to push one tile's name out of line with the
     next one's. */
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: invert(1);
  mix-blend-mode: screen;
}

.product-art.as-drawn img {
  filter: none;
  mix-blend-mode: normal;
}

/* Waiting for a drawing: the frame names the file it wants, and nothing
   about it pretends to be artwork. */
.art-missing {
  display: none;
  position: absolute;
  inset: 0;
  place-items: center;
  color: var(--quiet);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
}

.product-art.empty img {
  display: none;
}

.product-art.empty .art-missing {
  display: grid;
}

.product-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 18px 22px 20px;
}

.product h2 {
  margin: 0;
  font-size: 18px;
  letter-spacing: -0.3px;
}

.product-line {
  margin: 2px 0 10px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
}

.product-blurb {
  margin: 0 0 18px;
  color: var(--text-secondary);
  font-size: 14px;
}

.product-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.product-foot .quiet {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
}

/* A two-line button in a narrow card looks like a mistake, and it is one. */
.product-foot .button,
.product-foot .button-quiet {
  white-space: nowrap;
}

.section-head {
  margin: 38px 0 14px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.2px;
}

/* ------------------------------------------------------------- connections */

.rows {
  padding: 4px 22px;
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 0;
  border-bottom: 1px solid var(--line);
}

.row:last-child {
  border-bottom: 0;
}

.row h3 {
  margin: 0 0 3px;
  font-size: 15.5px;
}

.row-main p {
  margin: 0;
  max-width: 54ch;
  color: var(--text-secondary);
  font-size: 14px;
}

.row-main .quiet {
  margin-top: 5px;
  display: block;
}

.row-side {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  text-align: right;
}

.row-state {
  max-width: 30ch;
  color: var(--quiet);
  font-size: 12.5px;
}

.row.held .row-state {
  color: var(--ink);
}

/* ----------------------------------------------------------------- account */

.account-card {
  max-width: 520px;
  margin-bottom: 18px;
}

.account-card h2 {
  margin: 0 0 6px;
  font-size: 16px;
}

.account-card .button,
.account-card .button-quiet {
  width: auto;
}

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

footer {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  max-width: 1040px;
  width: 100%;
  margin: 0 auto;
  padding: 18px 24px 26px;
  color: var(--quiet);
  font-size: 12px;
}

/* ------------------------------------------------------------- small print */

@media (max-width: 860px) {
  .welcome {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .welcome-pitch h1 {
    font-size: 32px;
  }

  /*
    NARROW: the chip stays up beside the mark — it is who you are, and it is
    also the way into Account — and the three tabs take the second row on
    their own. Three stacked rows was the alternative, and it pushed the
    greeting off the top of a phone.

    AND THE NAME GOES BACK TO THE LEFT. Centring it is worth the width on a
    desktop bar that is mostly empty; on a phone the bar is full, and a
    centred lockup with a chip crowding one side of it reads as badly placed
    rather than as centred.

    THESE RULES ARE GRID RULES NOW. They were written for the flex bar this
    used to be — `flex-wrap`, an auto margin and `width: 100%` — and every
    one of them is inert against a grid: the nav would have stayed jammed in
    the first track at its natural width instead of taking a row. Changing
    the layout model at one breakpoint means changing it at both.
  */
  .topbar {
    grid-template-columns: auto 1fr;
    gap: 10px 12px;
    padding: 10px 16px;
  }

  .brandmark {
    grid-column: 1;
    grid-row: 1;
    justify-self: start;
  }

  .chip {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }

  .tabs {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: stretch;
    justify-content: space-between;
  }

  main {
    padding: 28px 16px 48px;
  }

  .row {
    flex-direction: column;
    align-items: flex-start;
  }

  .row-side {
    flex-direction: row;
    align-items: center;
    text-align: left;
  }
}

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