/* ============================================================================================
   UBQ — THE FRONT. The public face at the root of the same app the console lives in.

   `docs/ubq-website-spec-v3b.md` is the brief (v1's principles still govern); `docs/ubq-look.md` is the ruling this file
   implements. One codebase: the marketing front is served at `/`, the console is behind
   `/login`, and the two DO NOT SHARE A STYLESHEET. `console.css` is an app shell — it sets
   `overflow: hidden` on the body and lays the page out as a flex column that fills the
   viewport, which is right for a board and wrong for a document that scrolls. Loading both
   would mean one of them losing, quietly, in whichever order the browser resolved them.

   THE RULED LOOK, and it is a ruling rather than a preference (spec §7's one request back):

     Accent   #F15A24   orange. A DESIGN accent and nothing else — it is not the colour of any
                        brick, and no copy anywhere may read it as one. Used for calls to
                        action, the mark, and the single highlight in a diagram. Nowhere else.
     Ink      #1A1A1A   not pure black. Pure black on near-white is a contrast the eye reads as
                        a glare edge at body size; this is the same reading with the edge off.
     Paper    near-white, faintly warm, so the orange sits ON something rather than vibrating
                        against a blue-white.
     Type     Inter throughout, headings and body. One family, weight doing the work.

   RESTRAINT IS THE WHOLE DEVICE. Orange is the only strong colour on a neutral field, so it
   pops in proportion to how rarely it appears. Every time this file is edited, the question to
   ask first is whether the new orange thing makes the existing orange things mean less. There
   is no second accent, and adding one is a ruling, not a commit.

   TOKENS, for the reason `console.css` has them: a restyle for a client, or a shared look
   decision that moves the orange half a step, is an edit to `:root` and nothing else. Nothing
   below the token block may contain a raw colour.
   ============================================================================================ */

:root {
  /* --- paper and ink ---------------------------------------------------------------- */
  --paper:      #faf9f7;   /* near-white, a half-degree warm */
  --paper-2:    #f2f0ec;   /* a band that separates without drawing a line */
  --panel:      #ffffff;
  --ink:        #1a1a1a;   /* ruled: not pure black */
  --ink-2:      #4a4744;   /* secondary text, still comfortably readable at body size */
  --ink-3:      #7c7771;   /* labels, captions, the quiet half of a pair */
  --line:       #e3e0da;
  --line-2:     #cfcbc3;
  --night-ink:  #f2f0ec;   /* type on the hero photograph, which is paper */

  /* --- the accent, and the only one ---------------------------------------------------
     A design accent, NOT a hardware colour. See the header. */
  --accent:     #f15a24;
  --accent-ink: #ffffff;
  --accent-deep:#d24817;   /* the same orange under a press, for hover and focus only */
  --accent-wash:#f15a2412;

  /* --- rhythm ------------------------------------------------------------------------ */
  --radius:     10px;
  --radius-sm:  6px;
  --bar-h:      76px;
  --gutter:     24px;
  --measure:    1180px;   /* the page's shoulder-to-shoulder width */
  --prose:      68ch;     /* the width a paragraph is allowed to reach */
  --shadow:     0 1px 2px #1a1a1a0d, 0 8px 26px #1a1a1a0a;
  --ease:       cubic-bezier(.2, .7, .2, 1);

  --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: 400 16.5px/1.65 var(--sans);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "cv05" 1, "ss03" 1;   /* Inter's single-storey l and rounded quotes */
}
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
img, svg { max-width: 100%; }
h1, h2, h3 { margin: 0; letter-spacing: -0.02em; line-height: 1.15; font-weight: 700; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

.wrap { width: 100%; max-width: var(--measure); margin: 0 auto; padding: 0 var(--gutter); }
.prose { max-width: var(--prose); }

/* Focus is visible and it is the accent, because a keyboard user on a marketing page is a
   keyboard user on the contact form two screens later. One ring, declared once. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

/* Every anchor target on this page sits under a sticky bar, so every anchor target needs the
   bar's height back. Declared once, against `[id]`, rather than on the four sections that
   happen to be linked today — the fifth one added next month would land under the bar and
   nobody would know why. */
[id] { scroll-margin-top: calc(var(--bar-h) + 18px); }
html { scroll-behavior: smooth; }

/* --- the mark ----------------------------------------------------------------------------
   `assets/UBQlogo1.png`, cut by `scripts/make-logo-assets.py`. The FULL LOCKUP here — UBQ, the
   sensor-node Q and FIELD & FLEET — because this bar has the room and this is the first thing a
   prospect sees. The console's top bar has the same mark with the strapline dropped, for the
   reason given in `console.css`: at bar height that line renders as a smear rather than as type.

   The bar is 76px because of this. A 60px bar puts the lockup at 34px, which puts the strapline
   at six pixels — and a mark rendered at a size its own smallest element cannot survive is a
   mark that makes the page look blurry rather than branded. */

.mark { display: inline-flex; align-items: center; flex: none; }
.mark img { display: block; height: 44px; width: auto; }

/* --- the top bar -------------------------------------------------------------------------
   Sticky, because the page is long and the sign-in link is the one thing a returning customer
   came for. Section anchors in the middle; the console door on the right. */

.topbar {
  position: sticky; top: 0; z-index: 50; height: var(--bar-h);
  background: #faf9f7f2; backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--line);
}
.topbar .wrap { height: 100%; display: flex; align-items: center; gap: 28px; }
.topnav { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.topnav a {
  padding: 7px 11px; border-radius: var(--radius-sm); font-size: 13.5px; font-weight: 500;
  color: var(--ink-2); white-space: nowrap;
}
.topnav a:hover { color: var(--ink); background: var(--paper-2); }
.topnav .signin {
  border: 1px solid var(--line-2); font-weight: 600; color: var(--ink); margin-left: 8px;
}
.topnav .signin:hover { border-color: var(--accent); color: var(--accent); background: transparent; }

/* --- buttons ------------------------------------------------------------------------------
   One filled and one outlined, and there is never a third. The filled one is the only large
   area of orange on the page, which is why there is exactly one of it per screenful. */

.btn {
  display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 13px 22px; border-radius: var(--radius); border: 1px solid transparent;
  font-size: 15.5px; font-weight: 600; letter-spacing: -0.01em;
  transition: background 140ms var(--ease), border-color 140ms var(--ease), color 140ms var(--ease);
}
.btn.primary { background: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-deep); }
.btn.ghost { border-color: var(--line-2); color: var(--ink); background: transparent; }
.btn.ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn .arrow { font-size: 17px; line-height: 1; transform: translateY(-1px); }

/* --- section furniture --------------------------------------------------------------------- */

section { padding: 74px 0; }
section.banded { background: var(--paper-2); }
.eyebrow {
  font-size: 11.5px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 14px;
}
.eyebrow b { color: var(--accent); font-weight: 700; }
h2.section-title { font-size: clamp(26px, 3.4vw, 34px); margin-bottom: 16px; }
.lede { font-size: 18px; color: var(--ink-2); }

/* --- the hero ------------------------------------------------------------------------------ */

.hero { padding: 76px 0 58px; }
.hero h1 {
  font-size: clamp(34px, 5.1vw, 58px); letter-spacing: -0.035em; margin-bottom: 22px;
  max-width: 22ch;
}
.hero .sub { font-size: clamp(17px, 1.6vw, 19.5px); color: var(--ink-2); max-width: 54ch; margin-bottom: 30px; }
.hero .ctas { display: flex; flex-wrap: wrap; gap: 12px; }

/* --- 2. what we do ----------------------------------------------------------------------
   Two paragraphs, the first set larger because it is the one that says what we do. The label
   column earns less width than the thing it labels. */

.says .wrap { display: grid; grid-template-columns: .72fr 1.28fr; gap: 48px; }
.says p { font-size: 17px; color: var(--ink-2); }
.says p b { color: var(--ink); font-weight: 600; }
.says .lead-para {
  font-size: clamp(19px, 2.1vw, 23px); line-height: 1.5; letter-spacing: -0.02em;
  color: var(--ink);
}

/* --- 3. tasking / telemetry ------------------------------------------------------------------
   Two panels side by side, outbound and inbound. */

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 24px 24px 20px;
}
.panel h3 { font-size: 21px; margin-bottom: 16px; }
.panel dl { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 10px 16px; }
.panel dt { font-weight: 600; font-size: 14.5px; }
.panel dd { margin: 0; font-size: 14.5px; color: var(--ink-2); }

/* --- 4. capabilities: the card grid ------------------------------------------------------------
   Spec v3b §5. Always open — image on top, title, two lines — and the grid reflows by itself, so a
   new capability is a new card and no edit here. The frame is one fixed shape so a row of cards
   lines up whatever each image's proportions; photographs fill it, the drawing sits inside it, and
   a card still waiting for its photograph is a quiet tile wearing the node mark. */

.caps-head { max-width: var(--prose); margin-bottom: 30px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 20px; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  display: flex; flex-direction: column;
}
.card-frame { aspect-ratio: 16 / 10; overflow: hidden; background: var(--paper-2); border-bottom: 1px solid var(--line); }   /* overflow holds the ratio: a tall image cannot stretch the frame */
.card-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-frame.drawn { display: grid; place-items: center; padding: 10px; background: var(--panel); }
.card-frame.drawn svg { width: 100%; height: auto; }
.card-frame.empty { display: grid; place-items: center; }
/* A required caption (the manifest's licence for the image) sits on the card, quiet, under its frame. */
.card .card-caption { margin: 12px 20px 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-3); font-style: italic; }
.card .card-caption + h3 { margin-top: 10px; }
.card-frame.empty .mark-tile { width: 56px; height: 56px; object-fit: contain; opacity: .22; }
.card h3 { font-size: 17.5px; margin: 18px 20px 8px; }
.card p { margin: 0 20px 20px; font-size: 15px; line-height: 1.55; color: var(--ink-2); }

/* THE CREDIBILITY SENTENCE (v3b §6). One element, one class, so dropping it is a deletion and
   the paragraph above stands without it. Set quiet: a footnote to the contact copy, not a claim. */
.credibility {
  margin-top: 26px; padding-left: 18px; border-left: 3px solid var(--accent);
  font-size: 16px; color: var(--ink-2); max-width: 46ch; line-height: 1.55;
}

/* --- the contact section ------------------------------------------------------------------
   v2 §6, made need-led by v3b §6. It was a tab; it is the last section of the page now, which is where a single-CTA page
   was always going to put it. The layout argument survives the move: the left column is the
   proposition, the right is the interaction, and when the grounded builder lands (v1 §5,
   post-PoC) swapping a form for a conversation is a change to one column and nothing else on
   this page moves. */
.contact .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: start; }

.builder-form { display: grid; gap: 14px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow); }
.builder-form h3 { font-size: 17px; }
.builder-form label { font-size: 12.5px; font-weight: 600; letter-spacing: .03em; color: var(--ink-2); display: block; margin-bottom: 6px; }
.builder-form input, .builder-form textarea {
  width: 100%; padding: 11px 13px; border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  background: var(--paper); font-size: 15px;
}
.builder-form input:focus, .builder-form textarea:focus { border-color: var(--accent); }
.builder-form textarea { min-height: 116px; resize: vertical; }
.builder-form .field { margin: 0; }
.builder-form .hint { font-size: 13px; color: var(--ink-3); }
.builder-form .btn { justify-content: center; }
/* The honeypot. Off-screen rather than `display: none`, because some form fillers skip what is
   not rendered and this one is meant to be filled by exactly the things that fill everything. */
.builder-form .trap {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}
.form-said { padding: 13px 15px; border-radius: var(--radius-sm); font-size: 14.5px; }
.form-said.good { background: var(--accent-wash); border: 1px solid var(--accent); color: var(--ink); }
.form-said.bad { background: var(--paper-2); border: 1px solid var(--line-2); color: var(--ink-2); }

/* --- the footer -------------------------------------------------------------------------------
   The one line that appears on every surface of the front (spec §2). */

.foot { border-top: 1px solid var(--line); padding: 34px 0 44px; background: var(--paper-2); }
.foot .wrap { display: flex; flex-wrap: wrap; gap: 14px 26px; align-items: center; }
.foot .line { font-size: 14px; color: var(--ink-2); }
.foot .line b { color: var(--ink); font-weight: 600; }
.foot .line .sep { color: var(--line-2); margin: 0 8px; }
.foot .line em { font-style: italic; color: var(--ink-2); }
.foot a:hover { color: var(--accent); }

/* --- narrow ------------------------------------------------------------------------------------
   One breakpoint, because there are only two layouts on this page: two columns and one. */

@media (max-width: 860px) {
  :root { --gutter: 18px; }
  body { font-size: 16px; }
  section { padding: 52px 0; }
  .hero { padding: 48px 0 40px; }
  .says .wrap, .contact .wrap, .pair {
    grid-template-columns: 1fr; gap: 34px;
  }
  .hero h1 { max-width: none; }
  .topnav a:not(.signin) { display: none; }
}

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

/* --- photographs (Acquisition's caption manifest v1, 7 Oct) ------------------------------- */
.hero.has-photo { position: relative; overflow: hidden; color: var(--night-ink); background: #0d1526;
  min-height: min(78vh, 760px); display: flex; align-items: flex-start; }
.hero.has-photo .hero-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 50%; z-index: 0; }
.hero.has-photo .hero-narrow { display: none; }
.hero.has-photo .hero-caption { position: absolute; right: 22px; bottom: 16px; z-index: 2; margin: 0; max-width: 46ch;
  font-size: 13px; line-height: 1.4; text-align: right; color: rgba(242, 240, 236, .92); text-shadow: 0 1px 3px rgba(0, 0, 0, .6); }
.hero.has-photo::before { content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(8, 14, 30, .55) 0%, rgba(8, 14, 30, .25) 45%, rgba(8, 14, 30, 0) 70%); }
.hero.has-photo .wrap { position: relative; z-index: 2; }
.hero.has-photo h1 { color: #fff; }
.hero.has-photo .sub { color: rgba(242, 240, 236, .88); }
@media (max-width: 720px) {
  .hero.has-photo .hero-wide, .hero.has-photo .hero-caption { display: none; }   /* the composite and its caption go together */
  .hero.has-photo .hero-narrow { display: block; object-position: 84% 75%; }       /* keep the glowing second unit in frame */
}
/* The desktop composite is bright where the copy sits (the left monitor, the desk), so the copy
   column gets a shade of its own, and the required caption a solid backing — a caption that cannot
   be read is not a licence. Phones keep the dawn shot and its own top gradient. */
@media (min-width: 721px) {
  .hero.has-photo::before {
    background: linear-gradient(90deg, rgba(8, 12, 22, .82) 0%, rgba(8, 12, 22, .62) 42%, rgba(8, 12, 22, .12) 72%, rgba(8, 12, 22, 0) 100%),
                linear-gradient(180deg, rgba(8, 12, 22, .35) 0%, rgba(8, 12, 22, 0) 40%);
  }
  .hero.has-photo .hero-caption { background: rgba(8, 12, 22, .78); padding: 6px 10px; border-radius: 6px; text-shadow: none; }
}
