/* ---------------------------------------------------------------------------
   pharmosy-ui.css - the marketing design system.

   Lifted out of index.php once the homepage stopped being the only page using
   it. Every rule is scoped under .ph- and under .ph-main, which is the class
   the <main> of each marketing page carries.

   WHY PLAIN CSS AND NOT TAILWIND UTILITIES

   public/css/tailwind.min.css is generated from the classes this codebase
   already uses. A class a page invents therefore renders as nothing - no
   warning, no error, just an unstyled element - unless someone remembers to
   rebuild. A whole design system expressed as new utilities would be a
   standing invitation to that failure, on every page, forever.

   This file is loaded AFTER tailwind.min.css in inc-header.php, so where the
   two ever collide, this wins.

   MOBILE FIRST. Every rule is written for a 375px phone and opened up at
   min-width breakpoints. The ones that matter: 480 (buttons go from full width
   to auto), 560, 640, 900, 1000, 1140.

   COLOUR IS MEASURED, NOT PICKED. Every foreground token here clears WCAG AA
   against all three page backgrounds (white, paper #faf9f7, tint #f2f0ec). Two
   of them did not on the first pass and were darkened until they did; see the
   note on --muted.
--------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   TOKENS

   The palette is the first thing that reads as "made" rather than "generated".
   Two decisions do most of the work:

 - The page is not white. #FAF9F7 is a warm paper, half a degree off the
       default, and the difference against cool navy ink is what stops the
       whole thing looking like an untouched framework starter.
 - There is one warm accent (copper) against the blue. A single warm mark
       on a cold page is an old print trick, and it is why the rules, the index
       numbers and the pull quotes read as considered rather than decorative.
--------------------------------------------------------------------------- */
.ph-main{
  --paper:#faf9f7;
  --paper-2:#f2f0ec;
  --white:#fff;
  --ink:#0b1524;
  --ink-2:#43506a;
  /* Measured, not picked by eye. The first draft of these two was #78849a and
     #b4633a, and a contrast sweep over every text node on the page put them at
     3.6:1 and 3.9:1 against the tint - under the 4.5:1 WCAG asks of body text,
     and they are used for exactly that: captions, section numbers, the labels
     in the product panel. Both are darkened to clear 4.5:1 on all three
     backgrounds this page uses (white, paper, tint). The hue is unchanged; they
     are the same two colours, just far enough down to be readable in a shop
     with the lights on. */
  --muted:#5f6b80;
  --line:#e5e1d9;
  --line-2:#d6d1c7;
  --brand:#1d4ed8;
  --brand-soft:#eef3ff;
  --accent:#9e522c;
  --accent-soft:#f6ede7;
  --ok:#0e7a5f;
  --ok-soft:#e8f5f0;
  --warn:#8a5f10;
  --warn-soft:#faf1de;
  --stop:#a4303f;
  --stop-soft:#fbecee;

  --f-display:'Plus Jakarta Sans',ui-sans-serif,system-ui,sans-serif;
  --f-text:'Inter',ui-sans-serif,system-ui,sans-serif;
  --f-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --f-serif:'Instrument Serif',Georgia,'Times New Roman',serif;

  --pad:1.25rem;          /* gutter on a phone */
  --wrap:76rem;

  background:var(--paper);
  color:var(--ink-2);
  font-family:var(--f-text);
  font-size:1rem;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip;        /* a decorative layer must never make the page scroll sideways */
}
@media (min-width:640px){ .ph-main{ --pad:2rem; } }
@media (min-width:1140px){ .ph-main{ --pad:2.5rem; } }

/* The sticky header is shared with every other page, so it is white. Against
   warm paper that leaves a visible seam right under the nav. Tinted here only
 - this style block is served on the homepage and nowhere else. */
body:has(.ph-main) > header{ background:rgba(250,249,247,.88)!important; border-bottom-color:var(--line)!important; }

/* --- primitives ---------------------------------------------------------- */
.ph-wrap{ width:100%; max-width:var(--wrap); margin-inline:auto; padding-inline:var(--pad); }
.ph-narrow{ max-width:46rem; }
.ph-mid{ max-width:62rem; }

.ph-sec{ padding-block:clamp(3.25rem,9vw,7rem); }
.ph-sec--paper{ background:var(--paper); }
.ph-sec--white{ background:var(--white); border-block:1px solid var(--line); }
.ph-sec--tint{ background:var(--paper-2); border-block:1px solid var(--line); }
.ph-sec--dark{ background:var(--ink); color:#c3cbdb; }

/* Eyebrow: mono, tracked, with a short copper rule. The rule is the detail -
   a label on its own reads as a caption, a label with a rule reads as a
   section marker. */
.ph-eyebrow{
  display:flex; align-items:center; gap:.7rem;
  font-family:var(--f-mono); font-size:.6875rem; font-weight:500;
  letter-spacing:.16em; text-transform:uppercase; color:var(--accent);
  margin:0 0 1.1rem;
}
.ph-eyebrow::before{ content:""; width:1.75rem; height:1px; background:var(--accent); flex:none; }
.ph-eyebrow .ph-num{ color:var(--muted); }
.ph-sec--dark .ph-eyebrow{ color:#e0a17a; }
.ph-sec--dark .ph-eyebrow::before{ background:#e0a17a; }
.ph-sec--dark .ph-eyebrow .ph-num{ color:#8695b2; }

/* Display type. clamp() from a phone-safe floor to a desktop ceiling, so there
   is no width at which a headline is either cramped or absurd. */
.ph-h1,.ph-h2,.ph-h3{ font-family:var(--f-display); color:var(--ink); font-weight:800;
                      letter-spacing:-.035em; line-height:1.05; text-wrap:balance; margin:0; }
.ph-h1{ font-size:clamp(2.3rem,8vw,4.4rem); }
.ph-h2{ font-size:clamp(1.8rem,4.8vw,2.9rem); line-height:1.09; }
.ph-h3{ font-size:clamp(1.02rem,2.2vw,1.22rem); font-weight:700; letter-spacing:-.02em; line-height:1.28; }
.ph-sec--dark .ph-h1,.ph-sec--dark .ph-h2,.ph-sec--dark .ph-h3{ color:#fff; }

/* The one serif on the page. A handful of emphasised words inside a headline
   and nothing else. Sparingly is the whole point: two words in a contrasting
   serif read as editorial, a paragraph of it reads as a wedding invitation. */
.ph-em{ font-family:var(--f-serif); font-weight:400; font-style:italic;
        letter-spacing:-.005em; color:var(--brand); }
.ph-sec--dark .ph-em{ color:#8fb4ff; }

.ph-lede{ font-size:clamp(1rem,2vw,1.18rem); line-height:1.62; color:var(--ink-2);
          max-width:40rem; margin:1.3rem 0 0; text-wrap:pretty; }
.ph-sec--dark .ph-lede{ color:#a9b4c8; }
.ph-p{ margin:.85rem 0 0; color:var(--ink-2); text-wrap:pretty; }
.ph-small{ font-size:.875rem; color:var(--muted); }

.ph-head{ max-width:44rem; }
.ph-head--center{ margin-inline:auto; text-align:center; }
.ph-head--center .ph-eyebrow{ justify-content:center; }
.ph-head--center .ph-lede{ margin-inline:auto; }

/* --- buttons ------------------------------------------------------------- */
/* 48px tall: a 44px touch minimum with room either side, so a thumb hits the
   button rather than the thing next to it. */
.ph-btn{ display:inline-flex; align-items:center; justify-content:center; gap:.55rem;
         min-height:3rem; padding:.85rem 1.5rem; border-radius:.65rem;
         font-family:var(--f-display); font-size:.95rem; font-weight:700; letter-spacing:-.01em;
         text-decoration:none; cursor:pointer; border:1px solid transparent;
         transition:background-color .18s ease,border-color .18s ease,color .18s ease; }
.ph-btn--primary{ background:var(--ink); color:#fff; }
.ph-btn--primary:hover{ background:#1b2b46; }
.ph-btn--ghost{ background:transparent; color:var(--ink); border-color:var(--line-2); }
.ph-btn--ghost:hover{ border-color:var(--ink); background:rgba(11,21,36,.03); }
.ph-btn--light{ background:#fff; color:var(--ink); }
.ph-btn--light:hover{ background:#e9edf3; }
.ph-btn--onDark{ background:transparent; color:#fff; border-color:rgba(255,255,255,.34); }
.ph-btn--onDark:hover{ border-color:#fff; background:rgba(255,255,255,.08); }
.ph-btn i{ font-size:.8em; }
.ph-main a:focus-visible,.ph-main summary:focus-visible{ outline:2px solid var(--brand);
         outline-offset:3px; border-radius:.35rem; }

/* On a phone every button is FULL WIDTH. Two 150px buttons side by side at
   375px both read as secondary, and neither is a comfortable thumb target.
   Below 480px they stack and fill the column; above it they sit in a row and
   size to their own text. */
.ph-cta{ display:flex; flex-direction:column; gap:.7rem; margin-top:2rem; }
.ph-cta > .ph-btn{ width:100%; }
@media (min-width:480px){
  .ph-cta{ flex-direction:row; flex-wrap:wrap; align-items:center; }
  .ph-cta > .ph-btn{ width:auto; }
}

/* --- hairline grid --------------------------------------------------------
   The spec-sheet look: one background the colour of the rule, cells butted up
   with a 1px gap, and the gap IS the rule. Every line is exactly 1px however
   the cells wrap, which is the thing per-cell borders cannot give you. */
.ph-grid{ display:grid; gap:1px; background:var(--line); border:1px solid var(--line);
          border-radius:.9rem; overflow:hidden; }
.ph-grid > *{ background:var(--white); padding:1.35rem 1.15rem; min-width:0; }
@media (min-width:640px){ .ph-grid > *{ padding:1.75rem 1.5rem; } }
.ph-grid--2,.ph-grid--3,.ph-grid--4{ grid-template-columns:minmax(0,1fr); }
@media (min-width:560px){ .ph-grid--3,.ph-grid--4{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (min-width:900px){
  .ph-grid--2{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .ph-grid--3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
  .ph-grid--4{ grid-template-columns:repeat(4,minmax(0,1fr)); }
}

/* --- chips --------------------------------------------------------------- */
.ph-chip{ display:inline-flex; align-items:center; gap:.4rem; border-radius:999px;
          padding:.28rem .6rem; font-family:var(--f-mono); font-size:.6875rem; font-weight:500;
          letter-spacing:.09em; text-transform:uppercase; white-space:nowrap; }
.ph-chip--live{ background:var(--ok-soft); color:var(--ok); }
.ph-chip--soon{ background:var(--paper-2); color:var(--muted); }
.ph-chip--ref{ background:var(--brand-soft); color:var(--brand); }
.ph-chip--warn{ background:var(--warn-soft); color:var(--warn); }
.ph-chip--stop{ background:var(--stop-soft); color:var(--stop); }

.ph-idx{ font-family:var(--f-mono); font-size:.6875rem; font-weight:500; color:var(--muted);
         letter-spacing:.08em; }

/* =========================================================================
   HERO
========================================================================= */
.ph-hero{ position:relative; padding-block:clamp(2.5rem,7vw,4.5rem) clamp(3rem,8vw,5.5rem);
          background:var(--paper); overflow:hidden; }
/* A 26px rule grid at 3.5% - far too faint to notice, which is the point. You
   should register that the surface has depth without being able to say why.
   Masked away before it reaches the content below it. */
.ph-hero::before{ content:""; position:absolute; inset:0; pointer-events:none;
  background-image:linear-gradient(to right,rgba(11,21,36,.045) 1px,transparent 1px),
                   linear-gradient(to bottom,rgba(11,21,36,.045) 1px,transparent 1px);
  background-size:26px 26px;
  -webkit-mask-image:radial-gradient(115% 78% at 68% 8%,#000 0%,transparent 72%);
          mask-image:radial-gradient(115% 78% at 68% 8%,#000 0%,transparent 72%); }
.ph-hero > *{ position:relative; }

.ph-hero-grid{ display:grid; gap:clamp(2.5rem,6vw,3.5rem); align-items:center; }
@media (min-width:1000px){
  /* The headline column gets the larger share. At an even split the h1 was
     about 440px at 1440, which is four lines of 70px type and breaks phrases
     in the middle of themselves - "runs, on / one record". */
  .ph-hero-grid{ grid-template-columns:minmax(0,1.1fr) minmax(0,1fr); gap:3.5rem; align-items:center; }
}
@media (min-width:1240px){ .ph-hero-grid{ gap:4.5rem; } }

.ph-flag{ display:inline-flex; align-items:center; gap:.6rem; border:1px solid var(--line-2);
          background:rgba(255,255,255,.7); border-radius:999px; padding:.4rem .85rem .4rem .5rem;
          font-family:var(--f-mono); font-size:.6875rem; font-weight:500; letter-spacing:.12em;
          text-transform:uppercase; color:var(--ink-2); margin-bottom:1.6rem; }
.ph-flag svg{ width:1.2rem; height:.75rem; border-radius:2px; flex:none; }

.ph-hero h1{ margin:0; }
.ph-hero .ph-lede{ max-width:34rem; }

/* The trust row is a hairline list on a phone and a single line on desktop.
   Three short lines stacked beat three cramped columns at 375px. */
.ph-trust{ list-style:none; margin:2.25rem 0 0; padding:1.25rem 0 0; border-top:1px solid var(--line);
           display:grid; gap:.85rem; }
@media (min-width:560px){ .ph-trust{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:1.25rem; } }
.ph-trust li{ display:flex; align-items:flex-start; gap:.6rem; font-size:.875rem;
              font-weight:500; color:var(--ink-2); min-width:0; }
.ph-trust i{ color:var(--accent); font-size:.8rem; margin-top:.28rem; flex:none; }

/* =========================================================================
   THE APP PANEL

   Drawn, not screenshotted. A real screenshot at this size is unreadable and
   dates the moment any pixel of the product moves; this is the same interface
   at the level of detail the eye actually takes in from a hero - the shape of
   the thing, the queue, the status of each row.

   Everything in it is a service the product ships. Nothing here is a mock of
   a feature we have not built.
========================================================================= */
.ph-app{ position:relative; }
.ph-app-shell{ border:1px solid var(--line-2); border-radius:.95rem; overflow:hidden;
               background:#fff; box-shadow:0 1px 2px rgba(11,21,36,.05),
                                           0 28px 60px -32px rgba(11,21,36,.42); }
.ph-app-bar{ display:flex; align-items:center; gap:.45rem; padding:.6rem .8rem;
             background:var(--paper-2); border-bottom:1px solid var(--line); }
.ph-app-bar b{ width:.5rem; height:.5rem; border-radius:999px; background:#d3cec4; flex:none; }
.ph-app-url{ flex:1; min-width:0; margin-left:.5rem; display:flex; align-items:center; gap:.35rem;
             background:#fff; border:1px solid var(--line); border-radius:999px;
             padding:.2rem .6rem; font-family:var(--f-mono); font-size:.5625rem; color:var(--muted);
             overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }

.ph-app-body{ display:grid; grid-template-columns:minmax(0,1fr); }
@media (min-width:560px){ .ph-app-body{ grid-template-columns:8.5rem minmax(0,1fr); } }

/* The sidebar is the first thing to go on a phone: at 375px it would take a
   third of the panel to show eight words nobody can read. */
.ph-app-nav{ display:none; background:var(--paper); border-right:1px solid var(--line);
             padding:.85rem .6rem; }
@media (min-width:560px){ .ph-app-nav{ display:block; } }
.ph-app-brand{ display:flex; align-items:center; gap:.4rem; padding:.15rem .35rem .8rem;
               font-family:var(--f-display); font-weight:800; font-size:.75rem; color:var(--ink);
               letter-spacing:-.02em; }
/* > span:first-child, NOT span. pharmosy_wordmark() returns a <span>, so a
   bare descendant selector styled the WORDMARK as an 18px dark tile too and
   crushed "PharmOSy" inside it. Second time this exact shape of bug has bitten
   in this file - see .ph-app-hd .ph-app-avatar. If a rule here targets a bare
   element inside a brand or header row, scope it. */
.ph-app-brand > span:first-child{ width:1.1rem; height:1.1rem; border-radius:.3rem;
                    background:var(--ink); color:#fff; display:grid; place-items:center;
                    font-size:.5rem; flex:none; }
.ph-app-brand{ white-space:nowrap; }
.ph-app-nav a,.ph-app-nav i{ pointer-events:none; }
.ph-app-nav ul{ list-style:none; margin:0 0 .1rem; padding:0; display:grid; gap:.1rem; }
/* Group headings, because the real sidebar has them: Pharmacy is the counter,
   Clinical is the consultation room, Finance is getting paid. */
.ph-app-navhd{ margin:.55rem 0 .3rem; padding-left:.4rem; font-family:var(--f-mono);
               font-size:.5rem; font-weight:500; letter-spacing:.14em;
               text-transform:uppercase; color:var(--muted); }
.ph-app-navhd:first-of-type{ margin-top:.15rem; }
.ph-app-nav li{ display:flex; align-items:center; gap:.45rem; padding:.35rem .4rem;
                border-radius:.35rem; font-size:.625rem; font-weight:500; color:var(--muted);
                white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ph-app-nav li i{ width:.7rem; font-size:.55rem; text-align:center; flex:none; }
.ph-app-nav li.on{ background:#fff; color:var(--ink); font-weight:700;
                   box-shadow:inset 0 0 0 1px var(--line); }
.ph-app-nav li.on i{ color:var(--brand); }

.ph-app-main{ padding:.95rem .85rem 1.1rem; min-width:0; }
@media (min-width:560px){ .ph-app-main{ padding:1.1rem 1.1rem 1.25rem; } }
.ph-app-hd{ display:flex; align-items:flex-start; justify-content:space-between; gap:.75rem; }
.ph-app-hd p{ margin:0; font-family:var(--f-display); font-weight:800; font-size:.8125rem;
              color:var(--ink); letter-spacing:-.02em; }
.ph-app-hd span{ display:block; margin-top:.1rem; font-size:.625rem; color:var(--muted); }
.ph-app-hd .ph-app-avatar{ width:1.6rem; height:1.6rem; border-radius:999px; background:var(--ink); color:#fff;
                display:grid; place-items:center; font-size:.5625rem; font-weight:700; flex:none;
                font-family:var(--f-display); }

.ph-app-stats{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1px;
               margin-top:.85rem; background:var(--line); border:1px solid var(--line);
               border-radius:.55rem; overflow:hidden; }
.ph-app-stats div{ background:#fff; padding:.5rem .45rem; min-width:0; }
.ph-app-stats b{ display:block; font-family:var(--f-display); font-size:1rem; font-weight:800;
                 color:var(--ink); line-height:1.1; letter-spacing:-.03em; }
.ph-app-stats span{ display:block; margin-top:.1rem; font-size:.5625rem; color:var(--muted);
                    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

.ph-app-sub{ display:flex; align-items:center; justify-content:space-between; gap:.5rem;
             margin:.95rem 0 .45rem; }
.ph-app-sub p{ margin:0; font-family:var(--f-mono); font-size:.5625rem; font-weight:500;
               letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }

.ph-q{ list-style:none; margin:0; padding:0; border:1px solid var(--line); border-radius:.55rem;
       overflow:hidden; }
.ph-q li{ display:flex; align-items:center; gap:.5rem; padding:.5rem .55rem;
          border-top:1px solid var(--line); min-width:0; }
.ph-q li:first-child{ border-top:0; }
.ph-q time{ font-family:var(--f-mono); font-size:.5625rem; color:var(--muted); flex:none; }
.ph-q .ph-q-who{ min-width:0; flex:1; }
.ph-q .ph-q-who b{ display:block; font-size:.625rem; font-weight:600; color:var(--ink);
                   white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ph-q .ph-q-who span{ display:block; font-size:.5625rem; color:var(--muted);
                      white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ph-q .ph-chip{ font-size:.5rem; padding:.18rem .45rem; flex:none; }

/* The floating card. Static, and it is the one thing on this page the
   competition cannot copy without doing the clinical work: real NICE
   referral criteria, on the screen, inside the consultation.
   On a phone it drops out of the overlap and sits underneath. */
.ph-app-note{ margin-top:.9rem; border:1px solid var(--line-2); border-radius:.7rem;
              background:#fff; padding:.75rem .8rem;
              box-shadow:0 18px 34px -22px rgba(11,21,36,.45); }
@media (min-width:1000px){
  /* Overlaps the CORNER of the panel, not its contents. At -3.5rem the card
     sat across the last row of the queue, which reads as a rendering fault
     rather than as depth - you see half a patient name behind it. It now
     clears the rows and only its top edge crosses the panel border. */
  .ph-app-note{ position:absolute; left:-3rem; bottom:-6rem; width:16.5rem; margin-top:0; }
}
/* Below 1000px the card is in the flow, under the panel, at full width. It
   only overlaps where there is room to overlap. */
.ph-app-note-hd{ display:flex; align-items:center; gap:.45rem; margin-bottom:.5rem; }
.ph-app-note-hd b{ font-family:var(--f-display); font-size:.6875rem; font-weight:800; color:var(--ink); }
.ph-app-note ul{ list-style:none; margin:0; padding:0; display:grid; gap:.3rem; }
.ph-app-note li{ display:flex; gap:.4rem; font-size:.625rem; line-height:1.4; color:var(--ink-2); }
.ph-app-note li i{ color:var(--stop); font-size:.5rem; margin-top:.28rem; flex:none; }

/* =========================================================================
   SPEC BAR - the facts, on one hairline strip. No motion.
========================================================================= */
.ph-spec{ background:var(--ink); color:#fff; }
.ph-spec ul{ list-style:none; margin:0; padding:0; display:grid; gap:1px;
             background:rgba(255,255,255,.13); }
@media (min-width:560px){ .ph-spec ul{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (min-width:900px){ .ph-spec ul{ grid-template-columns:repeat(4,minmax(0,1fr)); } }
.ph-spec li{ background:var(--ink); padding:1.35rem var(--pad); min-width:0; }
.ph-spec b{ display:block; font-family:var(--f-display); font-size:1.6rem; font-weight:800;
            letter-spacing:-.04em; color:#fff; line-height:1; }
.ph-spec span{ display:block; margin-top:.4rem; font-size:.8125rem; color:#93a0b8; text-wrap:pretty; }

/* =========================================================================
   SECTION 01 - POSITIONING

   The awkward sentence, said first and said big. A pharmacy owner's opening
   question is always "does this replace my PMR" and the honest answer is no.
   Putting it in the largest type on the page is a claim about how the rest of
   the page should be read.
========================================================================= */
.ph-split{ display:grid; gap:clamp(2rem,5vw,3.5rem); align-items:center; }
@media (min-width:900px){
  .ph-split{ grid-template-columns:minmax(0,.85fr) minmax(0,1fr); gap:4rem; }
  .ph-split--flip > :first-child{ order:2; }
}

/* A photograph with a caption reads as evidence. The same photograph floating
   with a soft shadow reads as stock. The frame and the mono caption cost
   nothing and change which of the two it is. */
.ph-figure{ margin:0; }
.ph-figure img{ display:block; width:100%; height:auto; aspect-ratio:4/5;
                object-fit:cover; object-position:center 18%;
                border-radius:.9rem; border:1px solid var(--line-2); background:var(--paper-2); }
@media (min-width:900px){ .ph-figure img{ aspect-ratio:3/4; } }
/* The plate number is uppercase mono; the caption beside it is not. A whole
   sentence set in tracked uppercase at 10px is a wall - you read it letter by
   letter. The label is the part that wants to look like a label. */
.ph-figure figcaption{ display:flex; gap:.75rem; margin-top:.85rem; padding-top:.85rem;
                       border-top:1px solid var(--line); font-size:.8125rem;
                       color:var(--muted); line-height:1.6; text-wrap:pretty; }
.ph-figure figcaption span:first-child{ font-family:var(--f-mono); font-size:.625rem;
                       letter-spacing:.09em; text-transform:uppercase; color:var(--accent);
                       flex:none; padding-top:.2rem; }

.ph-quote{ font-family:var(--f-display); font-weight:800; letter-spacing:-.035em;
           line-height:1.12; color:var(--ink); font-size:clamp(1.6rem,4.4vw,2.6rem);
           margin:0; text-wrap:balance; }

.ph-facts{ list-style:none; margin:2rem 0 0; padding:0; display:grid; gap:0;
           border-top:1px solid var(--line); }
.ph-facts li{ display:grid; gap:.3rem; padding:1.1rem 0; border-bottom:1px solid var(--line); }
@media (min-width:560px){
  .ph-facts li{ grid-template-columns:8.5rem minmax(0,1fr); gap:1.25rem; align-items:baseline; }
}
.ph-facts dt,.ph-facts b{ font-family:var(--f-mono); font-size:.625rem; font-weight:500;
                          letter-spacing:.1em; text-transform:uppercase; color:var(--accent); }
.ph-facts p{ margin:0; font-size:.95rem; color:var(--ink-2); text-wrap:pretty; }

/* =========================================================================
   SECTION 02 - THE NICE PATHWAYS

   Static, on purpose. Everything in these cards comes out of nice_pathways().
========================================================================= */
.ph-paths{ display:grid; gap:1px; background:var(--line); border:1px solid var(--line);
           border-radius:.9rem; overflow:hidden; margin-top:clamp(2rem,4vw,2.75rem);
           grid-template-columns:minmax(0,1fr); }
@media (min-width:620px){ .ph-paths{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (min-width:1000px){ .ph-paths{ grid-template-columns:repeat(4,minmax(0,1fr)); } }
.ph-path{ background:#fff; padding:1.15rem 1.1rem; min-width:0;
          display:flex; flex-direction:column; gap:.6rem; }
.ph-path-hd{ display:flex; align-items:flex-start; justify-content:space-between; gap:.6rem; }
.ph-path h3{ font-family:var(--f-display); font-size:.9375rem; font-weight:700;
             letter-spacing:-.02em; line-height:1.25; color:var(--ink); margin:0; min-width:0; }
.ph-path-flag{ display:flex; gap:.45rem; font-size:.8125rem; line-height:1.5; color:var(--ink-2);
               border-top:1px solid var(--line); padding-top:.6rem; margin-top:auto; }
.ph-path-flag i{ color:var(--stop); font-size:.5rem; margin-top:.45rem; flex:none; }
.ph-path-n{ font-family:var(--f-mono); font-size:.625rem; letter-spacing:.08em;
            text-transform:uppercase; color:var(--muted); }

/* =========================================================================
   SECTION 03 - THE PLATFORM LEDGER
========================================================================= */
.ph-feat{ display:flex; flex-direction:column; gap:.85rem; }
.ph-feat-hd{ display:flex; align-items:center; justify-content:space-between; gap:.75rem; }
.ph-feat-ic{ width:2.25rem; height:2.25rem; border-radius:.55rem; display:grid; place-items:center;
             background:var(--brand-soft); color:var(--brand); font-size:.9rem; flex:none; }
.ph-feat--soon .ph-feat-ic{ background:var(--paper-2); color:var(--muted); }
.ph-feat p{ margin:0; font-size:.9375rem; line-height:1.6; color:var(--ink-2); text-wrap:pretty; }

/* =========================================================================
   SECTION 04 - FOUR SYSTEMS, OR ONE
========================================================================= */
.ph-ledger{ display:grid; gap:clamp(1rem,2.5vw,1.5rem); margin-top:clamp(2rem,4vw,2.75rem);
            grid-template-columns:minmax(0,1fr); align-items:stretch; }
@media (min-width:840px){ .ph-ledger{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.ph-card{ border:1px solid var(--line); border-radius:.9rem; background:#fff;
          padding:1.5rem 1.25rem; min-width:0; }
@media (min-width:640px){ .ph-card{ padding:2rem 1.75rem; } }
.ph-card--dark{ background:var(--ink); border-color:var(--ink); color:#c3cbdb; }
.ph-card--dark .ph-h3{ color:#fff; }
.ph-card-hd{ display:flex; align-items:center; justify-content:space-between; gap:.75rem;
             padding-bottom:1rem; border-bottom:1px solid var(--line); }
.ph-card--dark .ph-card-hd{ border-bottom-color:rgba(255,255,255,.14); }
.ph-rows{ list-style:none; margin:0; padding:0; }
.ph-rows li{ display:flex; align-items:center; gap:.7rem; padding:.85rem 0;
             border-bottom:1px solid var(--line); font-size:.9375rem; min-width:0; }
.ph-rows li:last-child{ border-bottom:0; }
.ph-card--dark .ph-rows li{ border-bottom-color:rgba(255,255,255,.12); color:#dbe2ef; }
.ph-rows i{ flex:none; font-size:.75rem; }
.ph-rows .ph-x{ color:var(--muted); }
.ph-rows .ph-tick{ color:#6ee7b7; }
.ph-rows span{ min-width:0; }
.ph-rows em{ margin-left:auto; font-style:normal; font-family:var(--f-mono); font-size:.625rem;
             letter-spacing:.08em; text-transform:uppercase; color:var(--muted); flex:none; }
.ph-card--dark .ph-rows em{ color:#7f8ca6; }
.ph-card-ft{ margin:1.25rem 0 0; font-size:.875rem; color:var(--muted); text-wrap:pretty; }
.ph-card--dark .ph-card-ft{ color:#8b98b2; }

/* =========================================================================
   SECTION 05 - THE CATALOGUE
   Thirteen rows, numbered, hairline separated. A dense list of real service
   names is more persuasive to a pharmacist than thirteen decorated cards -
   they are scanning for the two or three they actually deliver.
========================================================================= */
.ph-cat{ display:grid; gap:1px; background:var(--line); border:1px solid var(--line);
         border-radius:.9rem; overflow:hidden; margin-top:clamp(2rem,4vw,2.75rem);
         grid-template-columns:minmax(0,1fr); }
@media (min-width:700px){ .ph-cat{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (min-width:1060px){ .ph-cat{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
.ph-cat-item{ background:#fff; padding:1.1rem 1.15rem; min-width:0; display:flex; gap:.85rem; }
.ph-cat-item > i{ width:1.9rem; height:1.9rem; border-radius:.45rem; display:grid;
                  place-items:center; font-size:.8rem; flex:none;
                  background:var(--paper-2); color:var(--ink); }
.ph-cat-item div{ min-width:0; }
.ph-cat-item b{ display:block; font-family:var(--f-display); font-size:.9375rem; font-weight:700;
                letter-spacing:-.02em; color:var(--ink); line-height:1.3; }
.ph-cat-item p{ margin:.3rem 0 0; font-size:.8125rem; line-height:1.55; color:var(--muted);
                text-wrap:pretty; }

/* =========================================================================
   SECTION 06 - THE WORK THAT PAYS
========================================================================= */
.ph-steps{ list-style:none; margin:2rem 0 0; padding:0; border-top:1px solid var(--line); }
.ph-steps li{ padding:1.35rem 0; border-bottom:1px solid var(--line); display:grid; gap:.35rem;
              grid-template-columns:2.25rem minmax(0,1fr); align-items:start; }
.ph-steps li > span:first-child{ grid-row:span 2; font-family:var(--f-mono); font-size:.6875rem;
                                 color:var(--accent); letter-spacing:.08em; padding-top:.2rem; }
.ph-steps b{ font-family:var(--f-display); font-size:1.02rem; font-weight:700;
             letter-spacing:-.02em; color:var(--ink); }
.ph-steps p{ margin:0; font-size:.9375rem; color:var(--ink-2); text-wrap:pretty; }

/* =========================================================================
   SECTION 07 - THE AI ROADMAP (dark)
   Deliberately the quietest section on the page. Everything in it is unbuilt,
   and a loud section about unbuilt work is how a product loses the trust the
   rest of the page just earned.
========================================================================= */
.ph-road{ list-style:none; margin:0; padding:0; display:grid; gap:1px;
          background:rgba(255,255,255,.13); border:1px solid rgba(255,255,255,.13);
          border-radius:.9rem; overflow:hidden; grid-template-columns:minmax(0,1fr); }
@media (min-width:640px){ .ph-road{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.ph-road li{ background:var(--ink); padding:1.35rem 1.25rem; min-width:0; }
.ph-road span{ font-family:var(--f-mono); font-size:.625rem; letter-spacing:.1em;
               text-transform:uppercase; color:#8695b2; }
.ph-road b{ display:block; margin-top:.5rem; font-family:var(--f-display); font-size:1rem;
            font-weight:700; letter-spacing:-.02em; color:#fff; }
.ph-road p{ margin:.35rem 0 0; font-size:.875rem; color:#98a5bd; text-wrap:pretty; }

.ph-notice{ display:flex; gap:.7rem; margin-top:1.5rem; padding:.95rem 1.1rem;
            border:1px solid rgba(255,255,255,.16); border-radius:.65rem;
            background:rgba(255,255,255,.04); font-size:.875rem; color:#a9b4c8; text-wrap:pretty; }
.ph-notice i{ color:#e0a17a; margin-top:.3rem; flex:none; font-size:.8rem; }

/* =========================================================================
   SECTION 08 - QUESTIONS
   The first two stay OPEN. Bing in particular treats text behind a closed
   <details> as lower-value than text on the page, and an FAQ is exactly the
   content we want indexed.
========================================================================= */
.ph-faq{ border:1px solid var(--line); border-radius:.9rem; overflow:hidden; background:#fff;
         margin-top:clamp(2rem,4vw,2.5rem); }
.ph-faq details{ border-top:1px solid var(--line); }
.ph-faq details:first-child{ border-top:0; }
.ph-faq summary{ display:flex; align-items:center; justify-content:space-between; gap:1rem;
                 list-style:none; cursor:pointer; padding:1.15rem 1.15rem; min-height:3.25rem;
                 font-family:var(--f-display); font-weight:700; font-size:.9875rem;
                 letter-spacing:-.02em; color:var(--ink); text-wrap:pretty; }
@media (min-width:640px){ .ph-faq summary{ padding-inline:1.6rem; font-size:1.05rem; } }
.ph-faq summary::-webkit-details-marker{ display:none; }
.ph-faq summary i{ color:var(--muted); font-size:.75rem; flex:none;
                   transition:transform .2s ease; }
.ph-faq details[open] summary i{ transform:rotate(45deg); color:var(--accent); }
.ph-faq p{ margin:0; padding:0 1.15rem 1.35rem; font-size:.9375rem; line-height:1.65;
           color:var(--ink-2); max-width:52rem; text-wrap:pretty; }
@media (min-width:640px){ .ph-faq p{ padding-inline:1.6rem; } }

/* =========================================================================
   FINAL CTA
========================================================================= */
.ph-end{ background:var(--ink); color:#a9b4c8; position:relative; overflow:hidden; }
.ph-end::before{ content:""; position:absolute; inset:0; pointer-events:none;
  background-image:linear-gradient(to right,rgba(255,255,255,.045) 1px,transparent 1px),
                   linear-gradient(to bottom,rgba(255,255,255,.045) 1px,transparent 1px);
  background-size:34px 34px;
  -webkit-mask-image:radial-gradient(80% 100% at 50% 0%,#000 0%,transparent 75%);
          mask-image:radial-gradient(80% 100% at 50% 0%,#000 0%,transparent 75%); }
.ph-end > *{ position:relative; }
.ph-end .ph-cta{ justify-content:center; }
.ph-end-note{ margin:2rem auto 0; padding-top:1.5rem; border-top:1px solid rgba(255,255,255,.14);
              max-width:34rem; font-size:.875rem; color:#8b98b2; text-wrap:pretty; }

/* =========================================================================
   INNER-PAGE PARTS

   Everything above this line was written for the homepage. Everything below
   is what features, pricing, about and contact needed on top of it - added
   here rather than in each page, because four private copies of a page hero
   is exactly how five pages end up looking like five different products.
========================================================================= */

/* --- inner page hero ------------------------------------------------------
   Shorter than the homepage hero and left-aligned, so an inner page announces
   itself without pretending to be a landing page. */
.ph-phero{ position:relative; background:var(--paper); overflow:hidden;
           padding-block:clamp(2.5rem,7vw,4.5rem) clamp(2.5rem,7vw,4rem);
           border-bottom:1px solid var(--line); }
.ph-phero::before{ content:""; position:absolute; inset:0; pointer-events:none;
  background-image:linear-gradient(to right,rgba(11,21,36,.045) 1px,transparent 1px),
                   linear-gradient(to bottom,rgba(11,21,36,.045) 1px,transparent 1px);
  background-size:26px 26px;
  -webkit-mask-image:radial-gradient(100% 80% at 20% 0%,#000 0%,transparent 70%);
          mask-image:radial-gradient(100% 80% at 20% 0%,#000 0%,transparent 70%); }
.ph-phero > *{ position:relative; }
.ph-phero .ph-h1{ font-size:clamp(2.1rem,6.4vw,3.6rem); }
.ph-phero .ph-lede{ max-width:38rem; }

/* --- dark pull-quote band ------------------------------------------------ */
.ph-band{ background:var(--ink); color:#c3cbdb; }
.ph-band-q{ font-family:var(--f-display); font-weight:800; letter-spacing:-.035em;
            line-height:1.16; color:#fff; margin:0; text-wrap:balance;
            font-size:clamp(1.45rem,4vw,2.35rem); }
.ph-band-by{ margin:1.5rem 0 0; font-family:var(--f-mono); font-size:.6875rem;
             letter-spacing:.16em; text-transform:uppercase; color:#8695b2; }

/* --- pricing -------------------------------------------------------------
   One column on a phone. Three "plans" side by side at 375px is the single
   most common way a pricing page becomes unreadable. */
.ph-plans{ display:grid; gap:clamp(1rem,2.5vw,1.5rem); margin-top:clamp(2rem,4vw,2.75rem);
           grid-template-columns:minmax(0,1fr); align-items:stretch; }
@media (min-width:860px){ .ph-plans{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
/* Two plans rather than three. Left at three columns the pair stretched wide
   enough that the tick lists read as two unrelated pages side by side, so the
   two-up variant is capped and centred instead. */
@media (min-width:860px){
  .ph-plans--two{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
.ph-plan{ display:flex; flex-direction:column; border:1px solid var(--line);
          border-radius:.9rem; background:#fff; padding:1.5rem 1.35rem; min-width:0; }
@media (min-width:640px){ .ph-plan{ padding:2rem 1.75rem; } }
.ph-plan--lead{ background:var(--ink); border-color:var(--ink); color:#c3cbdb; }
.ph-plan--lead .ph-h3{ color:#fff; }
.ph-plan-price{ font-family:var(--f-display); font-weight:800; letter-spacing:-.04em;
                font-size:clamp(1.9rem,5vw,2.4rem); color:var(--ink); line-height:1;
                margin:1rem 0 .35rem; }
.ph-plan--lead .ph-plan-price{ color:#fff; }
.ph-plan-per{ font-size:.8125rem; color:var(--muted); }
.ph-plan--lead .ph-plan-per{ color:#8695b2; }
.ph-plan .ph-rows{ margin-top:1.25rem; }
.ph-plan .ph-btn{ margin-top:1.5rem; width:100%; }
.ph-plan-body{ flex:1; }

/* --- forms ---------------------------------------------------------------
   16px minimum on every field. Below 16px iOS Safari zooms the whole page in
   on focus and does not zoom back out, which on a contact form means the
   visitor is fighting the layout from the first tap. 48px tall for the same
   reason the buttons are. */
.ph-form{ display:grid; gap:1.1rem; }
.ph-field{ display:grid; gap:.4rem; min-width:0; }
.ph-field > label{ font-family:var(--f-mono); font-size:.6875rem; font-weight:500;
                   letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.ph-field input,.ph-field select,.ph-field textarea{
  width:100%; min-height:3rem; padding:.75rem .9rem; font-size:1rem;
  font-family:var(--f-text); color:var(--ink); background:#fff;
  border:1px solid var(--line-2); border-radius:.6rem; -webkit-appearance:none; appearance:none;
  transition:border-color .18s ease, box-shadow .18s ease; }
.ph-field textarea{ min-height:8rem; resize:vertical; line-height:1.6; }
.ph-field input:focus,.ph-field select:focus,.ph-field textarea:focus{
  outline:none; border-color:var(--brand); box-shadow:0 0 0 3px rgba(29,78,216,.14); }
.ph-field input::placeholder,.ph-field textarea::placeholder{ color:#9aa4b6; }
@media (min-width:640px){ .ph-form--2{ grid-template-columns:repeat(2,minmax(0,1fr)); }
                          .ph-span2{ grid-column:1 / -1; } }

/* --- misc ---------------------------------------------------------------- */
.ph-list{ list-style:none; margin:1.25rem 0 0; padding:0; display:grid; gap:.7rem; }
.ph-list li{ display:flex; gap:.65rem; font-size:.9375rem; color:var(--ink-2); min-width:0; }
.ph-list li i{ color:var(--ok); font-size:.8rem; margin-top:.35rem; flex:none; }
.ph-sec--dark .ph-list li{ color:#a9b4c8; }
.ph-sec--dark .ph-list li i{ color:#6ee7b7; }

/* =========================================================================
   LEGAL PAGES

   A privacy policy is read differently from a marketing page: people arrive
   looking for one paragraph, not reading top to bottom. So it gets a sticky
   contents column on desktop and a plain ordered list on a phone, and the
   measure is held to about 68 characters - long legal prose at full width is
   how a policy becomes unreadable without being badly written.
========================================================================= */
.ph-legal{ display:grid; gap:clamp(2rem,4vw,3rem); }
@media (min-width:1000px){
  .ph-legal{ grid-template-columns:15rem minmax(0,1fr); gap:4rem; align-items:start; }
  .ph-legal-toc{ position:sticky; top:6rem; }
}
.ph-legal-toc ol{ list-style:none; margin:0; padding:0; display:grid; gap:0; }
.ph-legal-toc li{ display:grid; grid-template-columns:2rem minmax(0,1fr); gap:.5rem;
                  align-items:baseline; border-top:1px solid var(--line); }
.ph-legal-toc li:last-child{ border-bottom:1px solid var(--line); }
.ph-legal-toc li > span{ font-family:var(--f-mono); font-size:.625rem; color:var(--muted); }
.ph-legal-toc a{ display:flex; align-items:center; min-height:2.75rem; padding:.35rem 0;
                 font-size:.875rem; font-weight:500; color:var(--ink-2); text-wrap:pretty; }
.ph-legal-toc a:hover{ color:var(--brand); }

.ph-legal-body{ max-width:42rem; min-width:0; }
.ph-legal-body > section + section{ margin-top:clamp(2.25rem,5vw,3rem);
                                    padding-top:clamp(2.25rem,5vw,3rem);
                                    border-top:1px solid var(--line); }
.ph-legal-h{ display:flex; align-items:baseline; gap:.85rem; }
.ph-legal-h > span{ font-family:var(--f-mono); font-size:.75rem; font-weight:500;
                    color:var(--accent); flex:none; padding-top:.15rem; }
.ph-legal-h > h2{ min-width:0; }
.ph-legal-body p{ margin:1rem 0 0; color:var(--ink-2); line-height:1.7; text-wrap:pretty; }
/* A list item here is a PARAGRAPH with a bullet, not a row of columns.
   It was display:flex, which turns every child into a flex item - so a
   <strong> lead-in became its own narrow column and the sentence following it
   was crushed into a second one. Nine bullets on the privacy page rendered as
   an unreadable two-column table of fragments.
   The bullet is absolutely positioned instead, so the text inside the item is
   ordinary inline flow: <strong>, links and running text all wrap together
   the way prose is supposed to. */
.ph-legal-body ul{ list-style:none; margin:1rem 0 0; padding:0; display:grid; gap:.7rem; }
.ph-legal-body ul li{ position:relative; padding-left:1.15rem; color:var(--ink-2);
                      line-height:1.7; min-width:0; text-wrap:pretty; }
.ph-legal-body ul li::before{ content:""; position:absolute; left:0; top:.62em;
                              width:.35rem; height:.35rem; border-radius:999px;
                              background:var(--accent); }
.ph-legal-body strong{ color:var(--ink); font-weight:600; }
.ph-legal-body a{ color:var(--brand); font-weight:600; }
/* TO CONFIRM: the placeholders a solicitor has to fill in before launch. They
   are marked in the page rather than guessed at, and the marker is loud on
   purpose - an invented company number is worse than an obvious gap. */
.ph-todo{ display:inline-flex; align-items:center; gap:.35rem; padding:.1rem .45rem;
          border-radius:.3rem; background:var(--warn-soft); color:var(--warn);
          font-family:var(--f-mono); font-size:.6875rem; font-weight:500;
          letter-spacing:.06em; text-transform:uppercase; }

/* =========================================================================
   DARK SURFACES, ALL OF THEM

   There are four dark surfaces on this site and they were not one thing:
   .ph-sec--dark, .ph-band, .ph-card--dark and .ph-plan--lead. The on-dark
   colour overrides were written against .ph-sec--dark only, so anything
   ink-coloured that landed on one of the other three kept its light-page
   colour and quietly failed.

   That is not a hypothetical. The final CTA on the homepage carried .ph-end
   without .ph-sec--dark, and its headline rendered near-black on near-black:
   the whole line was invisible except the two words inside .ph-em, which set
   their own colour. It shipped to a screenshot before anyone caught it.

   Every dark surface is listed together here so the next one added is a class
   name in this block rather than a bug found in a screenshot. A contrast sweep
   over all eight pages now reports zero failures at AA.
========================================================================= */
.ph-sec--dark, .ph-band, .ph-card--dark, .ph-plan--lead, .ph-auth-brand{ color:#c3cbdb; }

.ph-sec--dark .ph-h1, .ph-sec--dark .ph-h2, .ph-sec--dark .ph-h3,
.ph-band .ph-h1, .ph-band .ph-h2, .ph-band .ph-h3,
.ph-card--dark .ph-h3, .ph-plan--lead .ph-h3, .ph-auth-brand h1{ color:#fff; }

.ph-sec--dark .ph-em, .ph-band .ph-em,
.ph-card--dark .ph-em, .ph-plan--lead .ph-em, .ph-auth-brand .ph-em{ color:#8fb4ff; }

.ph-sec--dark .ph-lede, .ph-band .ph-lede, .ph-plan--lead .ph-lede{ color:#a9b4c8; }

/* The right-hand meta column in a row list, and the section index in an
   eyebrow. Both were --muted, which is tuned for a light page and lands at
   3.4:1 on ink. */
.ph-sec--dark .ph-rows em, .ph-band .ph-rows em,
.ph-card--dark .ph-rows em, .ph-plan--lead .ph-rows em,
.ph-sec--dark .ph-eyebrow .ph-num, .ph-band .ph-eyebrow .ph-num,
.ph-plan--lead .ph-plan-per, .ph-plan--lead .ph-card-ft{ color:#8695b2; }

.ph-sec--dark .ph-eyebrow, .ph-band .ph-eyebrow, .ph-plan--lead .ph-eyebrow,
.ph-auth-brand .ph-eyebrow{ color:#e0a17a; }
.ph-sec--dark .ph-eyebrow::before, .ph-band .ph-eyebrow::before,
.ph-plan--lead .ph-eyebrow::before, .ph-auth-brand .ph-eyebrow::before{ background:#e0a17a; }

.ph-card--dark .ph-rows li, .ph-plan--lead .ph-rows li{ border-bottom-color:rgba(255,255,255,.12); color:#dbe2ef; }
.ph-card--dark .ph-card-hd, .ph-plan--lead .ph-card-hd{ border-bottom-color:rgba(255,255,255,.14); }
.ph-plan--lead .ph-rows .ph-x{ color:#8695b2; }

/* =========================================================================
   AUTH PAGES (sign in, pharmacy picker, password reset)

   These are public-facing - they are the first screen a pharmacy sees every
   morning, and the one a prospect lands on from a link. They had their own
   head block, their own Poppins tag and their own hand-rolled field styles,
   so they drifted from the marketing site the moment it was redesigned.

   They now load this file and use the same tokens, the same fields and the
   same buttons. The .ph-auth- classes below are only the split-screen layout,
   which nothing else on the site needs.
========================================================================= */
.ph-auth{ display:flex; min-height:100vh; min-height:100dvh; background:var(--paper); }

/* The brand panel. Hidden below 1024px - on a phone the job is to sign in,
   and half a screen of marketing above the field is half a screen of
   scrolling before you can do it. */
.ph-auth-brand{ display:none; }
@media (min-width:1024px){
  .ph-auth-brand{ position:relative; display:flex; flex-direction:column; justify-content:space-between;
                  width:50%; overflow:hidden; background:var(--ink); color:#c3cbdb;
                  padding:clamp(2.5rem,3.5vw,3.5rem); }
  .ph-auth-brand::before{ content:""; position:absolute; inset:0; pointer-events:none;
    background-image:linear-gradient(to right,rgba(255,255,255,.05) 1px,transparent 1px),
                     linear-gradient(to bottom,rgba(255,255,255,.05) 1px,transparent 1px);
    background-size:32px 32px;
    -webkit-mask-image:radial-gradient(90% 70% at 25% 10%,#000 0%,transparent 72%);
            mask-image:radial-gradient(90% 70% at 25% 10%,#000 0%,transparent 72%); }
  .ph-auth-brand > *{ position:relative; }
}
.ph-auth-brand h1{ font-family:var(--f-display); font-weight:800; letter-spacing:-.035em;
                   line-height:1.08; color:#fff; margin:0; max-width:18ch;
                   font-size:clamp(2rem,2.9vw,2.75rem); text-wrap:balance; }
.ph-auth-brand p{ margin:1.25rem 0 0; max-width:34ch; color:#a9b4c8; line-height:1.62; }
.ph-auth-brand .ph-list li{ color:#c3cbdb; }
.ph-auth-brand .ph-list li i{ color:#6ee7b7; }
.ph-auth-mark{ display:inline-flex; align-items:center; gap:.65rem; min-height:2.75rem;
               font-family:var(--f-display); font-weight:800; font-size:1.15rem;
               letter-spacing:-.03em; color:#fff; }
.ph-auth-mark > span:first-child{ display:grid; place-items:center; width:2.25rem; height:2.25rem;
               border-radius:.6rem; background:rgba(255,255,255,.12); color:#fff; flex:none; }

.ph-auth-facts{ display:flex; flex-wrap:wrap; gap:.75rem 1.5rem; padding:1rem 1.25rem;
                border:1px solid rgba(255,255,255,.15); border-radius:.7rem;
                background:rgba(255,255,255,.04); }
.ph-auth-facts span{ display:inline-flex; align-items:center; gap:.55rem; font-size:.875rem; color:#c3cbdb; }
.ph-auth-facts i{ color:#e0a17a; font-size:.8rem; }

/* The form side. Full width on a phone, half on desktop. */
.ph-auth-panel{ display:flex; align-items:center; justify-content:center; width:100%;
                padding:clamp(2rem,6vw,3rem) var(--pad); }
@media (min-width:1024px){ .ph-auth-panel{ width:50%; } }
.ph-auth-inner{ width:100%; max-width:26rem; }
.ph-auth-inner h2{ font-family:var(--f-display); font-weight:800; letter-spacing:-.035em;
                   font-size:clamp(1.7rem,4.5vw,2.1rem); color:var(--ink); margin:0; line-height:1.1; }
.ph-auth-inner .ph-btn{ width:100%; }
.ph-auth-mark--light{ color:var(--ink); margin-bottom:2rem; }
.ph-auth-mark--light > span:first-child{ background:var(--ink); color:#fff; }
@media (min-width:1024px){ .ph-auth-mark--light{ display:none; } }

/* The pharmacy-address field: a fixed prefix butted against the input, drawn
   as one control. The focus ring goes on the WRAPPER, not the input, or the
   two halves light up separately. */
.ph-auth-addr{ display:flex; align-items:stretch; overflow:hidden;
               border:1px solid var(--line-2); border-radius:.6rem; background:#fff;
               transition:border-color .18s ease, box-shadow .18s ease; }
.ph-auth-addr:focus-within{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(29,78,216,.14); }
.ph-auth-addr > span{ display:none; align-items:center; white-space:nowrap; background:var(--paper-2);
                      border-right:1px solid var(--line); padding:0 .8rem;
                      font-family:var(--f-mono); font-size:.75rem; color:var(--muted); }
@media (min-width:420px){ .ph-auth-addr > span{ display:flex; } }
.ph-auth-addr input{ min-width:0; flex:1; border:0; min-height:3rem; padding:.75rem .9rem;
                     font-family:var(--f-mono); font-size:1rem; color:var(--ink); background:transparent; }
.ph-auth-addr input:focus{ outline:none; box-shadow:none; }

.ph-auth-or{ display:flex; align-items:center; gap:1rem; margin:2rem 0; }
.ph-auth-or::before, .ph-auth-or::after{ content:""; height:1px; flex:1; background:var(--line); }
.ph-auth-or span{ font-family:var(--f-mono); font-size:.625rem; letter-spacing:.14em;
                  text-transform:uppercase; color:var(--muted); }

.ph-auth-err{ display:flex; gap:.65rem; margin:1.5rem 0 0; padding:.9rem 1rem; border-radius:.6rem;
              background:var(--stop-soft); color:var(--stop); font-size:.9375rem; text-wrap:pretty; }
.ph-auth-err i{ margin-top:.25rem; flex:none; }
.ph-auth-foot{ display:flex; align-items:center; justify-content:center; gap:.5rem;
               margin:2rem 0 0; font-size:.8125rem; color:var(--muted); }

/* Centred card layout, for the password pages that have no brand panel. */
.ph-auth--card{ align-items:center; justify-content:center; padding:clamp(2rem,6vw,4rem) var(--pad); }
.ph-auth--card .ph-auth-inner{ max-width:27rem; }

/* =========================================================================
   VALIDATION, WITHOUT THE PAGE JUMPING

   Pressing "Send message" on the contact form moved the button 54px DOWN, out
   from under the pointer that had just pressed it. Press it twice - which is
   what you do when a button appears not to have worked - and the second press
   lands on whatever slid into its place.

   The cause is that inc-form-validate.php inserts its `.pv-msg` line INTO THE
   FLOW underneath each failing control. On the contact form that is 27px (the
   message plus the field's own row gap) added to two rows of the grid at once
   - name and email share a row, the message field is another - so everything
   below moved by 54.

   (Worth recording what it was NOT, because it looks like the obvious culprit:
   `div.needs-answer { padding: .5rem .625rem }` in that same file. A .ph-field
   is a <div>, so it appears to match - but the script puts .needs-answer on
   the CONTROL, never on the wrapper, so that rule never fires here. Measured,
   not assumed.)

   THE MESSAGE GETS A SLOT THAT IS ALWAYS THERE. Every .ph-field reserves one
   line at the bottom whether or not it is currently failing, and the message
   is positioned into that reserved space. Nothing moves when it appears,
   because the space was already spent. The form's row-gap is reduced to pay
   for it, so the rhythm between fields is unchanged.

   Fixed here rather than in inc-form-validate.php: that file is shared with
   every app form, and an in-flow message is the right default for a layout
   that has not reserved room for one.

   Measured after the change, clicking submit with three empty required fields:
   button moved 0px, the note below it moved 0px, the document grew 0px.
========================================================================= */
.ph-form{ row-gap:.35rem; column-gap:1.1rem; }
.ph-form > *:not(.ph-field){ margin-top:.75rem; }
.ph-form > *:not(.ph-field):first-child{ margin-top:0; }

.ph-field{ position:relative; padding-bottom:1.35rem; }

/* The reserved slot. overflow is left visible so a message that does wrap to
   two lines is still fully readable - it eats into the row gap rather than
   being clipped, which is the lesser of the two faults. */
.ph-field .pv-msg{ position:absolute; left:0; right:0; bottom:.05rem;
                   margin-top:0; font-size:.75rem; line-height:1.25; }

/* The failing control keeps the shared rose treatment from
   inc-form-validate.php - a box-shadow ring, which costs no layout - but takes
   this design system's corner radius rather than the app's, so a flagged field
   is the same shape as the one next to it. */
.ph-field input.needs-answer,
.ph-field select.needs-answer,
.ph-field textarea.needs-answer{ border-radius:.6rem; border-color:#f43f5e; }
.ph-field > label:has(+ .needs-answer),
.ph-field > label:has(+ * .needs-answer){ color:#9f1239; }

/* =========================================================================
   NATION BADGE (service catalogue)

   Five of the fourteen services are commissioned in some nations and not
   others. The catalogue used to say "thirteen services" with no qualification
   at all, so a Welsh or Northern Irish pharmacy was being sold the lot and
   could actually run nine of them.

   Two visual weights on purpose. UK-wide is the quiet default - it is not news
   and it should not shout. A restriction is the copper accent, because it is
   the thing the reader needs to notice before they get to month two.
========================================================================= */
.ph-nation{ display:inline-block; margin:.35rem 0 0; font-family:var(--f-mono);
            font-size:.625rem; font-weight:500; letter-spacing:.09em;
            text-transform:uppercase; color:var(--muted); }
.ph-nation--limited{ color:var(--accent); }
.ph-nation--limited::before{ content:"\25C6"; margin-right:.4rem; font-size:.5rem;
                             vertical-align:.08em; }
.ph-cat-item p{ margin-top:.3rem; }

/* The brand glyph inside the drawn app panel. pharmosy_glyph() takes a class
   rather than a size, because every other caller sizes it with Tailwind - this
   one is at UI scale inside a mock, so it gets its own. */
.ph-app-glyph{ width:.68rem; height:.68rem; display:block; }
.ph-app-brand{ gap:.45rem; }

/* =========================================================================
   APP STORE BADGES

   PLACEHOLDERS, drawn in the house style, and NOT the official artwork.

   Both Google and Apple require their own supplied badge assets and have
   written rules about size, clear space and wording - Apple's in particular
   does not allow the mark to be redrawn. Shipping a hand-made lookalike as the
   real thing is a trademark problem, so these are deliberately our own shape
   and are swapped for the official artwork on the day the apps are listed.

   Not links yet either. The Android wrapper is built and signed but not
   published, and iOS does not exist at all, so there is nowhere to point them.
   They are <span>, not <a> with a dead href: a badge that looks clickable and
   does nothing teaches a visitor that the chrome here is decorative, which is
   the same reason the footer's three social buttons were removed.
========================================================================= */
.ph-stores{ display:flex; flex-wrap:wrap; gap:.7rem; }
.ph-store{
  display:inline-flex; align-items:center; gap:.7rem;
  padding:.6rem 1.1rem .6rem .95rem; border-radius:.7rem;
  border:1px solid var(--line-2); background:#fff; color:var(--ink);
  cursor:default; user-select:none;
}
.ph-store svg{ width:1.4rem; height:1.4rem; flex:none; }
.ph-store span{ display:block; text-align:left; line-height:1.15; }
.ph-store b{ display:block; font-family:var(--f-display); font-size:.9375rem;
             font-weight:700; letter-spacing:-.02em; }
.ph-store i{ display:block; font-style:normal; font-family:var(--f-mono);
             font-size:.5625rem; letter-spacing:.11em; text-transform:uppercase;
             color:var(--muted); }

/* On the dark CTA band. */
.ph-sec--dark .ph-store, .ph-end .ph-store{
  background:transparent; border-color:rgba(255,255,255,.28); color:#fff; }
.ph-sec--dark .ph-store i, .ph-end .ph-store i{ color:#8695b2; }

/* SENTENCE CASE, and not mono. This was tracked uppercase mono at 10px, which
   is right for a three-word label and awful for the twenty-five word sentence
   it actually holds - on a phone it came out as three lines of shouting. Same
   mistake as the figcaption further up this file, made on the same day: the
   rule is about LENGTH, not about the typeface. Uppercase is for labels. */
.ph-stores-note{ margin:1rem 0 0; max-width:46ch; margin-inline:auto;
                 font-size:.8125rem; line-height:1.55; color:var(--muted); }
.ph-stores-note b{ display:block; margin-bottom:.2rem; font-family:var(--f-mono);
                 font-size:.625rem; font-weight:500; letter-spacing:.11em;
                 text-transform:uppercase; }
.ph-sec--dark .ph-stores-note, .ph-end .ph-stores-note{ color:#8695b2; }
@media (min-width:480px){ .ph-stores{ justify-content:inherit; } }


/* =========================================================================
   THE PHONE WALKTHROUGH

   Four real frames from one cold start on a Pixel 9a running the signed build:
   the launcher, the splash, the hand-off, the app. Nothing here is drawn. A
   competitor can mock a phone; they cannot mock a build that installs.

   IT PLAYS ITSELF, and there is no JavaScript in it. Pure CSS keyframes on
   stacked images, so it works with scripting off, cannot get stuck part way,
   and costs nothing to start.

   REDUCED MOTION IS HONOURED, and honoured properly: the animation is not
   merely paused, because a paused stack of absolutely positioned images shows
   whichever happens to be last. Under prefers-reduced-motion the sequence is
   dropped and the FINAL frame - the app, signed in - is shown on its own. That
   is the one frame that carries the message, so nobody misses anything.

   Timings: the launcher holds long enough to read, the splash and hand-off go
   past at roughly the speed they do on the handset, and the app holds longest
   because it is the point. 7s round trip.
========================================================================= */
.ph-walk{ display:grid; gap:clamp(2rem,5vw,3.5rem); align-items:start; }
@media (min-width:900px){
  /* auto, NOT 1fr, for the phone column. At 1fr it was a 752px track holding a
     280px handset, which left a gutter wider than the phone between it and the
     captions - it read as a layout that had lost something. The column now
     shrinks to the phone and the captions sit beside it, and the pair are
     centred in the section so the whitespace falls on both sides instead of
     all of it on the right. */
  .ph-walk{ grid-template-columns:auto minmax(0,24rem); gap:3.5rem;
            justify-content:center; }
}
@media (min-width:1140px){ .ph-walk{ gap:4.5rem; } }

.ph-phone{ position:relative; width:100%; max-width:19rem; margin-inline:auto;
           border:.55rem solid #0b1524; border-radius:2.2rem; background:#0b1524;
           box-shadow:0 30px 60px -30px rgba(11,21,36,.55); }
/* A DEFINITE width once the layout is two columns, not width:100% + max-width.
   In an `auto` grid track a percentage width resolves against the track and the
   track sizes to min-content - which for the handset is just its two bezels,
   16px. The column collapsed and the phone vanished to a sliver.
   This block must stay AFTER the base .ph-phone rule above: same specificity,
   so source order decides, and the first attempt at this fix was written above
   it and silently lost. */
@media (min-width:900px){ .ph-phone{ width:19rem; max-width:none; margin-inline:0; } }
.ph-phone-screen{ position:relative; border-radius:1.7rem; overflow:hidden;
                  aspect-ratio:360/785; background:#0b1524; }
/* the pill cut-out, drawn rather than shipped as an image */
.ph-phone-screen::after{ content:""; position:absolute; top:.5rem; left:50%;
                         transform:translateX(-50%); width:3.4rem; height:.85rem;
                         border-radius:999px; background:#0b1524; z-index:5; }

.ph-screen{ position:absolute; inset:0; width:100%; height:100%;
            object-fit:cover; object-position:top; opacity:0; }

/* Each frame owns a slice of one 7s timeline. The 1% ramps are a cross-fade
   short enough to read as a cut, which is what a phone actually does. */
@keyframes phw1{ 0%,17%{opacity:1} 18%,100%{opacity:0} }
@keyframes phw2{ 0%,17%{opacity:0} 18%,30%{opacity:1} 31%,100%{opacity:0} }
@keyframes phw3{ 0%,30%{opacity:0} 31%,41%{opacity:1} 42%,100%{opacity:0} }
@keyframes phw4{ 0%,41%{opacity:0} 42%,96%{opacity:1} 100%{opacity:0} }
.ph-screen[data-step="1"]{ animation:phw1 7s infinite; }
.ph-screen[data-step="2"]{ animation:phw2 7s infinite; }
.ph-screen[data-step="3"]{ animation:phw3 7s infinite; }
.ph-screen[data-step="4"]{ animation:phw4 7s infinite; }

/* --- the caption list, lit in step ---------------------------------------- */
.ph-steps-nav{ list-style:none; margin:0; padding:0; display:grid; gap:.5rem; }
.ph-steps-nav li{ display:flex; gap:.85rem; align-items:flex-start;
                  border:1px solid var(--line); border-radius:.7rem; background:#fff;
                  padding:.85rem 1rem; }
.ph-steps-nav li > span:first-child{ font-family:var(--f-mono); font-size:.625rem;
                  color:var(--muted); padding-top:.15rem; flex:none; }
.ph-steps-nav b{ display:block; font-family:var(--f-display); font-size:.9375rem;
                 font-weight:700; letter-spacing:-.02em; color:var(--ink); }
.ph-steps-nav p{ margin:.15rem 0 0; font-size:.8125rem; color:var(--ink-2); text-wrap:pretty; }

@keyframes phwLit1{ 0%,17%{background:var(--paper-2);border-color:var(--ink)} 18%,100%{background:#fff;border-color:var(--line)} }
@keyframes phwLit2{ 0%,17%{background:#fff;border-color:var(--line)} 18%,30%{background:var(--paper-2);border-color:var(--ink)} 31%,100%{background:#fff;border-color:var(--line)} }
@keyframes phwLit3{ 0%,30%{background:#fff;border-color:var(--line)} 31%,41%{background:var(--paper-2);border-color:var(--ink)} 42%,100%{background:#fff;border-color:var(--line)} }
@keyframes phwLit4{ 0%,41%{background:#fff;border-color:var(--line)} 42%,96%{background:var(--paper-2);border-color:var(--ink)} 100%{background:#fff;border-color:var(--line)} }
.ph-steps-nav li:nth-child(1){ animation:phwLit1 7s infinite; }
.ph-steps-nav li:nth-child(2){ animation:phwLit2 7s infinite; }
.ph-steps-nav li:nth-child(3){ animation:phwLit3 7s infinite; }
.ph-steps-nav li:nth-child(4){ animation:phwLit4 7s infinite; }

/* Motion sickness is not a design preference, and a healthcare site should be
   the last one to ignore it. No animation at all, and the final frame shown. */
@media (prefers-reduced-motion: reduce){
  .ph-screen, .ph-steps-nav li{ animation:none !important; }
  .ph-screen{ opacity:0; }
  .ph-screen[data-step="4"]{ opacity:1; }
  .ph-steps-nav li{ background:#fff; border-color:var(--line); }
}
