/* ==========================================================================
   MANARA · the site stylesheet
   Design system: Meridian / Harbour. Written up in docs/design-system.md.
   Light mode : Harbour, exactly as approved 2026-08-09.
   Dark  mode : "ink and signal". Read docs/design-system.md before changing a
                token. Almost nothing is filled. The page is five greys and the
                dark itself carries the premium.
   Radius 4px everywhere. Mono is data only. No scroll animation, by brand rule.
   The one piece of full-page motion is the transition veil in section 23, which
   moves between pages and leaves the page itself as still as it ever was.

   Every page under site/ links this one file. It is the only place the tokens
   live, so a token changed here changes on every page at once. The demo page
   at /demo/ still carries its own copy of the tokens for its own components:
   see docs/design-system.md §1.

   THERE IS NO CALLOUT COMPONENT HERE, AND ONE IS NOT TO BE ADDED. A tinted box
   with an icon, a bold assertion and a sentence explaining the assertion is the
   house tell of machine-written copy, and it was removed from this site on
   purpose. If a sentence matters, it goes in the prose.
   ========================================================================== */

/* ---------- 0 · the display face, self hosted ---------- */
/* Newsreader is served from this origin rather than from the Google CDN, and it
   is the only family that has moved so far. The reason is the transition veil:
   Google Fonts costs two hops, the stylesheet on fonts.googleapis.com and then
   the file on fonts.gstatic.com, so the face is never registered by the time a
   new document paints its first frame. Measured on a warm cache, first paint at
   5ms and Newsreader usable at 19ms. The veil's panel is on screen from that
   first frame carrying the name of the page in this face, so what a visitor saw
   was one frame of Georgia and then a snap to Newsreader on every navigation.

   Self hosted, the @font-face is discovered while this stylesheet is parsed,
   which has to finish before first paint anyway, and the file is preloaded from
   the head of every page. It also costs fewer bytes than the CDN did: these are
   the Google latin subsets with the weight axis cut to what the site actually
   sets, 200 to 400 upright and 200 to 300 italic, 128KB and 143KB down to 91KB
   and 96KB. The optical size axis is kept in full because font-optical-sizing
   is auto by design: see docs/design-system.md §3.

   Newsreader is under the SIL Open Font License 1.1, and site/fonts/OFL.txt is
   the licence it requires to travel with. IBM Plex and Amiri are still on the
   CDN, which is why the CSP still names it. See README launch task 4.

   The unicode-range is Google's own latin subset. Anything outside it falls
   through to the stack in --display, which is the same behaviour as before. */
@font-face{
  font-family:'Newsreader';
  font-style:normal;
  font-weight:200 400;
  font-display:swap;
  src:url('/fonts/newsreader-normal.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
                U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
                U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Newsreader';
  font-style:italic;
  font-weight:200 300;
  font-display:swap;
  src:url('/fonts/newsreader-italic.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
                U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
                U+2212,U+2215,U+FEFF,U+FFFD;
}

/* The same file again under a second name, for the transition veil and nothing
   else. The difference is `optional`, and it is the point of the whole block.

   `swap` above is right for a page: on a cold visit the reader gets the words
   immediately in Georgia and the real face replaces it a moment later. That
   trade is wrong for the veil. Its panel carries one line of 54px display type
   and is on screen for under a second, so a face arriving late does not improve
   anything: it just changes the letterforms under the reader mid transition,
   which is the "the font changes and then goes back" this was reported as.

   `optional` removes the possibility rather than making it less likely. The
   browser gets a very short window to have the face ready; if it does, the
   label is Newsreader from the first frame, and if it does not, the label stays
   in the fallback for the life of that document. Either way nothing changes
   while it is being looked at. The fallback here is deliberately Georgia rather
   than var(--display): that stack starts with 'Newsreader', which would hand
   the swap straight back. No extra bytes, it is the same file and the same
   cache entry as the face above. */
@font-face{
  font-family:'Newsreader Veil';
  font-style:normal;
  font-weight:200 400;
  font-display:optional;
  src:url('/fonts/newsreader-normal.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
                U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
                U+2212,U+2215,U+FEFF,U+FFFD;
}

/* ---------- 1 · tokens, light ---------- */
:root{
  /* light is the default ground, whatever the operating system prefers,
     so scrollbars and form controls stay light too */
  color-scheme:light;
  /* ground */
  --paper:#FAFBFA;
  --paper-2:#E7ECEA;
  --paper-3:#D6E2DC;
  /* ink */
  --ink:#0D1211;
  --ink-soft:#36423F;
  --muted:#5C6A66;
  --line:rgba(13,18,17,.16);
  --line-soft:rgba(13,18,17,.08);
  /* scrollbar: the green, well down in alpha. Loud enough to belong to the page,
     quiet enough that a bar running the full height is not the loudest thing on it. */
  --scroll-thumb:rgba(12,74,62,.34);
  --scroll-thumb-hover:rgba(12,74,62,.60);
  /* the one colour, split into three named roles so the dark theme can
     move each one independently. This is the whole trick of "ink and signal". */
  --accent-surface:#0C4A3E;   /* a filled green surface */
  --accent-surface-2:#175C4C; /* its hover */
  --accent-mark:#0C4A3E;      /* a small mark on a pale ground: tick, key, rule */
  --accent-quiet:#7FB8A6;     /* a small mark ON a filled green surface */
  --on-accent:#FAFBFA;        /* type on a filled green surface */
  --on-accent-soft:rgba(250,251,250,.86);
  --btn-fg:#FBFBF9;           /* type inside the primary button */
  /* supporting. Two only, each with a job. */
  --slate:#2E4653;            /* the institutional register */
  --on-slate:#FAFBFA;
  --bone:#EFEDE6;             /* the patient register */
  /* semantic */
  --ok:#2F6B4F; --warn:#8C5A12; --danger:#9E3B2A; --info:#33566E;
  /* type is fixed. Do not swap a family: see docs/design-system.md §3 */
  --display:'Newsreader',Georgia,'Times New Roman',serif;
  --text:'IBM Plex Sans',system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,monospace;
  --ar-display:'Amiri','Times New Roman',serif;
  --ar-text:'IBM Plex Sans Arabic',system-ui,sans-serif;
  /* space, 4pt base */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:72px; --s9:112px; --s10:168px;
  /* geometry: Harbour is 4px, everywhere, no exceptions */
  --r:4px;
  --hair:1px;
  --shadow-1:0 1px 0 rgba(16,19,20,.06);
  --shadow-2:0 12px 32px -18px rgba(16,19,20,.45);
  /* motion */
  --ease-standard:cubic-bezier(.2,.6,.2,1);
  --ease-enter:cubic-bezier(0,.7,.2,1);
  --t-1:120ms; --t-2:220ms; --t-3:400ms; --t-4:700ms;
  /* shell */
  --maxw:1240px;
  --gut:var(--s5);
}
@media (min-width:900px){ :root{ --gut:var(--s7) } }

/* ---------- 2 · tokens, dark: "ink and signal" ---------- */
/* opt-in only: nothing here applies until the switch sets data-theme="dark" */
:root[data-theme="dark"]{
  color-scheme:dark;
  --paper:#0A0E0D;      /* the page */
  --paper-2:#101615;    /* lifted ground: page head, strips */
  --paper-3:#161E1C;    /* card ground */
  --ink:#EEF3F1;
  --ink-soft:#C3CDCA;
  --muted:#93A09C;
  --line:rgba(238,243,241,.14);
  --line-soft:rgba(238,243,241,.07);
  /* the mint, not the deep green: on a near-black ground the deep green disappears */
  --scroll-thumb:rgba(127,184,166,.26);
  --scroll-thumb-hover:rgba(127,184,166,.46);
  /* green stops being pale and becomes a deep surface again.
     The mint drops to a signal, used small, never as a field. */
  --accent-surface:#0E3B32;
  --accent-surface-2:#12483C;
  --accent-mark:#7FB8A6;
  --accent-quiet:#7FB8A6;
  --on-accent:#EEF3F1;
  --on-accent-soft:rgba(238,243,241,.82);
  --btn-fg:#08100E;
  --slate:#24343C;      /* institutional stays DARK in the dark theme.
                           The light slate inverted here was a 2:1 contrast fail. */
  --on-slate:#EEF3F1;
  --bone:#14201C;
  --ok:#7FB8A6; --warn:#DCA850; --danger:#E58B76; --info:#8FB4CC;
  --shadow-1:0 1px 0 rgba(0,0,0,.4);
  --shadow-2:0 12px 32px -18px rgba(0,0,0,.8);
}

/* ---------- 3 · reset and base ---------- */
*{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:88px;-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--text);font-weight:400;font-size:16px;line-height:1.6;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,svg{max-width:100%}
a{color:inherit}
::selection{background:var(--accent-surface);color:var(--on-accent)}
:focus-visible{outline:2px solid var(--accent-mark);outline-offset:3px;border-radius:var(--r)}
/* the mobile navigation panel is toggled with the hidden attribute and also
   carries a class, and a class beats the user agent's [hidden]{display:none} */
[hidden]{display:none!important}

/* ---------- 3a · scrollbar ---------- */
/* A default scrollbar is the one piece of chrome on the page that belongs to the
   browser rather than to Harbour, and it shows. This makes it ours: a 4px bar in
   the green, on no track at all, which is the same geometry as every other corner
   here. Standard properties first, for Firefox and Chrome 121 and up; the webkit
   block below is the fallback for Safari and older Chrome, where the transparent
   border plus background-clip is what gets the bar down to 4px with air around it. */
html{scrollbar-width:thin;scrollbar-color:var(--scroll-thumb) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{
  background:var(--scroll-thumb);background-clip:content-box;
  border:3px solid transparent;border-radius:var(--r);
}
::-webkit-scrollbar-thumb:hover{background:var(--scroll-thumb-hover);background-clip:content-box}
::-webkit-scrollbar-corner{background:transparent}
.skip{
  position:absolute;inset-inline-start:var(--s4);top:-64px;z-index:100;
  background:var(--ink);color:var(--paper);padding:10px 16px;border-radius:var(--r);
  font-size:13px;font-weight:500;text-decoration:none;transition:top var(--t-2) var(--ease-standard);
}
.skip:focus{top:var(--s4)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* Motion, per the brand book: nothing bounces, nothing scales on hover,
   and the page does not animate on scroll. Only ambient product state moves. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
}

/* ---------- 4 · type scale ---------- */
h1,h2,h3,h4{margin:0}
h1{
  font-family:var(--display);font-optical-sizing:auto;font-weight:200;
  font-size:clamp(38px,5.6vw,72px);line-height:1.02;letter-spacing:-.03em;
  max-width:15ch;
}
h1 em{font-style:italic;font-weight:200}
/* a page head heading is one step down from the landing page's, because it sits
   beside a standfirst rather than alone above a product card */
.phead h1{font-size:clamp(34px,4.6vw,58px);line-height:1.04;max-width:17ch}
h2{
  font-family:var(--display);font-optical-sizing:auto;font-weight:300;
  font-size:clamp(30px,4.2vw,50px);line-height:1.06;letter-spacing:-.02em;max-width:20ch;
}
h2 em{font-style:italic;font-weight:300}
/* h3 is the card title. The uppercase label style is a class, not a tag, so the
   heading LEVEL can follow the document outline while the look stays put. */
h3{font-family:var(--text);font-weight:600;font-size:16px;line-height:1.35;letter-spacing:-.005em}
.h-label{font-family:var(--text);font-weight:600;font-size:13px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
p{margin:0 0 var(--s4);max-width:68ch;color:var(--ink-soft)}
p:last-child{margin-bottom:0}
.lede{
  font-family:var(--display);font-weight:300;font-size:clamp(19px,2.1vw,25px);
  line-height:1.45;color:var(--ink);max-width:56ch;
}
.small{font-size:13.5px;line-height:1.6;color:var(--muted);max-width:72ch}
/* Labels are IBM Plex Sans at normal width. Mono is data only:
   numerals, identifiers, hex, code. Correction of 2026-08-09. */
.label{
  font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--muted);
}
.label.accent{color:var(--accent-mark)}
.num{font-family:var(--mono);font-size:12px;letter-spacing:.01em}
/* an inline link inside prose: underlined, because colour alone is not a
   distinguishing mark (WCAG 1.4.1) */
.tlink{color:var(--accent-mark);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
.tlink:hover{text-decoration-thickness:2px}

/* ---------- 5 · shell ---------- */
.wrap{max-width:var(--maxw);margin:0 auto;padding-inline:var(--gut)}
.band{border-top:var(--hair) solid var(--line-soft)}
section{padding-block:var(--s8)}
@media (min-width:900px){ section{padding-block:var(--s9)} }
/* A section head is the label and the heading, and nothing else. The green block
   that used to sit above it was removed in August 2026: it read as decoration,
   it appeared on every section on every page, and the label underneath was
   already doing the work of marking where a section starts. Do not put it back. */
.sechead{margin-bottom:var(--s7)}
.secnum{
  font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--accent-mark);margin-bottom:var(--s3);
}

/* ---------- 6 · grids ---------- */
.g2{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--s7);align-items:start}
.g3{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--s5)}
.g4{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:var(--s5)}
.split{display:grid;gap:var(--s7)}
@media (min-width:1000px){ .split{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr)} }

/* ---------- 7 · surfaces ---------- */
.panel{
  border:var(--hair) solid var(--line);background:var(--paper);
  border-radius:var(--r);padding:var(--s5);
}
.panel.tint{background:var(--paper-2);border-color:transparent}
.panel.wash{background:var(--paper-3);border-color:transparent;box-shadow:inset 4px 0 0 var(--accent-surface)}
:root[data-theme="dark"] .panel.wash{background:var(--paper-3);box-shadow:inset 4px 0 0 var(--accent-mark)}
.panel.slate{background:var(--slate);border-color:transparent;color:var(--on-slate)}
.panel.slate p,.panel.slate .small{color:color-mix(in srgb,var(--on-slate) 80%,transparent)}
.panel.slate h3{color:var(--on-slate)}
.panel.slate .label{color:color-mix(in srgb,var(--on-slate) 62%,transparent)}

/* ---------- 8 · lists ---------- */
ul.clean{list-style:none;padding:0;margin:0}
ul.clean li{position:relative;padding-inline-start:var(--s5);margin-bottom:var(--s3);color:var(--ink-soft);font-size:14.5px;line-height:1.55}
ul.clean li::before{content:"";position:absolute;inset-inline-start:0;top:.7em;width:12px;height:var(--hair);background:var(--accent-mark)}
ul.clean li:last-child{margin-bottom:0}
ul.clean li b{color:var(--ink);font-weight:600}
/* a long list reads better in two columns than as one tall stack, but only
   where there is room for it. break-inside keeps a bullet whole. */
@media (min-width:900px){
  ul.clean.two{columns:2;column-gap:var(--s7)}
  ul.clean.two li{break-inside:avoid;margin-bottom:var(--s4)}
}

.kv{display:grid;grid-template-columns:auto 1fr;gap:var(--s3) var(--s5);font-size:14px;align-items:baseline;margin:0}
.kv dt{font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;text-transform:uppercase;color:var(--muted);white-space:nowrap}
.kv dd{margin:0;color:var(--ink-soft)}

/* ---------- 9 · buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  font-family:var(--text);font-size:14.5px;font-weight:500;letter-spacing:.01em;line-height:1.2;
  padding:13px 22px;border:var(--hair) solid var(--accent-surface);background:var(--accent-surface);
  color:var(--btn-fg);border-radius:var(--r);cursor:pointer;text-decoration:none;
  transition:background var(--t-1) var(--ease-standard),border-color var(--t-1) var(--ease-standard),color var(--t-1) var(--ease-standard);
}
.btn:hover{background:var(--accent-surface-2);border-color:var(--accent-surface-2)}
.btn:active{transform:translateY(1px)}
/* in the dark theme the action is the mint, used once, at button size */
:root[data-theme="dark"] .btn{background:var(--accent-mark);border-color:var(--accent-mark);color:var(--btn-fg)}
:root[data-theme="dark"] .btn:hover{background:#9BCFBF;border-color:#9BCFBF}
.btn.sec{background:transparent;color:var(--ink);border-color:var(--line)}
.btn.sec:hover{background:transparent;border-color:var(--ink);color:var(--ink)}
:root[data-theme="dark"] .btn.sec{background:transparent;color:var(--ink);border-color:var(--line)}
:root[data-theme="dark"] .btn.sec:hover{background:transparent;border-color:var(--ink)}
.btn.sm{padding:9px 15px;font-size:13.5px}
.btnrow{display:flex;gap:var(--s3);flex-wrap:wrap;align-items:center}

/* ---------- 10 · header ---------- */
.hdr{
  position:sticky;top:0;z-index:50;background:color-mix(in srgb,var(--paper) 88%,transparent);
  backdrop-filter:saturate(140%) blur(10px);-webkit-backdrop-filter:saturate(140%) blur(10px);
  border-bottom:var(--hair) solid var(--line);
}
.hdr-in{
  max-width:var(--maxw);margin:0 auto;padding:var(--s4) var(--gut);
  display:flex;align-items:center;justify-content:space-between;gap:var(--s5);
}
.brand{display:flex;align-items:center;gap:var(--s3);text-decoration:none;flex:none}
.brand svg{display:block;color:var(--ink)}
.nav{display:none;gap:var(--s6);list-style:none;margin:0;padding:0}
@media (min-width:1060px){ .nav{display:flex} }
/* padding-block takes these to the 24px minimum hit area WCAG 2.2 SC 2.5.8 asks
   for. They are standalone links, not links inside a sentence, so the inline
   exception does not cover them. */
.nav a{
  font-size:13.5px;color:var(--muted);text-decoration:none;
  display:inline-block;padding-block:4px;
  transition:color var(--t-1) var(--ease-standard);
}
.nav a:hover{color:var(--ink)}
.nav a[aria-current]{color:var(--ink);box-shadow:inset 0 -2px 0 var(--accent-mark)}
.hdr-act{display:flex;align-items:center;gap:var(--s3);flex:none}
.hdr-act .btn{display:none}
@media (min-width:640px){ .hdr-act .btn{display:inline-flex} }

/* the menu button and its panel. The site is seven pages now, so the navigation
   cannot be desktop-only: under 1060px the links move into a disclosure that
   opens in flow underneath the header rather than over the page. Nothing INSIDE
   a page slides or fades, by brand rule. The transition veil in section 23
   moves between pages, and it is not a licence to make this panel slide. */
.mtoggle{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-family:var(--text);font-size:13px;font-weight:500;line-height:1.2;
  padding:9px 12px;border:var(--hair) solid var(--line);border-radius:var(--r);
  background:transparent;color:var(--ink);cursor:pointer;
  transition:border-color var(--t-1) var(--ease-standard);
}
.mtoggle:hover{border-color:var(--ink)}
@media (min-width:1060px){ .mtoggle{display:none} }
.mnav{border-top:var(--hair) solid var(--line-soft);background:var(--paper)}
@media (min-width:1060px){ .mnav{display:none!important} }
.mnav ul{list-style:none;margin:0;padding:var(--s2) 0 var(--s5);display:grid;gap:0}
.mnav a{
  display:block;padding-block:11px;font-size:15px;color:var(--ink-soft);
  text-decoration:none;border-bottom:var(--hair) solid var(--line-soft);
  transition:color var(--t-1) var(--ease-standard);
}
.mnav a:hover{color:var(--ink)}
.mnav a[aria-current]{color:var(--accent-mark)}
.mnav li.cta{padding-top:var(--s4)}
.mnav .btn{
  display:inline-flex;border-bottom:0;padding:13px 22px;
  font-size:14.5px;color:var(--btn-fg);
}

/* theme switch: two states, drawn, never the operating system's */
.tsw{
  display:inline-flex;border:var(--hair) solid var(--line);border-radius:var(--r);
  overflow:hidden;background:transparent;flex:none;
}
.tsw button{
  background:none;border:0;padding:8px 9px;cursor:pointer;color:var(--muted);
  display:grid;place-items:center;line-height:0;
  transition:background var(--t-1) var(--ease-standard),color var(--t-1) var(--ease-standard),
             box-shadow var(--t-1) var(--ease-standard);
}
.tsw button:hover{color:var(--ink)}
/* the selected side is marked the way everything else on this page is marked: a soft
   ground and a green rule sitting inside the edge. It is deliberately not a filled
   block, because the only filled block in this header is the call to action. */
.tsw button[aria-pressed="true"]{
  background:var(--paper-2);color:var(--accent-mark);
  box-shadow:inset 0 -2px 0 var(--accent-mark);
}
.tsw button[aria-pressed="true"]:hover{color:var(--accent-mark)}

/* ---------- 11 · hero, landing page ---------- */
/* the headroom above the first line is deliberately tighter than a normal
   section: the sticky header already supplies air, and the product card has
   to finish inside the first screen rather than be cut by its foot. */
.hero{
  background:var(--paper-2);
  border-top:3px solid var(--accent-surface);
  padding-block:var(--s6) var(--s8);
}
@media (min-width:900px){ .hero{padding-block:var(--s7) var(--s9)} }
/* dark: the hero is not a band of colour, it is a slightly lifted ground
   with a hairline. Nothing on the first screen is filled except the button,
   the card edge, and the method band below it. */
:root[data-theme="dark"] .hero{background:#0D1211;border-top:var(--hair) solid var(--line)}
.hero-grid{display:grid;gap:var(--s7);align-items:stretch}
@media (min-width:1000px){ .hero-grid{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:var(--s8)} }
.hero .eyebrow{
  font-family:var(--text);font-size:12px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--accent-mark);margin-bottom:var(--s5);
}
:root[data-theme="dark"] .hero .eyebrow{color:var(--muted)}
.hero .sub{font-size:17px;line-height:1.55;color:var(--ink-soft);max-width:50ch;margin:var(--s5) 0 var(--s6)}
.hero-note{font-size:13px;color:var(--muted);margin:var(--s4) 0 0;max-width:46ch}

/* ---------- 11b · page head, every page except the landing ---------- */
.phead{background:var(--paper-2);border-top:3px solid var(--accent-surface);padding-block:var(--s7)}
:root[data-theme="dark"] .phead{background:#0D1211;border-top:var(--hair) solid var(--line)}
.phead .eyebrow{
  font-family:var(--text);font-size:12px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--accent-mark);margin-bottom:var(--s4);
}
:root[data-theme="dark"] .phead .eyebrow{color:var(--muted)}
/* h1 on the left, the standfirst on the right and sitting on the same baseline
   band, so the head is two tight columns rather than one column with a hole
   beside it. */
.phead-grid{display:grid;gap:var(--s5)}
@media (min-width:1000px){
  .phead-grid{grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);gap:var(--s8);align-items:end}
}
.phead .lede{margin:0}

/* the product card. In daylight it is the one saturated surface on the first
   screen. In the dark it is a raised grey with a two pixel mint edge. */
.pcard{
  background:var(--accent-surface);color:var(--on-accent);border:0;border-radius:var(--r);
  padding:var(--s6);display:flex;flex-direction:column;
}
.pcard .label{color:var(--accent-quiet)}
.pcard .pcard-t{
  font-family:var(--display);font-weight:300;font-size:27px;line-height:1.2;
  letter-spacing:-.01em;margin:var(--s3) 0 var(--s4);color:var(--on-accent);max-width:none;
}
.pcard p{color:var(--on-accent-soft);font-size:14px;margin-bottom:var(--s5);max-width:46ch}
.pcard ul.clean li{color:var(--on-accent-soft);font-size:13.5px}
.pcard ul.clean li::before{background:var(--accent-quiet)}
.pcard ul.clean li b{color:var(--on-accent)}
.pcard .pfoot{display:flex;align-items:center;gap:var(--s3);margin-top:auto;padding-top:var(--s5)}
.pcard .pfoot .label{color:var(--accent-quiet)}
.pcard .plink{
  margin-top:var(--s5);font-size:13.5px;font-weight:500;color:var(--on-accent);
  text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;
}
:root[data-theme="dark"] .pcard{
  background:var(--paper-3);color:var(--ink);
  border:var(--hair) solid var(--line);box-shadow:inset 0 2px 0 var(--accent-mark);
}
:root[data-theme="dark"] .pcard .pcard-t{color:var(--ink)}
:root[data-theme="dark"] .pcard p,
:root[data-theme="dark"] .pcard ul.clean li{color:var(--ink-soft)}
:root[data-theme="dark"] .pcard ul.clean li b{color:var(--ink)}
:root[data-theme="dark"] .pcard .pfoot .label{color:var(--muted)}
:root[data-theme="dark"] .pcard .plink{color:var(--accent-mark)}

/* listening, not transcribing. The two never share a shape, because a doctor
   needs to know at a glance whether the room is being recorded. */
.wave{display:flex;align-items:flex-end;gap:3px;height:22px}
.wave i{width:3px;height:30%;background:var(--accent-quiet);animation:wv 900ms var(--ease-standard) infinite alternate}
.wave i:nth-child(2){animation-delay:90ms}.wave i:nth-child(3){animation-delay:180ms}
.wave i:nth-child(4){animation-delay:270ms}.wave i:nth-child(5){animation-delay:360ms}
.wave i:nth-child(6){animation-delay:450ms}.wave i:nth-child(7){animation-delay:120ms}
.wave i:nth-child(8){animation-delay:300ms}
@keyframes wv{to{height:100%}}
@media (prefers-reduced-motion:reduce){ .wave i{height:65%} }

/* ---------- 12 · the method band ---------- */
.mband{background:var(--accent-surface);color:var(--on-accent);padding-block:var(--s7)}
.mband .label{color:var(--accent-quiet);margin-bottom:var(--s5)}
:root[data-theme="dark"] .mband .label{color:var(--accent-mark)}
.mgrid{
  display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s5) var(--s4);
  padding-top:var(--s5);border-top:var(--hair) solid color-mix(in srgb,var(--on-accent) 28%,transparent);
}
@media (min-width:640px){ .mgrid{grid-template-columns:repeat(4,1fr)} }
@media (min-width:1000px){ .mgrid{grid-template-columns:repeat(7,1fr)} }
.mgrid .step{font-size:14.5px;color:var(--on-accent);font-weight:500}
.mgrid .k{
  display:block;font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;
  color:var(--accent-quiet);margin-bottom:5px;
}
.mgrid .d{display:block;font-size:12.5px;font-weight:400;color:var(--on-accent-soft);margin-top:4px;line-height:1.45}
.mband .mfoot{
  margin-top:var(--s5);padding-top:var(--s4);
  border-top:var(--hair) solid color-mix(in srgb,var(--on-accent) 20%,transparent);
}
.mband .mfoot a{
  font-size:13.5px;font-weight:500;color:var(--on-accent);text-decoration:underline;
  text-underline-offset:3px;text-decoration-thickness:1px;
}
:root[data-theme="dark"] .mband .mfoot a{color:var(--accent-mark)}

/* ---------- 13 · the method ledger ---------- */
.ledger{border-top:var(--hair) solid var(--ink);margin-top:var(--s5)}
/* padding-inline-start gives the 3px state bar its own space, so it marks the
   row rather than clipping the numeral sitting in the first column */
.ledger .row{
  display:grid;grid-template-columns:44px 1fr;gap:var(--s3) var(--s5);
  padding-block:var(--s4);padding-inline:var(--s4);
  border-bottom:var(--hair) solid var(--line-soft);position:relative;
}
@media (min-width:760px){ .ledger .row{grid-template-columns:44px 180px 1fr} }
.ledger .n{font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;color:var(--muted);padding-top:3px}
.ledger .w{font-weight:600;font-size:15.5px;color:var(--ink)}
.ledger .d{font-size:14px;color:var(--ink-soft);grid-column:2/-1}
@media (min-width:760px){ .ledger .d{grid-column:3} }
.ledger .row.fix{background:var(--paper-3)}
.ledger .row.fix .n{color:var(--accent-mark)}
.ledger .row.fix::before{content:"";position:absolute;inset-inline-start:0;top:0;bottom:0;width:3px;background:var(--accent-surface)}
:root[data-theme="dark"] .ledger .row.fix{background:var(--paper-3)}
:root[data-theme="dark"] .ledger .row.fix::before{background:var(--accent-mark)}

/* ---------- 14 · chips ---------- */
.chip{
  display:inline-flex;align-items:center;gap:6px;font-family:var(--text);font-size:11.5px;
  font-weight:500;letter-spacing:.02em;padding:4px 10px;border:var(--hair) solid var(--line);
  border-radius:var(--r);color:var(--muted);white-space:nowrap;
}
.chip .dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.chip.now{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 42%,transparent)}
.chip.dev{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 42%,transparent)}
.chip.later{color:var(--info);border-color:color-mix(in srgb,var(--info) 42%,transparent)}

/* ---------- 15 · the record artifact ---------- */
.rec{
  border:var(--hair) solid var(--line);border-radius:var(--r);background:var(--paper);
  overflow:hidden;box-shadow:var(--shadow-2);
}
.rec-bar{
  display:flex;align-items:center;gap:var(--s3);padding:10px var(--s4);
  border-bottom:var(--hair) solid var(--line);background:var(--paper-2);
}
.rec-bar .label{color:var(--muted);margin:0}
.rec-body{padding:var(--s5)}
.rec-h{
  font-family:var(--display);font-weight:300;font-size:22px;line-height:1.2;
  letter-spacing:-.01em;color:var(--ink);margin:0 0 var(--s4);
}
.rec-row{
  display:grid;grid-template-columns:112px 1fr;gap:var(--s2) var(--s4);
  padding:9px 0;border-top:var(--hair) solid var(--line-soft);font-size:13.5px;align-items:baseline;
}
.rec-row:first-of-type{border-top:0}
.rec-row dt{font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;text-transform:uppercase;color:var(--muted)}
.rec-row dd{margin:0;color:var(--ink-soft)}
.rec-row dd b{color:var(--ink);font-weight:600}
/* a field the doctor did not dictate. It stays in the record, in its own place,
   marked. That is what the product does, so that is what the drawing shows. */
.rec-row dd.unstated{color:var(--muted);display:flex;align-items:baseline;gap:var(--s2)}
.rec-row dd.unstated::before{
  content:"";width:11px;height:2px;background:var(--warn);flex:none;transform:translateY(-4px);
}
.rec-foot{
  margin-top:var(--s4);padding-top:var(--s3);
  border-top:var(--hair) solid var(--line-soft);font-size:12.5px;color:var(--muted);
}
.rec-sign{
  display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;justify-content:space-between;
  margin-top:var(--s5);padding-top:var(--s4);border-top:var(--hair) solid var(--line);
}

/* ---------- 16 · diagram ---------- */
.diagram{margin:0}
.diagram svg{display:block;width:100%;height:auto}
.diagram figcaption{
  font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--muted);margin-top:var(--s4);
}

/* ---------- 16b · photographs ----------
   Harbour's imagery rules written as code. Ratios are 3:2 and 1:1 and nothing
   else, every frame is cropped to the grid, takes this variation's radius and
   carries no border, and type never sits on top of a picture. Each <img>
   declares its real width and height so the page cannot shift while it loads.
   Provenance note for whoever maintains this: these frames are generated, not
   photographed, which is why not one of them is captioned or positioned as our
   clinic, our team or a customer. They are atmosphere. The moment a real shoot
   happens they get replaced and the captions can start doing work. */
.shot{margin:0}
.shot img{
  display:block;width:100%;height:auto;
  border-radius:var(--r);background:var(--paper-2);
}
.shot.r32 img{aspect-ratio:3/2;object-fit:cover}
.shot.r11 img{aspect-ratio:1/1;object-fit:cover}
.shot figcaption{
  font-family:var(--text);font-size:11px;font-weight:500;letter-spacing:.045em;
  text-transform:uppercase;color:var(--muted);margin-top:var(--s3);
}
/* The paired block. A photograph is never stacked underneath finished text,
   because that reads as decoration dropped in at the end of a column. It sits
   BESIDE the sentence it carries, vertically centred against it, so the picture
   and its argument arrive on screen together. This is the brand book's rule
   stated positively: type sits beside a photograph, in its own column. Under
   900px it stacks, photograph first, its text immediately after it. */
.figrow{display:grid;gap:var(--s6);align-items:center;margin-bottom:var(--s8)}
@media (min-width:900px){
  .figrow{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s8)}
}
.figrow .lede{margin-bottom:var(--s4)}
.figrow p:last-child{margin-bottom:0}
/* inside an audience card the photograph sits at the foot, so the three
   cards line up along the bottom whatever the copy does above them */
.aupanel .shot{margin-top:auto;padding-top:var(--s2)}
/* inside the hero product card the photograph fills the foot of the card,
   under the sentence about dictating and above the status line */
.pcard .shot{margin-top:auto;padding-top:var(--s5)}

/* ---------- 17 · audience ---------- */
.aud{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--s4)}
.aupanel{padding:var(--s5);border-radius:var(--r);background:var(--paper);border:var(--hair) solid var(--line);display:flex;flex-direction:column;gap:var(--s3)}
.aupanel h3{margin:0}
.aupanel p{font-size:13.5px;margin:0;color:var(--ink-soft)}
.aupanel.clinic{background:var(--paper-3);border-color:transparent;box-shadow:inset 0 3px 0 var(--accent-surface)}
:root[data-theme="dark"] .aupanel.clinic{background:var(--paper-3);box-shadow:inset 0 3px 0 var(--accent-mark)}
.aupanel.org{background:var(--slate);border-color:transparent;box-shadow:inset 0 3px 0 color-mix(in srgb,var(--on-slate) 45%,transparent);color:var(--on-slate)}
.aupanel.org h3{color:var(--on-slate)}
.aupanel.org p{color:color-mix(in srgb,var(--on-slate) 80%,transparent)}
.aupanel.org .chip{color:color-mix(in srgb,var(--on-slate) 78%,transparent);border-color:color-mix(in srgb,var(--on-slate) 34%,transparent)}

/* ---------- 18 · proof strip ---------- */
.proof{background:var(--paper-2);border-top:var(--hair) solid var(--line);padding-block:var(--s7)}
.proof-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--s6) var(--s5)}
.proof-grid b{font-family:var(--display);font-weight:400;font-size:20px;line-height:1.25;display:block;color:var(--ink);margin-bottom:6px;letter-spacing:-.01em}
.proof-grid span{font-size:13px;color:var(--muted);display:block;max-width:34ch}

/* ---------- 19 · faq ---------- */
.faq{display:grid;gap:0;border-top:var(--hair) solid var(--line)}
.faq details{border-bottom:var(--hair) solid var(--line-soft)}
.faq summary{
  list-style:none;cursor:pointer;padding:var(--s5) var(--s6) var(--s5) 0;position:relative;
  font-size:16px;font-weight:500;color:var(--ink);line-height:1.4;
  transition:color var(--t-1) var(--ease-standard);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"";position:absolute;inset-inline-end:6px;top:calc(var(--s5) + .55em);
  width:11px;height:var(--hair);background:var(--accent-mark);
}
.faq summary::before{
  content:"";position:absolute;inset-inline-end:11px;top:calc(var(--s5) + .05em);
  width:var(--hair);height:11px;background:var(--accent-mark);
  transition:opacity var(--t-2) var(--ease-standard);
}
.faq details[open] summary::before{opacity:0}
.faq summary:hover{color:var(--accent-mark)}
.faq .a{padding:0 var(--s7) var(--s5) 0}
.faq .a p{font-size:15px;max-width:76ch}
.faq h2{margin-bottom:var(--s4)}
.faqgroup{margin-bottom:var(--s8)}
.faqgroup:last-child{margin-bottom:0}
.faqgroup .h-label{display:block;margin-bottom:var(--s4)}

/* ---------- 20 · contact ---------- */
.contact{background:var(--paper-2);border-top:var(--hair) solid var(--line)}
:root[data-theme="dark"] .contact{background:var(--paper-2)}
.form{display:grid;gap:var(--s4)}
.frow{display:grid;gap:var(--s4)}
@media (min-width:620px){ .frow{grid-template-columns:1fr 1fr} }
.field{display:flex;flex-direction:column;gap:6px}
.field label{font-size:12.5px;font-weight:500;letter-spacing:.01em;color:var(--ink)}
.field .hint{font-size:11.5px;color:var(--muted)}
input[type=text],input[type=email],input[type=tel],textarea{
  font-family:var(--text);font-size:15px;color:var(--ink);background:var(--paper);
  border:var(--hair) solid var(--line);border-bottom-color:var(--ink-soft);
  border-radius:var(--r);padding:12px 13px;width:100%;
  transition:border-color var(--t-1) var(--ease-standard),box-shadow var(--t-1) var(--ease-standard);
}
textarea{resize:vertical;min-height:120px;line-height:1.55}
input::placeholder,textarea::placeholder{color:var(--muted);opacity:.75}
input:focus,textarea:focus{outline:none;border-color:var(--accent-mark);box-shadow:inset 0 -1px 0 var(--accent-mark)}
.hpot{position:absolute;inset-inline-start:-9999px;width:1px;height:1px;opacity:0}
.form.panel{padding:var(--s6);background:var(--paper)}
.wa-btn{padding:14px 24px;font-size:15px}
.wa-btn svg{flex:none}

/* the mid-page call to action, placed straight after the artifact,
   which is the one moment on the page where conviction peaks */
.midcta{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--s5);margin-top:var(--s8);padding:var(--s6);
  background:var(--paper-2);border-radius:var(--r);box-shadow:inset 4px 0 0 var(--accent-surface);
}
:root[data-theme="dark"] .midcta{background:var(--paper-2);box-shadow:inset 4px 0 0 var(--accent-mark)}
.midcta p{margin:0;max-width:52ch;color:var(--ink)}
.midcta .lead{
  font-family:var(--display);font-weight:300;font-size:clamp(19px,2vw,23px);
  line-height:1.3;letter-spacing:-.01em;margin-bottom:6px;
}

/* the band that closes a page. Every page ends on the same offer, so the reader
   never has to go looking for the way to start a conversation. */
.ctaband{background:var(--paper-2);border-top:var(--hair) solid var(--line);padding-block:var(--s7)}
.ctaband-in{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s5)}
.ctaband .lead{
  font-family:var(--display);font-weight:300;font-size:clamp(21px,2.4vw,30px);
  line-height:1.22;letter-spacing:-.01em;color:var(--ink);margin:0 0 var(--s2);max-width:26ch;
}
.ctaband p.small{margin:0;max-width:54ch}

/* ---------- 21 · footer ---------- */
.ftr{border-top:var(--hair) solid var(--line);padding-block:var(--s7) var(--s7);background:var(--paper)}
.ftr-top{display:grid;gap:var(--s6);grid-template-columns:repeat(auto-fit,minmax(200px,1fr));align-items:start}
.ftr h3{color:var(--muted);margin-bottom:var(--s4);font-size:11px;letter-spacing:.045em;font-weight:500}
.ftr ul{list-style:none;margin:0;padding:0;display:grid;gap:2px}
.ftr ul a{
  font-size:13.5px;color:var(--ink-soft);text-decoration:none;
  display:inline-block;padding-block:4px;
  transition:color var(--t-1) var(--ease-standard);
}
.ftr ul a:hover{color:var(--ink)}
.ftr-line{
  font-family:var(--display);font-weight:300;font-style:italic;font-size:17px;
  color:var(--ink);margin-top:var(--s4);
}
.ftr-ar{font-family:var(--ar-text);direction:rtl;font-size:14px;color:var(--muted);margin-top:6px}
.ftr-bot{
  display:flex;flex-wrap:wrap;gap:var(--s4);justify-content:space-between;align-items:center;
  margin-top:var(--s7);padding-top:var(--s5);border-top:var(--hair) solid var(--line-soft);
  font-size:12.5px;color:var(--muted);
}

/* ---------- 22 · Arabic fragments ---------- */
.ar{direction:rtl;text-align:end;font-family:var(--ar-text)}
.ar.dis{font-family:var(--ar-display)}

/* ---------- 23 · the transition veil ---------- */
/* One element, two jobs, and the only full-page motion on this site.

   On the landing page it is the way in: the wordmark writes itself on a green
   ground, the line the hero opens with rises under it, and the panel lifts off
   the page it was already sitting on top of.

   On every page it is also the panel that covers the page while an internal
   link is being followed, carrying the name of the page being loaded. It comes
   up from below, and on the next page it carries on upward and off, so one
   click reads as one movement rather than as two.

   HOW IT MOVES, because a first version of this was rejected for being fast and
   abrupt and the reasons are worth keeping.

   - **It travels on one axis, upward, always.** Arriving and leaving are the
     same gesture continued, not two gestures pointed at each other.
   - **Its leading edge is a curve**, not a straight line. A flat edge crossing
     the viewport reads as a wipe; an edge that swells and then flattens reads
     as something passing. That is what .veil-lip is, and it is the one place on
     this site where a radius is not `--r`. It is an edge in motion, not a
     surface corner, and the 4px rule is untouched by it.
   - **Nothing here runs under half a second.** The `--t-*` scale tops out at
     700ms and its two easings are shaped for 120ms hover moves. Neither can
     carry a full screen panel without snapping, so the veil has its own four
     durations and its own three curves, below.
   - **The name arrives before the panel has finished** and leaves before the
     panel has cleared. The overlaps are the effect. Squaring them up so each
     step waits for the last is exactly what made the first version feel cheap.

   Four things about how it is built, because all four are load bearing.

   1. **It covers the page, it never gates it.** The page is in the document and
      painted underneath the whole time. Nothing waits for the veil, no content
      is withheld from a reader or a crawler, and the veil never takes focus:
      it is aria-hidden with nothing focusable inside it.
   2. **CSS runs it, not JavaScript.** Every animation here has a `forwards` or
      `both` fill, so a script that fails cannot leave a green panel sitting on
      top of the site. With scripting off the intro still plays and every link
      is an ordinary link.
   3. **`data-nav` on the root element picks which animation runs**, and it is
      set before first paint by the inline script in the head, for the same
      reason the theme is: one unstyled frame of green is worse than no
      animation at all. `out` is leaving, `in` is arriving, `done` is spent.
   4. **Reduced motion removes it entirely**, and the click handler in
      /js/manara.js stands down with it, so links navigate the ordinary way.

   The veil is the exception to "nothing on this site slides or fades", added
   deliberately in August 2026. It is the exception and not the opening of a
   door: the page underneath it still does not animate on scroll. */

:root{
  /* the veil's own clock. Named for the job, because the numbers only make
     sense next to each other and the overlaps between them are the effect. */
  --veil-cover:520ms;    /* the panel arriving over the page being left */
  --veil-clear:880ms;    /* the panel leaving the page arrived at */
  --veil-say:820ms;      /* a name or a mark rising into place */
  --veil-unsay:600ms;    /* the same, going */
  --veil-lip:920ms;      /* the curved edge swelling, or flattening out */
  /* the veil's own curves. Quartic in gathers speed into place, quartic out
     arrives fast and settles slowly, cubic in-out passes through and away. */
  --veil-in:cubic-bezier(.895,.03,.685,.22);
  --veil-out:cubic-bezier(.165,.84,.44,1);
  --veil-through:cubic-bezier(.645,.045,.355,1);
  --veil-lip-h:7vh;      /* how far the curved edge stands off the panel */
  --veil-rise:var(--s7); /* how far anything on the panel travels as it appears */
}
/* the reference this was matched against halves both on a phone, and it is
   right to: the same 50px rise across a 780px viewport reads as a lurch */
@media (max-width:540px){ :root{ --veil-lip-h:4vh; --veil-rise:var(--s6) } }

.veil{
  position:fixed;inset:0;z-index:200;
  display:grid;place-items:center;
  background:var(--accent-surface);color:var(--on-accent);
  visibility:hidden;pointer-events:none;
  /* The panel and its edges are told about the transform up front. Without this
     the browser promotes them on the first frame of the animation instead, and
     that frame is dropped: measured at 33ms against a 16.7ms budget, which is
     exactly the hitch at the start of the movement that this was reported as. */
  will-change:transform;
}
/* both children sit in the same cell. The intro and the destination name are
   never on screen together, and stacking them stops the panel reflowing. */
.veil-intro,.veil-to{grid-area:1/1;justify-self:center;align-self:center;padding-inline:var(--gut)}

/* The curved leading and trailing edges. They are full width blocks parked just
   outside the panel and squashed flat, so the thing that animates is a scale on
   the compositor rather than a height that repaints. Lead is the edge that goes
   first, so it swells as the panel comes up; trail is the edge that goes last,
   so it flattens as the panel leaves. */
.veil-lip{position:absolute;inset-inline:0;height:var(--veil-lip-h);background:var(--accent-surface);will-change:transform}
.veil-lip-lead{bottom:100%;transform-origin:50% 100%;transform:scaleY(0);border-radius:50% 50% 0 0/100% 100% 0 0}
.veil-lip-trail{top:100%;transform-origin:50% 0;transform:scaleY(1);border-radius:0 0 50% 50%/0 0 100% 100%}
@keyframes veil-lip-swell{from{transform:scaleY(0)}to{transform:scaleY(1)}}
@keyframes veil-lip-flatten{from{transform:scaleY(1)}to{transform:scaleY(0)}}

@keyframes veil-cover{
  from{visibility:visible;transform:translate3d(0,100%,0)}
  to{visibility:visible;transform:translate3d(0,0,0)}
}
@keyframes veil-clear{
  from{visibility:visible;transform:translate3d(0,0,0)}
  to{visibility:hidden;transform:translate3d(0,-100%,0)}
}
@keyframes veil-say{
  from{opacity:0;transform:translate3d(0,var(--veil-rise),0)}
  to{opacity:1;transform:translate3d(0,0,0)}
}
@keyframes veil-unsay{from{opacity:1}to{opacity:0}}

/* --- leaving: the panel comes up and the name rises with it --- */
/* The panel body gathers speed on the way in, which is the right shape for
   something arriving but leaves the first 200ms of a 520ms move almost still.
   After a click that reads as nothing having happened, so the curved edge is
   given the opposite curve and leads: it swells out of the bottom of the screen
   immediately, the body follows, and the click is answered on the first frame. */
:root[data-nav="out"] .veil{animation:veil-cover var(--veil-cover) var(--veil-in) both}
:root[data-nav="out"] .veil-lip-lead{animation:veil-lip-swell var(--veil-cover) var(--veil-out) both}
:root[data-nav="out"] .veil-to{animation:veil-say var(--veil-cover) var(--veil-out) both}

/* --- arriving: the name goes first, then the panel carries on upward --- */
:root[data-nav="in"] .veil{animation:veil-clear var(--veil-clear) var(--veil-through) both}
:root[data-nav="in"] .veil-lip-trail{animation:veil-lip-flatten var(--veil-lip) var(--veil-through) both}
:root[data-nav="in"] .veil-to{animation:veil-unsay var(--veil-unsay) linear both}

/* the name of the page being loaded. It is carried as a custom property rather
   than as a text node because on the page being arrived at it has to be on
   screen at first paint, before there is a body to write into. Empty when
   nothing set it, which is every ordinary page load. */
.veil-to{
  margin:0;max-width:20ch;text-align:center;text-wrap:balance;
  /* the `optional` face from section 0, and Georgia rather than var(--display)
     behind it, so this one line can never change letterforms while it is on
     screen. Read the reasoning at the @font-face itself. */
  font-family:'Newsreader Veil',Georgia,'Times New Roman',serif;
  font-optical-sizing:auto;font-weight:200;
  font-size:clamp(30px,4.6vw,54px);line-height:1.06;letter-spacing:-.02em;
  color:var(--on-accent);opacity:0;
}
.veil-to::after{content:var(--nav-title,"")}

/* --- the intro, landing page only, marked with data-intro on the veil --- */
/* The timeline in one place, so it can be read without counting delays:
     0ms        the panel is already there, with the page painted under it
     260-1080   the wordmark and its line rise into place as a group
     260-1620   the strokes write themselves, one every 100ms, the ink moving
                from the mint to the paper white across the whole word
     1000-1820  the line the hero opens with rises under the mark
     1900-2200  mark and line fade
     1900-2780  the panel lifts, its trailing edge flattening as it goes
     2780       gone, and the page has been readable the whole time */
.veil-intro{display:grid;justify-items:center;gap:var(--s5);opacity:0}
/* once anything has set data-nav, this page has been left or returned to and
   the intro is over: what shows then is the destination name */
:root[data-nav] .veil-intro{display:none}

:root:not([data-nav]) .veil[data-intro]{animation:veil-clear var(--veil-clear) var(--veil-through) 1900ms both}
:root:not([data-nav]) .veil[data-intro] .veil-lip-trail{animation:veil-lip-flatten var(--veil-lip) var(--veil-through) 1900ms both}
:root:not([data-nav]) .veil[data-intro] .veil-intro{
  animation:veil-say var(--veil-say) var(--veil-out) 260ms both,
            veil-unsay 300ms linear 1900ms forwards;
}

.veil-mark{width:clamp(190px,36vw,330px);height:auto;color:var(--accent-quiet)}
/* pathLength="1" in the markup normalises every stroke to a length of 1, so one
   dash pattern draws all nine of them without measuring anything in script */
.veil-mark path{stroke-dasharray:1 1;stroke-dashoffset:1}
@keyframes veil-ink{from{color:var(--accent-quiet)}to{color:var(--on-accent)}}
@keyframes veil-draw{to{stroke-dashoffset:0}}
:root:not([data-nav]) .veil[data-intro] .veil-mark{animation:veil-ink 1500ms var(--veil-out) 260ms both}
:root:not([data-nav]) .veil[data-intro] .veil-mark path{animation:veil-draw 760ms var(--veil-out) 260ms both}
/* the six letters left to right, then the three bars across the A's last,
   in the order a hand would write them */
.veil-mark path:nth-child(2){animation-delay:360ms}
.veil-mark path:nth-child(3){animation-delay:460ms}
.veil-mark path:nth-child(4){animation-delay:560ms}
.veil-mark path:nth-child(5){animation-delay:660ms}
.veil-mark path:nth-child(6){animation-delay:760ms}
.veil-mark path:nth-child(7),
.veil-mark path:nth-child(8),
.veil-mark path:nth-child(9){animation-delay:860ms}

.veil-line{
  /* a shorter rise than the group it sits inside, or the two movements add up
     and the line appears to overshoot the mark above it */
  --veil-rise:var(--s5);
  margin:0;text-align:center;color:var(--accent-quiet);opacity:0;
  font-family:var(--text);font-size:12px;font-weight:500;
  letter-spacing:.045em;text-transform:uppercase;
}
:root:not([data-nav]) .veil[data-intro] .veil-line{animation:veil-say var(--veil-say) var(--veil-out) 1000ms both}

/* Reduced motion takes the whole thing away rather than shortening it. A panel
   that appears and vanishes inside a frame is worse than one that never
   appears, and /js/manara.js checks the same query before it intercepts a
   click, so links go on working the ordinary way. */
@media (prefers-reduced-motion:reduce){ .veil{display:none} }
