/* public.css — the design system for every public marketing page.

   WHY THIS FILE EXISTS
   Before it, the public templates carried 2,588 lines of CSS across 25 separate
   inline <style> blocks and not one of them extended a base. The duplication was
   not approximate: authenticate.html, redirect.html and display.html held byte
   -for-byte IDENTICAL 135-line blocks, and landing.html and security_labels.html
   shared 76 identical lines. Every brand change had to be made by hand in two
   dozen places, which is the drift shape this codebase has already been bitten
   by twice (a navbar copy-pasted per page that kept advertising a renamed
   section; a public nav offering a page that 404s).

   WHAT BELONGS HERE
   Anything two public pages could share: the shell, type scale, sections, bands,
   cards, buttons, the pricing ladder, the order form. Page-specific one-offs stay
   in that page's own {% block page_css %}.

   WHAT DOES NOT
   Colour and typeface literals. Every value here resolves to a token from
   brand-tokens.css, which is Optrical's own tokens.css copied verbatim. A brand
   change is a swap of that file, not an edit of this one.

   NOT YET LOADED BY public/landing.html. The live homepage still carries its own
   inline styles, deliberately: it is the one page being left exactly as it
   renders today. It joins this file when the homepage is swapped, and
   macros/public_nav.html can be deleted at the same time.
*/

*{box-sizing:border-box;margin:0;padding:0}
:root{
    /* ── The Optrical logo, and nothing else ────────────────────────
       The wordmark is --c-navy #023151; the spiral mark beside it is
       --c-orange #F26429. That is the whole logo -- two colours on
       white -- so those two carry the page and every other value here
       is Optrical's own supporting token rather than a colour invented
       to sit next to them.

       THE ORANGE COMES IN TWO STRENGTHS, and the difference is not
       decorative. Measured:
         #F26429 on white ....... 3.17:1  fails AA for text
         #F26429 on navy ........ 4.25:1  AA at 24px+ only
         #FFFFFF on #F26429 ..... 3.17:1  fails -- so no white-on-orange
         #CF4A13 on white ....... 4.52:1  AA
         #FFFFFF on #CF4A13 ..... 4.52:1  AA
       So --accent is the brand orange, used for LARGE display type on
       navy, for borders and for rules; --accent-text is Optrical's own
       --c-orange-deep and is the only one allowed to carry or be small
       text. Optrical's tokens already drew this line; this just names
       which side each use sits on. */
    --ink:var(--c-navy);              /* #023151 dark bands, headings  */
    --ink-deep:var(--c-navy-deep);    /* #00243D                       */
    --ink-black:var(--c-navy-black);  /* #001A2C footer                */
    --ink2:var(--c-text);             /* #4F5256 body, 7.85:1 on white */
    --steel:var(--c-steel);           /* #8FA3B0 secondary ON navy     */
    --footer-text:var(--c-footer-text);
    --border:var(--c-border);         /* #E5E5E5                       */
    --surface:var(--c-panel);         /* #F4F6F8                       */
    --white:var(--c-surface);
    /* ORANGE NEVER TOUCHES A NAVY GROUND. Optrical's own sections.css
       settles this: every navy band it draws (.banner, .hero-simple,
       .hero) sets color:#fff and dims secondary copy with opacity, and
       there is no orange anywhere on them. The orange lives on white --
       buttons, notices, the nav underline. On navy it is only 4.25:1
       anyway, and next to a large white headline it reads as muddy
       rather than as an accent. So the two grounds get two treatments:
       on navy, hierarchy comes from white and --on-navy-2; on white, it
       comes from the orange. */
    --accent:var(--c-orange);         /* #F26429 LIGHT GROUNDS ONLY    */
    /* Optrical's own secondary-on-navy: white, dimmed. Composites to
       about #CBD4DA over --c-navy, ~9:1, and stays in the white family
       instead of introducing a fourth hue. */
    --on-navy-2:rgba(255,255,255,.82);
    --on-navy-rule:rgba(255,255,255,.22);
    --accent-text:var(--c-orange-deep);/* #CF4A13 the only text orange */
    --accent-hover:var(--c-blue-hover);/* #0868AA Optrical's own       */
    /* #797C80 is 4.19:1 on white and fails AA for body sizes, so the
       brand's --c-text-muted is deliberately NOT mapped to a --muted
       token here. On white, secondary text uses --ink2; on navy it uses
       --steel (5.15:1). Small grey text was one of the density
       complaints -- making it darker is part of the fix, not a
       compromise forced by the palette. */
    --muted:var(--c-text);
    /* 4px, from Optrical's --radius-btn. The 10px pill this page had is
       a generic-SaaS tell; the brand's buttons are nearly square. */
    --radius:4px;
    --radius-card:6px;
    /* TWO section rhythms, not one. The live page gives all twelve
       bands the same 72px, which is why they read as a single
       undifferentiated column. --gap-major separates the six sections;
       --gap-minor is for space INSIDE one. A reader can only tell a
       new topic has started if the gaps are unequal. */
    --gap-major:104px;
    --gap-minor:40px;
}
html{scroll-behavior:smooth}
/* 17px, up from the browser default the live page inherits. Its copy is
   set at 13-15px in the nav, chips and currency buttons -- small type at
   high word count is most of why the page FEELS dense before a word of
   it is read. Bigger type also caps how much can be written: the column
   runs out of room, which is the constraint the old page lacked. */
body{font-family:var(--f-body);color:var(--ink);background:var(--white);
     font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased}
a{color:var(--accent-text)}
em{font-style:normal;color:var(--accent)}
.wrap{max-width:1020px;margin:0 auto;padding:0 28px}

/* ── Nav ──────────────────────────────────────────────────────────────
   Four links and two buttons. The live nav offers up to FIFTEEN targets
   (a five-item Platform menu, a five-item Company menu, Pricing,
   Security Labels, DPP, Login, CTA) and six of them are #anchors into
   the page you are already on -- so the nav mostly scrolls you rather
   than navigating, and a deep link to #analytics drops you mid-band
   under a sticky bar with no landmark.

   No dropdowns at all here. Besides the count, the live ones are
   hover-driven <button>s with aria-haspopup and no aria-expanded, which
   makes them unreachable by keyboard; not rebuilding them is cheaper
   than fixing them. Company moves to the footer, where a visitor looks
   for corporate provenance anyway. */
/* SOLID white, not the translucent blur this had. Over the navy hero
   the 92%-opaque bar let the headline show through it -- an orange word
   ghosting up through the navbar, which read as a rendering fault. It
   is also what optrical.com does: .header-main is a flat --c-surface
   with a --c-rule underneath. */
.nav{position:sticky;top:0;z-index:50;background:var(--white);
     border-bottom:1px solid var(--c-rule)}
.nav-in{max-width:1020px;margin:0 auto;padding:0 28px;height:64px;
        display:flex;align-items:center;gap:28px}
.brand{font-family:var(--f-head);font-weight:700;font-size:21px;
       color:var(--ink);text-decoration:none;letter-spacing:-.02em;line-height:1.1}
/* The wordmark is navy and the mark beside it is orange -- so "O4" takes
   --ink and "QR" takes the spiral's colour. On white at 21px/800 the
   brand orange is large text (3.17:1 clears the 3:1 large threshold),
   which is the one place --accent is allowed on a white ground. */
.brand span{color:var(--accent)}
.brand small{display:block;font-family:var(--f-body);font-size:10.5px;
             font-weight:500;color:var(--ink2);letter-spacing:.02em}
.nav-links{margin-left:auto;display:flex;align-items:center;gap:24px}
.nav-links a{font-size:15px;color:var(--ink2);text-decoration:none;font-weight:500}
.nav-links a:hover{color:var(--accent-text)}
/* Navy, not orange. Optrical's own token file annotates --c-navy as
   "headings, nav links, primary button" and --c-orange as
   "accent / button hover" -- the brand's primary button has always been
   the navy one. It is also the only one that works: white on #F26429 is
   3.17:1 and fails. */
.nav-cta{padding:9px 18px;background:var(--ink);color:#fff!important;
         border-radius:var(--radius);font-weight:700;font-size:15px}
.nav-cta:hover{background:var(--accent-hover)}
.nav-login{color:var(--ink2)}
.burger{display:none;margin-left:auto;background:none;border:0;padding:8px;cursor:pointer}
.burger span{display:block;width:22px;height:2px;background:var(--ink);margin:4px 0;border-radius:2px}
.nav-mob{display:none;flex-direction:column;padding:8px 28px 18px;
         border-top:1px solid var(--border);background:#fff}
.nav-mob a{padding:12px 0;font-size:17px;color:var(--ink2);text-decoration:none;
           border-bottom:1px solid var(--border)}
.nav-mob a:last-child{border-bottom:0}

/* ── Hero ──────────────────────────────────────────────────────────────
   ONE headline, ONE sentence, ONE primary button.

   The live hero carries all four of the company's propositions before
   the first button: a two-clause headline (genuine AND compliant), then
   ~55 words covering micro-optic manufacturing AND per-unit identity AND
   passports, then a second paragraph about counterfeits, diversion and
   the ESPR deadline. Roughly ninety words. A visitor 400px down still
   cannot say what the product is.

   Compliance is not dropped -- it is a different buyer with a different
   question, and it gets the DPP page and one line further down. A hero
   that argues two cases wins neither. */
.hero{background:var(--ink);color:#fff;padding:96px 0 88px}
.hero-in{max-width:1020px;margin:0 auto;padding:0 28px;
         display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}
.hero h1{font-family:var(--f-head);font-size:60px;line-height:1.04;
         font-weight:700;letter-spacing:-.035em;margin-bottom:22px}
/* White, not orange. This was the loudest orange-on-navy on the page
   and the one that prompted the note. The emphasis survives without a
   hue change: "genuine" is already the last word of a three-word
   headline at 60px. */
.hero h1 em{color:#fff}
.hero p{font-size:20px;line-height:1.5;color:var(--on-navy-2);max-width:30em;margin-bottom:34px}
.hero-btns{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
/* .btn-primary only ever sits on a navy band. White fill, navy label:
   13.46:1, and it is the loudest thing available on that ground. An
   orange fill was the obvious first choice and is wrong twice over --
   white on #F26429 is 3.17:1, and even the deep orange only reaches
   2.97:1 against the navy behind it, so the button would not clear the
   3:1 that non-text UI needs to be seen as a shape at all. */
.btn-primary{padding:15px 30px;background:#fff;color:var(--ink);border-radius:var(--radius);
             font-weight:700;text-decoration:none;font-size:17px;display:inline-block;
             transition:background .15s,transform .15s}
.btn-primary:hover{background:var(--surface);color:var(--ink);transform:translateY(-1px)}
/* White outline, not orange. Same rule as the headline -- and the pair
   now reads as one family, a solid white button beside an outlined one,
   rather than as two unrelated buttons. */
.btn-ghost{padding:15px 28px;border:1px solid var(--on-navy-rule);color:#fff;
           border-radius:var(--radius);font-weight:500;text-decoration:none;font-size:17px}
.btn-ghost:hover{border-color:#fff;background:rgba(255,255,255,.08);color:#fff}
/* The parent-brand band was 87 words, four capability chips and two of
   its own buttons, sitting between the hero and the first explanation of
   the product. Optrical is a CREDIBILITY fact, not a section: it belongs
   where a reader checks credibility, which is next to the claim and in
   the footer. One line. */
.hero-trust{margin-top:30px;padding-top:22px;border-top:1px solid var(--on-navy-rule);
            font-size:15px;color:var(--on-navy-2);max-width:34em}
.hero-trust a{color:#fff;text-decoration:underline;text-underline-offset:3px}
.hero-visual img{width:100%;display:block}

/* ── Section shell ───────────────────────────────────────────────────── */
.sec{padding:var(--gap-major) 0}
/* The alternating white/grey band is GONE. It was part of what made the
   live page read as one undifferentiated column -- twelve stripes of
   equal weight -- and it also broke the eyebrow: --accent-text is
   4.52:1 on white but only 4.18:1 on the #F4F6F8 panel, so the label
   would have failed AA on every other section. Rhythm now comes from
   the two navy bands and the gap scale, which is the argument this
   redesign is making anyway. The panel tint is spent on cards instead. */
.sec.alt{background:var(--white)}
.sec-label{font-size:12.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
           color:var(--accent-text);margin-bottom:12px}
.sec-title{font-family:var(--f-head);font-size:38px;font-weight:700;
           letter-spacing:-.025em;line-height:1.18;margin-bottom:14px;max-width:16em}
/* ONE sub-paragraph is allowed per section, and it is capped at a single
   sentence. The live page has eleven .sec-sub paragraphs, several of
   them two or three sentences, and they are the bulk of the reading
   load -- each one restating the heading it sits under. */
.sec-lead{font-size:19px;color:var(--ink2);max-width:34em;margin-bottom:var(--gap-minor)}

/* ── Statement band ────────────────────────────────────────────────────
   The sharpest 60 words on the live site, given the room to land instead
   of being one band among twelve. No cards, no grid, nothing to compare
   it against -- a claim this central should be read, not scanned. */
.statement{background:var(--ink);color:#fff;padding:84px 0}
.statement .wrap{text-align:center}
.statement h2{font-family:var(--f-head);font-size:40px;font-weight:700;
              letter-spacing:-.03em;line-height:1.2;margin:0 auto 18px;max-width:15em}
.statement h2 em{color:#fff}
.statement p{font-size:19px;color:var(--on-navy-2);max-width:38em;margin:0 auto}
/* The one eyebrow that is NOT orange, because it is the one on navy. */
.statement .kicker{font-size:12.5px;font-weight:700;letter-spacing:.12em;
                   text-transform:uppercase;color:var(--on-navy-2);margin-bottom:16px}

/* ── Cards ─────────────────────────────────────────────────────────────
   One line of description each. The live equivalents carry a description
   plus a chip row of three or four keywords plus a link -- the chips are
   the section's word count and add no fact the sentence does not. */
/* 200px, not 260: the row holds FOUR cards when the Redirect and Display
   actions are both switched on, and 260 made the fourth wrap to a line
   of its own -- a single orphaned card under three, which reads as a
   layout fault rather than a category. auto-fit still collapses the
   empty tracks when the gated cards are off, so a two-card row fills
   the width instead of hugging the left edge. */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}
.card{background:var(--surface);border:1px solid var(--border);
      border-radius:var(--radius-card);padding:28px 26px}
.card-icon{font-size:26px;display:block;margin-bottom:14px}
.card h3{font-family:var(--f-head);font-size:20px;font-weight:700;margin-bottom:8px}
.card p{font-size:16px;color:var(--ink2);margin-bottom:14px}
.card a{font-size:15px;font-weight:700;text-decoration:none}
.card a:hover{text-decoration:underline}
/* Optrical already has a "coming soon" notice style -- --c-notice-soon
   is the brand orange over a --c-notice-soon-bg warm wash. Borrowed
   rather than invented, with the label in navy so an 11px pill is not
   relying on orange to be legible. */
.soon{display:inline-block;margin-left:8px;font-size:11px;font-weight:700;
      letter-spacing:.06em;text-transform:uppercase;color:var(--ink);
      background:#FFF9F5;border:1px solid var(--accent);
      border-radius:3px;padding:2px 8px;vertical-align:middle}

/* ── Pricing ───────────────────────────────────────────────────────────
   The tier LADDER only. The live pricing section is the densest thing on
   the site (328 words) and most of it is not prices: three meter columns
   (codes / records / top-ups), a starter-basket row, a regional-pricing
   paragraph and a printed-label footnote. A visitor cannot answer "what
   will this cost me" without first learning the billing ontology.

   That material is not wrong, it is just not a homepage's job -- it is
   the content of a /pricing page, linked below the ladder. The one fact
   from it that changes how the TABLE is read (volume is bought
   separately, so you are not pushed up a tier to print more) stays, as
   one sentence. */
/* 200px for the same reason the card row uses it: four public plans at
   230 need 974px of track in a 964px column, which orphaned Enterprise
   onto a second row -- and an orphaned tier reads as "there is more
   above this", which is the opposite of what the top tier should say.
   The plan count comes from the database, so this has to survive a
   fifth plan being published as well; auto-fit wraps to 2x2 or 3x2
   rather than leaving a single card stranded. */
.tiers{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:18px}
.tier{background:var(--surface);border:1px solid var(--border);
      border-radius:var(--radius-card);padding:26px 22px;
      display:flex;flex-direction:column}
/* The one card the eye should land on gets the spiral colour as a
   2px edge -- non-text UI at 4.25:1 against the page, no text riding
   on it, so full-strength orange is exactly right here. */
.tier.featured{background:#fff;border:2px solid var(--accent)}
.tier-badge{align-self:flex-start;font-size:11px;font-weight:700;letter-spacing:.06em;
            text-transform:uppercase;color:#fff;background:var(--accent-text);
            border-radius:3px;padding:3px 10px;margin-bottom:12px}
.tier-name{font-family:var(--f-head);font-size:19px;font-weight:700;margin-bottom:6px}
.tier-price{font-family:var(--f-head);font-size:30px;font-weight:700;
            color:var(--ink);line-height:1.15;margin:4px 0 2px}
.tier-price small{font-size:14px;font-weight:500;color:var(--ink2)}
.tier-meta{font-size:15px;color:var(--ink2);margin-bottom:16px}
.tier-feats{list-style:none;margin:0 0 22px;font-size:15px;color:var(--ink2)}
.tier-feats li{padding:5px 0 5px 20px;position:relative}
.tier-feats li::before{content:"✓";position:absolute;left:0;color:var(--accent-text);font-weight:700}
.tier-cta{margin-top:auto;text-align:center;padding:11px 16px;border-radius:var(--radius);
          border:1px solid var(--c-field-border);color:var(--ink);text-decoration:none;
          font-weight:700;font-size:15px;background:#fff}
.tier-cta:hover{border-color:var(--accent);color:var(--accent-text)}
.tier-cta.primary{background:var(--ink);border-color:var(--ink);color:#fff}
.tier-cta.primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#fff}
.ccy-row{display:flex;gap:8px;align-items:center;margin-bottom:20px}
.ccy-row span.lab{font-size:14px;color:var(--ink2);font-weight:500}
.ccy-btn{font:inherit;font-size:14px;font-weight:500;padding:5px 12px;border-radius:var(--radius);
         border:1px solid var(--c-field-border);background:#fff;color:var(--ink2);cursor:pointer}
.ccy-btn.active{border-color:var(--accent);color:var(--accent-text);font-weight:700}
.price-note{margin-top:24px;font-size:16px;color:var(--ink2)}

/* ── Constructions ─────────────────────────────────────────────────────
   The catalogue of what the factory actually makes. Given a plain
   bordered list rather than the card treatment the jobs get: these are
   specifications a buyer scans down looking for their format, not six
   propositions to choose between, and stamping the same radius and fill
   on both would flatten the difference. */
/* The rule lives on each CELL, not on the grid.

   It was a 1px grid gap over a --border-coloured background, which draws
   the dividers for free -- but only while the cells fill every track.
   There are six constructions in a four-column row, so the last two
   tracks of row two had nothing in them and the backing colour showed
   through as a grey rectangle sitting in the middle of the section.
   With the border on the cell an empty track is simply empty.

   280px also makes it three across rather than four, which divides six
   exactly today; the cell border is what keeps it correct when the
   factory adds a seventh. */
.cons{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
      gap:14px}
.con{background:var(--white);border:1px solid var(--border);
     border-radius:var(--radius-card);padding:22px 20px}
.con h3{font-family:var(--f-head);font-size:17px;font-weight:700;margin-bottom:7px}
.con p{font-size:15px;color:var(--ink2);margin-bottom:12px;line-height:1.5}
.con-for{font-size:13px;color:var(--accent-text);font-weight:500;
         letter-spacing:.02em}
.cons-note{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
           gap:22px;margin-top:26px;font-size:16px;color:var(--ink2)}
.cons-note strong{color:var(--ink);display:block;margin-bottom:3px}

/* ── Jobs ──────────────────────────────────────────────────────────────
   Outcomes, for the visitor who is still working out what they need. */
.jobs{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:20px}
.job{background:var(--surface);border:1px solid var(--border);
     border-radius:var(--radius-card);padding:22px 20px}
.job h3{font-family:var(--f-head);font-size:17px;font-weight:700;margin-bottom:6px}
.job p{font-size:15px;color:var(--ink2);line-height:1.5}

/* The other half of the same answer: the visitor who already knows the
   name of the thing they want, and only needs to see it listed. Set as
   a plain run of names rather than 17 more cards -- it is an index, and
   an index that looks like a menu of decisions is worse at both jobs. */
.cat{margin-top:30px;padding-top:24px;border-top:1px solid var(--border)}
.cat-h{font-size:15px;color:var(--ink2);margin-bottom:12px}
.cat-list{display:flex;flex-wrap:wrap;gap:8px}
.cat-list span{font-size:14px;color:var(--ink);background:var(--surface);
               border:1px solid var(--border);border-radius:3px;padding:5px 11px}

/* ── Order form ────────────────────────────────────────────────────────
   On navy, because this is the page's primary conversion surface and the
   navy bands are what the eye stops at. Same rule as everywhere else
   holds: no orange on this ground -- the submit button is white. */
.order-sec{background:var(--ink);color:#fff;padding:var(--gap-major) 0}
/* align-items:center, not start. The form is the taller column by a long
   way -- it has eight fields and a captcha against four lines of copy --
   so top-aligning left the copy hanging at the top of a tall empty navy
   panel. Centring splits that leftover height above and below the copy
   instead of dumping all of it underneath, which is what makes the two
   columns read as a pair rather than as one column and one orphan.
   Cheaper and more robust than padding the left column out with text
   nobody needs. */
.order-grid{display:grid;grid-template-columns:.85fr 1.15fr;gap:52px;align-items:center}
.order-copy h2{font-family:var(--f-head);font-size:32px;font-weight:700;
               letter-spacing:-.025em;line-height:1.2;margin:0 0 14px;color:#fff}
.order-copy p{font-size:17px;color:var(--on-navy-2);margin-bottom:20px}
.order-pts{list-style:none;margin:0;padding:0;font-size:15.5px;color:var(--on-navy-2)}
.order-pts li{padding:7px 0 7px 22px;position:relative}
.order-pts li::before{content:"✓";position:absolute;left:0;color:#fff;font-weight:700}

.order-form{background:#fff;border-radius:var(--radius-card);padding:26px 24px;
            color:var(--ink)}
/* The kind switch is the form's first and most consequential control, so
   it is a pair of large targets rather than a dropdown or a checkbox
   buried further down. */
.kind{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:20px}
.kind-opt{display:flex;align-items:flex-start;gap:9px;cursor:pointer;
          border:1px solid var(--c-field-border);border-radius:var(--radius);
          padding:12px 13px;transition:border-color .15s,background .15s}
.kind-opt:hover{border-color:var(--accent)}
.kind-opt input{margin-top:3px;flex-shrink:0;accent-color:var(--accent-text)}
.kind-opt span{font-size:14px;color:var(--ink2);line-height:1.35}
.kind-opt strong{display:block;font-size:15px;color:var(--ink);font-weight:700}
.kind-opt:has(input:checked){border-color:var(--accent);background:#FFF9F5}
.kind-opt:focus-within{outline:2px solid var(--accent-text);outline-offset:2px}

.of-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.of-f{margin-bottom:12px;display:flex;flex-direction:column}
.of-f label{font-size:13.5px;font-weight:500;color:var(--ink2);margin-bottom:5px}
.of-f .opt{color:var(--muted);font-weight:400}
.of-f input,.of-f select,.of-f textarea{
    font:inherit;font-size:15px;padding:10px 12px;border-radius:var(--radius);
    border:1px solid var(--c-field-border);background:#fff;color:var(--ink);width:100%}
.of-f input:focus,.of-f select:focus,.of-f textarea:focus{
    outline:2px solid var(--accent-text);outline-offset:1px;border-color:var(--accent)}
.of-f textarea{resize:vertical}
.of-cap{align-items:end}
.cap-wrap{display:flex;align-items:center;gap:8px}
.cap-img{height:44px;border:1px solid var(--c-field-border);border-radius:var(--radius);
         background:#fff}
.cap-reload{font:inherit;font-size:17px;line-height:1;cursor:pointer;padding:9px 11px;
            border:1px solid var(--c-field-border);border-radius:var(--radius);
            background:#fff;color:var(--ink2)}
.cap-reload:hover{border-color:var(--accent);color:var(--accent-text)}
.of-consent{display:flex;align-items:flex-start;gap:9px;font-size:14px;
            color:var(--ink2);margin:4px 0 18px;line-height:1.45}
.of-consent input{margin-top:3px;flex-shrink:0;width:auto;accent-color:var(--accent-text)}
.of-submit{font:inherit;font-size:16px;font-weight:700;width:100%;padding:14px;
           border:0;border-radius:var(--radius);background:var(--ink);color:#fff;
           cursor:pointer}
.of-submit:hover{background:var(--accent-hover)}
.of-submit:disabled{opacity:.6;cursor:default}
.of-msg{margin-top:12px;font-size:14.5px;min-height:1.2em}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
         white-space:nowrap}

/* ── Closing CTA ───────────────────────────────────────────────────────
   The live page's only conversion surface is a five-field contact form
   with an image captcha and a consent checkbox, at the bottom of 1,649
   words -- and when registration is switched off, EVERY primary button
   on the page funnels into it. Here the close is two links and the form
   lives on its own page, reachable in one click from anywhere. */
.close{background:var(--ink);color:#fff;padding:88px 0;text-align:center}
.close h2{font-family:var(--f-head);font-size:38px;font-weight:700;
          letter-spacing:-.03em;margin-bottom:14px}
.close p{font-size:19px;color:var(--on-navy-2);max-width:34em;margin:0 auto 30px}
.close .hero-btns{justify-content:center}

/* ── Deferred sections ─────────────────────────────────────────────────
   PREVIEW SCAFFOLD, not part of the proposal.

   Five bands come off this page in the redesign (Analytics, Lifecycle,
   Industries, Production, About) and the proposal is that each becomes
   its own page. Building five pages before the structure is agreed would
   be the wrong order, so for now these link back to the LIVE homepage's
   anchors -- which is why the row is labelled as such rather than
   dressed up as finished navigation. On adoption this row is deleted and
   the links move into the nav as real destinations. */
.deferred{border-top:1px dashed #cbd5e1;background:#fffbeb;padding:26px 0}
.deferred .wrap{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:baseline}
.deferred b{font-size:13px;letter-spacing:.05em;text-transform:uppercase;color:#92400e}
.deferred a{font-size:15px;color:#92400e}
.deferred small{width:100%;font-size:13.5px;color:#a16207}

/* ── Footer ────────────────────────────────────────────────────────── */
/* --c-navy-deep, which is what Optrical uses for its own footer body.
   It reads as one step down from the --c-navy bands above it, so the
   page darkens as it ends rather than repeating the same navy a fourth
   time. (Optrical splits a --c-navy-black bar below this one; there is
   nothing here to put in it.) */
.foot{background:var(--ink-deep);color:var(--footer-text);padding:56px 0 40px;font-size:15px}
.foot .wrap{display:grid;grid-template-columns:1fr auto;gap:28px;align-items:start}
.foot .fbrand{font-family:var(--f-head);font-weight:700;font-size:21px;color:#fff}
/* The wordmark keeps its two colours everywhere: "O4" takes the ground's
   text colour, "QR" is always the spiral orange. It is the brand mark,
   not body copy, and a mark that changes colour per section stops being
   recognisable as one.

   This is the one sanctioned exception to "no orange on navy", and it
   clears the bar on the measurement rather than on the exception:
   #F26429 on --c-navy-deep is 5.02:1, comfortably AA, because the footer
   navy is darker than the band navy. The rule was always about large
   display text and hairlines looking muddy on #023151; a 21px/700
   wordmark on a darker ground is neither. */
.foot .fbrand span{color:var(--accent)}
.foot p{margin-top:10px;max-width:32em;line-height:1.6}
.foot a{color:var(--c-footer-icon);text-decoration:none}
.foot a:hover{color:#fff;text-decoration:underline}
.flinks{display:flex;flex-direction:column;gap:9px;text-align:right}
.fcopy{margin-top:34px;padding-top:20px;border-top:1px solid var(--c-footer-rule);
       font-size:14px;color:var(--footer-text)}

.banner{background:#fef3c7;border-bottom:1px solid #fcd34d;color:#78350f;
        font-size:14px;padding:9px 28px;text-align:center}
.banner a{color:#78350f;font-weight:700}

@media(max-width:900px){
    :root{--gap-major:72px;--gap-minor:30px}
    .hero-in{grid-template-columns:1fr;gap:36px}
    .hero{padding:64px 0}
    .hero h1{font-size:42px}
    .hero p{font-size:18px}
    /* Text FIRST on a phone. The visual is decorative -- it names no
       product and makes no claim -- and at 375px it filled the entire
       first screen, so the headline and the primary button both opened
       below the fold. Ordering it above the copy is a desktop habit
       that costs the whole above-the-fold pitch on the device most
       scanners actually arrive on. */
    .hero-visual{margin-top:8px;opacity:.9}
    .sec-title,.statement h2,.close h2{font-size:30px}
    .nav-links{display:none}
    .burger{display:block}
    .order-grid{grid-template-columns:1fr;gap:30px}
    .of-row{grid-template-columns:1fr;gap:0}
    .kind{grid-template-columns:1fr}
    .foot .wrap{grid-template-columns:1fr}
    .flinks{text-align:left;flex-direction:row;flex-wrap:wrap;gap:14px}
}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}
    .btn-primary:hover{transform:none}}

/* ── Nav: current-page marker ───────────────────────────────────────────────
   The base template sets nav_active per page. Without this the nav on a
   standalone page looked identical to the nav on every other page, so a
   visitor could not tell where they were. */
.nav-links a.current{color:var(--accent-text);font-weight:700}
.nav-mob a.current{color:var(--accent-text);font-weight:700}

/* ── Cookie banner ──────────────────────────────────────────────────────────
   Strictly-necessary cookies only, so this is a notice rather than a consent
   gate -- there is nothing to opt out of, and a page that blocks on a choice it
   is not going to honour is worse than one that just says what it does.
   Recoloured from the old #38bdf8 link to the brand: the ground is navy, so the
   link is white rather than orange. */
.cookie-banner{position:fixed;bottom:0;left:0;right:0;z-index:999;
               background:var(--ink-deep);color:var(--on-navy-2);
               padding:13px 22px;display:flex;gap:16px;align-items:center;
               flex-wrap:wrap;font-size:14px;line-height:1.5}
.cookie-banner p{margin:0;flex:1;min-width:200px}
.cookie-banner a{color:#fff;text-decoration:underline;text-underline-offset:2px}
.cookie-accept{font:inherit;padding:8px 18px;background:#fff;color:var(--ink);
               border:0;border-radius:var(--radius);font-weight:700;
               font-size:14px;cursor:pointer;flex-shrink:0}
.cookie-accept:hover{background:var(--surface)}

/* ── Prose pages (privacy, terms) ───────────────────────────────────────────
   One narrow measure and a real type scale, so a legal page is readable rather
   than merely present. */
.prose-page{max-width:none;padding:var(--gap-major) 0}
.prose-page .wrap{max-width:760px}
.prose-page h1{font-family:var(--f-head);font-size:38px;font-weight:700;
               letter-spacing:-.025em;margin-bottom:10px}
.prose-page .updated{font-size:15px;color:var(--muted);margin-bottom:36px}
.prose-page h2{font-family:var(--f-head);font-size:22px;font-weight:700;
               margin:34px 0 10px}
.prose-page h3{font-family:var(--f-head);font-size:18px;font-weight:700;margin:24px 0 8px}
.prose-page p,.prose-page li{font-size:16.5px;color:var(--ink2);line-height:1.7}
.prose-page p{margin-bottom:14px}
.prose-page ul,.prose-page ol{margin:0 0 16px 22px}
.prose-page li{margin-bottom:7px}

/* ── Standalone page header ─────────────────────────────────────────────────
   The promoted pages open with a compact dark header rather than the homepage's
   full hero: they are destinations somebody chose, so they need to confirm
   where you are, not sell you on arriving. */
.page-head{background:var(--ink);color:#fff;padding:64px 0 60px}
.page-head .kicker{font-size:12.5px;font-weight:700;letter-spacing:.12em;
                   text-transform:uppercase;color:var(--on-navy-2);margin-bottom:14px}
.page-head h1{font-family:var(--f-head);font-size:clamp(30px,4.4vw,44px);font-weight:700;
              letter-spacing:-.03em;line-height:1.1;margin-bottom:16px;max-width:18em}
.page-head p{font-size:19px;color:var(--on-navy-2);max-width:44em;line-height:1.55}

/* Bullets inside a card. The homepage's analytics band carried these as loose
   text; as a list they can be skimmed, which is the only way six cards of
   capability get read at all. */
.feat-list{list-style:none;margin:12px 0 0;padding:0}
.feat-list li{font-size:15px;color:var(--ink2);line-height:1.45;
              padding:5px 0 5px 18px;position:relative}
.feat-list li::before{content:"";position:absolute;left:0;top:12px;width:6px;height:6px;
                      border-radius:50%;background:var(--accent)}

/* ── Timeline ───────────────────────────────────────────────────────────────
   The lifecycle argument is chronological -- launch, month 6, year 1, year 2 --
   so the stage marker carries real information and earns its place. A numbered
   or dated rail on content that is NOT a sequence would be decoration. */
.tl{display:grid;gap:0;border-left:2px solid var(--border);margin-left:6px}
.tl-item{padding:0 0 30px 26px;position:relative}
.tl-item:last-child{padding-bottom:0}
.tl-item::before{content:"";position:absolute;left:-7px;top:6px;width:12px;height:12px;
                 border-radius:50%;background:var(--accent);border:2px solid var(--white)}
.tl-when{font-size:12.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
         color:var(--accent-text);margin-bottom:4px}
.tl-item h3{font-family:var(--f-head);font-size:19px;font-weight:700;margin-bottom:5px}
.tl-item p{font-size:16px;color:var(--ink2);max-width:52em}

/* ── Catalogue rows ─────────────────────────────────────────────────────────
   Every QR action by its own name. A row per action rather than a card per
   action: this is an index somebody scans for one word, and 17 cards would read
   as 17 decisions to make. */
.uc-row{display:grid;grid-template-columns:minmax(160px,220px) 1fr;gap:20px;
        padding:16px 0;border-bottom:1px solid var(--border);align-items:baseline}
.uc-row:last-child{border-bottom:0}
.uc-row dt{font-family:var(--f-head);font-size:17px;font-weight:700;color:var(--ink)}
.uc-row dd{margin:0;font-size:16px;color:var(--ink2);line-height:1.5}
@media(max-width:640px){.uc-row{grid-template-columns:1fr;gap:4px}}

/* ── Pricing model ──────────────────────────────────────────────────────────
   The three meters a buyer is actually billed on. Off the homepage because a
   first-time visitor does not need the billing ontology to decide whether to
   keep reading; here because somebody comparing plans genuinely does. */
.meters{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px}
.meter{background:var(--surface);border:1px solid var(--border);
       border-radius:var(--radius-card);padding:24px 22px}
.meter h3{font-family:var(--f-head);font-size:19px;font-weight:700;margin-bottom:6px}
.meter > p{font-size:15.5px;color:var(--ink2);margin-bottom:12px}
.meter-rate{display:flex;flex-wrap:wrap;gap:7px;margin-top:14px}
.meter-rate span{font-size:13px;background:var(--white);border:1px solid var(--border);
                 border-radius:3px;padding:4px 9px;color:var(--ink)}
.meter-rate span.free{border-color:var(--accent);color:var(--accent-text);font-weight:600}

/* ── Credentials ────────────────────────────────────────────────────────────
   Proof, for a page with no salesperson behind it. Deliberately NOT the card
   treatment: these are facts about the company, and boxing each one makes them
   look like features. */
.creds{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:28px}
.cred h3{font-family:var(--f-head);font-size:18px;font-weight:700;margin-bottom:6px;
         color:var(--accent-text)}
.cred p{font-size:16px;color:var(--ink2);line-height:1.55}

/* ── Figures ────────────────────────────────────────────────────────────────
   A diagram is not a card: no fill, no shadow, just a hairline and room to
   breathe, so it reads as an illustration of the argument rather than as
   another item in a grid.

   overflow-x on the container, not the page. Several of these diagrams have a
   min-width wider than a phone (scan-path is three rows of a journey and does
   not usefully reflow), so the FIGURE scrolls sideways while the page body
   never does. The caption stays put outside the scroll area. */
.figure{margin:var(--gap-minor) 0 0}
.figure-inner{overflow-x:auto;border:1px solid var(--border);
              border-radius:var(--radius-card);background:var(--surface);
              padding:18px}
.figure img{display:block;width:100%;height:auto}
.figure img.wide{min-width:620px}
.figure figcaption{margin-top:10px;font-size:14.5px;color:var(--muted);max-width:60em}

/* ── Steps ──────────────────────────────────────────────────────────────────
   A numbered sequence, used for the scan flow on /use-cases. The marker earns
   its place here because the content genuinely is ordered: a code cannot be
   logged before it is resolved, or answered before it is logged. Numbering
   anything that is not a sequence would be decoration.

   160px, not 180: five steps at 180 need 972px of track inside a 964px column,
   so step five dropped onto a row of its own and the sequence stopped reading
   as one flow. */
.steps{counter-reset:s;list-style:none;display:grid;margin:0;padding:0;
       grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:18px}
.steps li{counter-increment:s;background:var(--surface);border:1px solid var(--border);
          border-radius:var(--radius-card);padding:22px 20px}
.steps li::before{content:counter(s);display:flex;align-items:center;justify-content:center;
                  width:28px;height:28px;border-radius:50%;background:var(--accent-text);
                  color:#fff;font-weight:700;font-size:14px;margin-bottom:14px}
.steps strong{display:block;font-size:17px;margin-bottom:4px}
.steps span{font-size:15px;color:var(--ink2);line-height:1.45}
