/* Post//Mundane brand v2 tokens - ops/brand/tokens/tokens.css is the source
     of truth. Only the subset this page uses is carried here. */
  :root {
    --pm-ink-900:#1E2F13; --pm-ink-800:#2C471D; --pm-ink-700:#375A24;
    --pm-ink-600:#456E2C; --pm-ink-500:#567F3B; --pm-ink-400:#7C9C64;
    --pm-ink-300:#A8BF94; --pm-ink-200:#CDDCC0;
    --pm-paper-050:#FFFAF0; --pm-paper-200:#F7ECDC;
    --pm-sans:"Helvetica Neue",Helvetica,"Archivo",Arial,sans-serif;
    --pm-mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,"DejaVu Sans Mono",monospace;
    --pm-ls-label:.22em;
    --pm-rule-hair:1px; --pm-rule-off:2px;
    --pm-radius:4px;
    --pm-shadow:none;            /* there is no elevation in this system */
    --pm-grain-opacity:.18;

    /* Plotter speed. Every stroke carries its own --t and --d; this scales
       all of them at once, the copy's --in with them, so the type still
       arrives as the pen finishes rather than after it. Lower is faster. */
    --plot:.38;

    /* One artboard unit in px. The plate cover-crops (xMaxYMid slice), so a
       unit is whichever of the two ratios is larger - exactly what the SVG
       resolves internally. With this, where the elevation begins is CSS
       arithmetic rather than something JS has to measure and keep fresh. */
    --u:max(calc(100vw / 2752), calc(100svh / 1536));
    --gutter:clamp(24px,5vw,72px);
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");

    /* page roles, mapped onto the tokens */
    --mono:var(--pm-mono);
    --sans:var(--pm-sans);
    --ground:var(--pm-paper-050);
    --ground-sub:var(--pm-paper-200);
    --line:var(--pm-ink-600);          /* THE LINE - rules, drawings, wordmark */
    --text:var(--pm-ink-800);          /* running text */
    --text-title:var(--pm-ink-900);
    --label:var(--pm-ink-500);         /* eyebrows, dimension text */
    --hair:var(--pm-ink-300);
  }
  * { box-sizing:border-box; }
  body { margin:0; background:var(--ground); }

  .hero {
    position:relative; width:100%; height:100svh; min-height:520px;
    overflow:hidden; background:var(--ground);
  }
  /* paper grain, generated in-page so nothing external is fetched */
  .hero::after {
    content:"";
    position:absolute; inset:0;
    pointer-events:none;
    background-image:var(--grain);
    background-size:200px 200px;
    mix-blend-mode:multiply;
    opacity:.18;
  }

  .hero__plate {
    position:absolute; inset:0; width:100%; height:100%;
    display:block; color:var(--line);
  }

  /* Every reveal is a white stroke inside a mask, hidden by its own length.
     One technique for all of them — no transforms, which do not apply
     reliably to shapes inside <mask>. */
  #mask path, #maskGrade {
    fill:none; stroke:#fff;
    stroke-linecap:butt; stroke-linejoin:round;
    stroke-dasharray:var(--len); stroke-dashoffset:var(--len);
  }
  #mask path { stroke-width:13; }
  #maskGrade { stroke-width:13; }

  .run #mask path, .run #maskGrade {
    transition-property:stroke-dashoffset;
    transition-duration:calc(var(--t,380ms) * var(--plot));
    transition-timing-function:linear;
    transition-delay:calc(var(--d,0ms) * var(--plot));
    stroke-dashoffset:0;
  }

  /* header sits above the plate and arrives only once the drawing settles */
  /* three tracks so the nav centres on the page, not on the space left over
     beside the lockup */
  .site-head {
    position:absolute; z-index:2; inset:0 0 auto 0;
    display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
    gap:24px;
    padding:clamp(20px,3.2vh,36px) clamp(24px,5vw,72px);
    font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
  }
  .site-head .lockup { justify-self:start; }
  .links { justify-self:center; }
  /* Wordmark A, "Ledger" - mono medium caps at .34em tracking with a midpoint
     separator, sitting on its 2px ruling-off line. The rule is part of the
     mark and never omitted; it spans the type only, never under the monogram.
     Monogram sits at 87.5% of the type's cap-height box, gap = half its width. */
  .lockup { display:flex; align-items:center; gap:.9em; }
  .lockup__mark { height:clamp(19px,1.6vw,25px); width:auto; flex:none; }
  /* Will's call: no ruling-off rule, and the sans rather than the mono.
     Note brand/02-identity.md says the rule "is part of the mark and never
     omitted" - this departs from that on purpose. The tracking stays; it is
     what still reads as a wordmark rather than a word. */
  .lockup__type {
    display:inline-block;
    font-family:var(--sans); font-weight:600;
    color:var(--pm-ink-900);
    font-size:clamp(13px,1.05vw,17px);
    letter-spacing:.30em; text-indent:.30em;
    line-height:1;
  }
  .links { display:flex; gap:clamp(16px,2.3vw,42px); }
  /* no opacity here: `.links a` (0,1,1) would outrank `.rise` (0,1,0) and
     leave the links visible before the drawing finishes */
  /* the nav takes the hero's face: same sans, same weight, same tight
     tracking. The mono label tracking came off with it - .22em is set for
     uppercase mono and reads as a mismatch inside a sans. */
  .links a {
    color:var(--label); text-decoration:none;
    font-family:var(--sans);
    font-weight:500; font-size:clamp(13px,.95vw,15px);
    letter-spacing:-.01em; text-transform:none;
    padding-bottom:3px; border-bottom:1px solid transparent;
    transition:opacity .2s ease, border-color .2s ease;
  }
  .links a:hover, .links a:focus-visible { border-bottom-color:currentColor; }
  .links a:focus-visible { outline:2px solid var(--line); outline-offset:4px; }

  /* AMBIENT VIDEO
     A muted loop with a glow that takes its colour from the frame on screen.
     The colour is sampled by drawing the video to a 1x1 canvas and reading
     that one pixel - the average of the frame, effectively - then used as the
     colour of a large box-shadow. Technique after the Framer AmbientVideo
     component; written natively because that module is React and loads from
     framerusercontent, which the artifact CSP blocks. */
  .ambient {
    margin:0;                     /* figure default, reset here not inline:
                                     an inline margin outranks the media query
                                     that pulls the frame off the elevation */
    position:relative;
    aspect-ratio:16 / 9;
    border-radius:12px;
    isolation:isolate;
  }
  .ambient video {
    position:relative; z-index:1;
    width:100%; height:100%;
    display:block; object-fit:cover;
    border-radius:inherit;
    box-shadow:0 0 28px 6px var(--glow, rgba(100,100,100,.3));
    transition:box-shadow .35s linear;
    background:var(--pm-ink-200);
  }
  .ambient__ph {
    position:relative; z-index:1;
    width:100%; height:100%;
    display:block; border-radius:inherit;
    box-shadow:0 0 28px 6px var(--glow, rgba(100,100,100,.3));
    transition:box-shadow .35s linear;
  }
  @media (prefers-reduced-motion:reduce) {
    .ambient__ph { transition:none; }
  }
  .ambient video[hidden], .ambient__ph[hidden] { display:none; }
  /* TEMPORARY - a third-party YouTube embed standing in for footage.
     Embedded, never re-hosted: the film is Vogue Architects' and an <iframe>
     is the route that credits and links back to them.

     It cannot drive the glow. A cross-origin frame gives no pixel access, so
     the 1x1 canvas read is impossible and the glow is a fixed colour here.
     The scale-and-crop hides YouTube's title and branding overlays, which sit
     outside the visible box; pointer-events:none keeps the hover chrome from
     ever appearing. Replace the whole block when the real file lands. */
  .ambient__yt {
    position:absolute; inset:0; z-index:2;   /* over the canvas fallback */
    overflow:hidden; border-radius:inherit;
    box-shadow:0 0 28px 6px rgba(86,101,58,.42);
    background:var(--pm-ink-800);
  }
  .ambient__yt iframe {
    position:absolute; top:50%; left:50%;
    width:158%; height:158%;   /* crops YouTube title and branding out */
    transform:translate(-50%,-50%);
    border:0; pointer-events:none;
  }
  .ambient__cap {
    display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
    margin-top:.9em; padding-top:.7em;
    border-top:1px solid var(--hair);
    font-family:var(--mono); font-size:9.5px; color:var(--label);
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  /* a glow is motion too: hold it still and do not autoplay */
  @media (prefers-reduced-motion:reduce) {
    .ambient video { transition:none; box-shadow:none; }
  }

  /* Wide: the copy column becomes two tracks. The headline spans both, the
     copy keeps the left, and the video takes the paper that was empty. */
  @media (min-width:1200px) {
    .intro {
      display:grid;
      /* auto, not 1fr: the first track takes the width of the copy itself,
         so the second one begins where the text and buttons actually end
         rather than at an arbitrary fraction of the column */
      grid-template-columns:auto minmax(0,1fr);
      column-gap:0;
      align-items:start;
    }
    .intro__title { grid-column:1 / -1; padding-right:48px; }
    .intro__copy { grid-column:1; }
    /* centred in the paper between the copy and the elevation, so the air
       either side of it is equal by construction rather than by a number */
    .ambient {
      grid-column:2; align-self:center; justify-self:center;
      /* smaller than the paper it sits in: 80px of air a side at minimum, so
         the glow never reaches the elevation */
      width:min(calc(100% - 160px), 460px);
    }
  }
  @media (max-width:1199px) {
    .ambient { margin-top:clamp(28px,4vh,44px); }
  }
  /* 901-1199 is the awkward band: too narrow for two columns, but the hero is
     still fixed height with the drawing at full strength, so a stacked frame
     overflows it and gets cropped. Below 900 the hero flows and there is room.
     The frame sits this band out rather than being cropped or shrunk to a
     stamp. */
  @media (min-width:901px) and (max-width:1199px) {
    .ambient { display:none; }
  }

  .rise { opacity:0; transform:translateY(10px); }
  .run .rise {
    opacity:1; transform:none;
    transition:opacity .7s ease calc(var(--in,0ms) * var(--plot)),
               transform .7s cubic-bezier(.2,.7,.3,1) calc(var(--in,0ms) * var(--plot));
  }

  /* The nav used to be hidden here, with the footer's sheet index carrying
     the sections on small screens. That index is Elsewhere links now, so the
     nav has to come back or AI Studio and Approach are unreachable below
     760px. It takes its own row under the lockup. */
  @media (max-width:760px) {
    .site-head {
      grid-template-columns:1fr; justify-items:center; gap:10px;
      padding-top:clamp(16px,2.4vh,26px);
    }
    .site-head .lockup { justify-self:center; }
    .links { flex-wrap:wrap; justify-content:center; gap:6px clamp(12px,4vw,20px); }
    .links a { font-size:12px; }
  }

  /* hero copy in the open paper to the left of the elevation */
  .intro {
    position:absolute; z-index:2;
    left:clamp(24px,5vw,72px);
    top:clamp(120px,17vh,200px);
    /* The annotation ticks begin 517 units in from the artboard's right edge,
       and the artboard is anchored right - so this is the open paper, exactly,
       at every viewport. No measuring, nothing to go stale. */
    width:calc(100vw - 517 * var(--u) - var(--gutter));
    color:var(--line);
  }
  .intro__title {
    margin:0 0 .7em;
    font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
    color:var(--text-title);
    /* a pure-vw preferred value sits on its floor right through the tablet
       range; the rem term keeps it climbing from the small end up */
    font-weight:500;
    /* The column is measured against the drawing, so this reaches two lines
       on the width rather than on the type size. */
    font-size:clamp(1.5rem, .95rem + 2.3vw, 2.45rem);
    line-height:1.12; letter-spacing:-.02em;
    /* pretty, not balance: balance evens the two lines, which left the first
       one short and the paper beside it empty. pretty fills the measure and
       only protects the last line from an orphan - so line one runs the width
       of the column and line two takes the remainder. */
    text-wrap:pretty;
  }
  .intro__sub {
    color:var(--text);
    margin:0 0 2em;
    /* the hero's face, a step down from it - the sub-line reads as the
       headline continuing rather than as a caption under it */
    font-family:var(--sans);
    font-weight:400;
    font-size:clamp(14px,1.05vw,17px); line-height:1.55;
    letter-spacing:-.005em;
    /* a sans sets wider per character than the mono did, so the measure comes
       in to hold the line length steady */
    max-width:48ch; opacity:.88;
  }
  /* reads as a link, but stays a button - it opens a dialog rather than
     navigating, and that is what a screen reader should announce */
  .lnk {
    display:inline-flex; align-items:center; gap:.6em;
    background:none; border:0; padding:0; cursor:pointer;
    color:var(--line); font-family:var(--sans);
    font-weight:500; font-size:clamp(12px,.85vw,14px);
    letter-spacing:-.005em; line-height:1;
  }
  .lnk span {
    text-decoration:underline;
    text-decoration-style:dotted;
    text-decoration-thickness:1px;
    text-underline-offset:4px;
  }
  .lnk:hover span, .lnk:focus-visible span { text-decoration-style:solid; }
  .lnk:focus-visible { outline:2px solid var(--line); outline-offset:4px; }
  .lnk__arrow { flex:none; height:1.05em; width:auto; opacity:.85; }

  /* the letter now lives inside its own sheet */
  .letter {
    color:var(--text);
    font-family:var(--sans);
    font-size:clamp(15px,1.05vw,17px);
    line-height:1.62;
    letter-spacing:-.005em;
    /* 82ch was a mono measure. A sans sets wider, and this is the longest
       read on the site - it needs a shorter line, not the same count. */
    max-width:62ch;
  }
  .letter p { margin:0 0 1.05em; }
  .letter p:last-child { margin-bottom:0; }
  .letter a {
    color:inherit; text-decoration:none;
    border-bottom:1px solid currentColor;
    padding-bottom:1px;
  }
  .letter a:hover, .letter a:focus-visible { background:rgba(69,110,44,.10); }

  /* signature closes the letter — scales with the type so it never overpowers it */
  /* signature closes the letter — scales with the type so it never overpowers it */
  .letter .sig { line-height:0; }
  .sig__mark { display:block; width:clamp(74px, 10em, 128px); height:auto; }


  /* sit in the band below grade; JS pins the exact offset to the line */
  /* the buttons now sit in the copy, under Open letter, rather than in the
     band below grade - so they are laid out, not pinned */
  .actions {
    margin-top:clamp(26px,3.6vh,44px);
    display:flex; flex-wrap:wrap; gap:12px;
    font-family:var(--mono);
  }
  /* A filled field, a full radius and type at a readable size - the weight
     comes from the field, not from elevation, so no shadow or gradient is
     needed to stop it reading flat. */
  .btn {
    display:inline-flex; align-items:center; justify-content:center;
    text-decoration:none; cursor:pointer;
    background-color:var(--line); color:var(--ground);
    border:1px solid var(--line); border-radius:999px;
    padding:.95em 1.7em;
    font-family:var(--sans); font-weight:500;
    font-size:clamp(13px,.95vw,15px);
    letter-spacing:-.005em; text-transform:none; line-height:1;
    transition:background-color .18s ease, border-color .18s ease,
               color .18s ease, transform .12s ease;
  }
  .btn:hover, .btn:focus-visible {
    background-color:var(--pm-ink-800); border-color:var(--pm-ink-800);
    color:var(--ground);
  }
  .btn:active { transform:translateY(1px); }

  /* the second action reads as the quieter one: same field, drawn not filled */
  .btn--ghost {
    background-color:transparent; color:var(--line);
  }
  .btn--ghost:hover, .btn--ghost:focus-visible {
    background-color:var(--pm-ink-200); border-color:var(--pm-ink-200);
    color:var(--pm-ink-900);
  }

  /* One control, drawn as two shapes. The wrapper carries no .btn: given the
     button skin it paints its own square field behind both shapes and every
     override has to fight the base rule back off. It is a group. */
  .cta {
    display:inline-flex; align-items:center; gap:5px;
    text-decoration:none; cursor:pointer;
    font-family:var(--sans); font-weight:500;
    font-size:clamp(13px,.95vw,15px);
    letter-spacing:-.005em; line-height:1;
    transition:transform .12s ease;
  }
  .cta:active { transform:translateY(1px); }
  .btn__label, .btn__go {
    display:inline-flex; align-items:center; justify-content:center;
    background-color:var(--line); color:var(--ground);
    transition:background-color .18s ease;
  }
  .btn__label { border-radius:999px; padding:.95em 1.7em; }
  .btn__go { border-radius:50%; width:3.05em; height:3.05em; flex:none; }
  .btn__go svg { width:1.05em; height:1.05em; display:block; }
  .cta:hover .btn__label, .cta:hover .btn__go,
  .cta:focus-visible .btn__label, .cta:focus-visible .btn__go {
    background-color:var(--pm-ink-800);
  }
  .cta:focus-visible { outline:2px solid var(--line); outline-offset:4px; border-radius:999px; }
  /* the old outlined button's hover lived here and, being later in the sheet,
     was quietly winning over the new .btn:hover and .btn--ghost:hover above -
     it is what painted a square field behind the split control */
  .btn:focus-visible { outline:2px solid var(--line); outline-offset:3px; }

  /* This block sits after .actions on purpose: placed before it, the base
     position:absolute wins on source order and the override does nothing. */
  /* A headline at this size cannot live in a fixed-height hero on a phone:
     it was being clipped by overflow:hidden at 360x640 and running through
     the CTA row everywhere narrow. Below 900px the drawing is a 22% backdrop
     anyway, so the hero flows with its content instead of cropping it. */
  @media (max-width:900px) {
    .hero {
      height:auto; min-height:100svh;
      padding-bottom:clamp(32px,6vh,64px);
    }
    .hero__plate { opacity:.22; }
    .intro {
      position:static; width:auto;
      margin:clamp(88px,14vh,140px) clamp(24px,5vw,72px) 0;
    }
  }


  /* ---- contact sheet ---------------------------------------------------- */
  /* A plain fixed overlay rather than <dialog>.showModal(): sandboxed
     iframes (the published artifact among them) block modal dialogs, and the
     fallback renders in normal flow — uncentred, no backdrop. */
  .overlay {
    position:fixed; inset:0; z-index:100;
    display:flex; align-items:center; justify-content:center;
    background:rgba(58,50,36,.42);
    opacity:0; transition:opacity .22s ease;
  }
  .overlay[hidden] { display:none; }
  .overlay.is-open { opacity:1; }

  .sheet {
    width:75vw; height:75vh;
    padding:0; border:1px solid var(--line);
    background:var(--ground); color:var(--line);
    position:relative; overflow:hidden;
    transform:translateY(8px) scale(.985);
    transition:transform .24s cubic-bezier(.2,.7,.3,1);
  }
  .overlay.is-open .sheet { transform:none; }
  .sheet::after {
    content:""; position:absolute; inset:0; pointer-events:none;
    background-image:var(--grain); background-size:200px 200px;
    mix-blend-mode:multiply; opacity:.18;
  }
  .sheet__inner {
    position:relative; z-index:1;
    height:100%; overflow:auto;
    padding:clamp(28px,4.5vw,64px);
    display:flex; flex-direction:column;
  }
  .sheet__close {
    position:absolute; z-index:2; top:14px; right:18px;
    background:none; border:0; cursor:pointer;
    color:var(--line); font-size:26px; line-height:1; padding:6px 10px;
  }
  .sheet__close:hover { opacity:.65; }
  .sheet__close:focus-visible { outline:2px solid var(--line); outline-offset:2px; }

  .sheet__eyebrow {
    margin:0 0 .9em; font-family:var(--mono); color:var(--label);
    font-size:11px; letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  .sheet__title {
    margin:0 0 .35em;
    font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
    color:var(--text-title);
    font-weight:500; font-size:clamp(1.5rem,2.9vw,2.3rem);
    letter-spacing:-.02em; line-height:1.08;
  }
  .sheet__lede {
    margin:0 0 clamp(24px,3.5vh,44px);
    font-family:var(--sans); font-size:clamp(14px,1vw,16px);
    line-height:1.6; letter-spacing:-.005em;
    max-width:44ch; color:var(--text);
  }

  .form { display:grid; grid-template-columns:1fr 1fr; gap:clamp(16px,2.4vw,30px); }
  .field--wide, .form__foot { grid-column:1 / -1; }
  .field { display:flex; flex-direction:column; gap:.55em; }
  .field label {
    font-family:var(--mono); font-size:10.5px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase; color:var(--label);
  }
  .field input, .field textarea {
    font-family:var(--mono); font-size:clamp(11px,.85vw,13px);
    color:var(--line); background:transparent;
    border:0; border-bottom:1px solid var(--hair);
    padding:.55em 0; resize:vertical;
  }
  .field input:focus, .field textarea:focus {
    outline:none; border-bottom-color:var(--line);
  }
  .form__foot { display:flex; align-items:center; gap:18px; flex-wrap:wrap; margin-top:.6em; }
  .form__note { margin:0; font-family:var(--mono); font-size:11px; letter-spacing:.06em; }
  /* honeypot - moved out of view rather than display:none, which the better
     bots know to skip. Out of the tab order and off the a11y tree. */
  .hp { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

  /* margin-top:auto against the flex column - the sheet gets a bottom edge
     instead of ending halfway down, and the space reads as margin */
  .sheet__foot {
    margin-top:auto; padding-top:clamp(16px,2.4vh,24px);
    border-top:1px solid var(--hair);
    display:flex; align-items:baseline; gap:10px clamp(14px,1.8vw,22px);
    flex-wrap:wrap;
    font-family:var(--mono); font-size:10px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  .sheet__foot span { color:var(--label); }
  .sheet__foot a {
    color:var(--text); text-decoration:none;
    border-bottom:1px solid var(--hair); padding-bottom:2px;
    letter-spacing:.06em; text-transform:none;
    font-size:clamp(10.5px,.8vw,12.5px);
  }
  .sheet__foot a:hover, .sheet__foot a:focus-visible { border-bottom-color:currentColor; }

  @media (max-width:760px) {
    .sheet { width:92vw; height:88vh; }
    .form { grid-template-columns:1fr; }
  }

  /* side panel: slides in from the right, Notion-style peek */
  .overlay--right { justify-content:flex-end; }
  .panel {
    width:min(620px, 46vw); height:100%;
    background:var(--ground); color:var(--line);
    border-left:1px solid var(--line);
    position:relative; overflow:hidden;
    transform:translateX(100%);
    transition:transform .34s cubic-bezier(.22,.75,.3,1);
  }
  .overlay--right.is-open .panel { transform:none; }
  .panel::after {
    content:""; position:absolute; inset:0; pointer-events:none;
    background-image:var(--grain); background-size:200px 200px;
    mix-blend-mode:multiply; opacity:.18;
  }
  /* flex column so the foot sits on the bottom edge: the panel reads as a
     sheet with a margin, not a column that ran out of content halfway */
  .panel__inner {
    position:relative; z-index:1;
    height:100%; overflow:auto;
    padding:clamp(28px,3.6vw,56px);
    display:flex; flex-direction:column;
  }
  .panel__foot {
    flex:none;
    display:flex; align-items:center; justify-content:space-between;
    gap:16px; flex-wrap:wrap;
    margin-top:clamp(30px,5vh,56px);
    padding-top:clamp(14px,2vh,20px);
    border-top:1px solid var(--hair);
    font-family:var(--mono); font-size:9.5px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  .panel__sheet { color:var(--label); }
  .btn--sm { padding:.8em 1.4em; font-size:clamp(12px,.85vw,13.5px); }
  .panel__body {
    flex:1 1 auto;
    color:var(--text);
    font-family:var(--sans);
    font-size:clamp(14px,1vw,16px); line-height:1.6;
    letter-spacing:-.005em;
  }
  .panel__body p { margin:0 0 1.4em; max-width:46ch; }
  .panel__body ul { list-style:none; margin:0; padding:0; }
  /* :not(.compat__item) - the logo strip is also a ul, and was picking up
     these rules as stray rules above and below each mark */
  .panel__body li:not(.compat__item) {
    padding:1.05em 0;
    border-top:1px solid var(--hair);
  }
  .panel__body li:not(.compat__item):last-child { border-bottom:1px solid var(--hair); }
  /* pinned: the body around it is sans now, and .22em uppercase tracking is
     a mono setting - inherited into a sans it reads as a mistake */
  .panel__body .li__k {
    display:block; font-family:var(--mono);
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
    font-size:10px; color:var(--label); margin-bottom:.5em;
  }

  /* which tools these are written for */
  .compat {
    display:flex; align-items:center; flex-wrap:wrap; gap:10px 14px;
    margin:0 0 1.9em;
    padding-bottom:1.4em;
    border-bottom:1px solid var(--hair);
  }
  .compat__list { display:flex; flex-wrap:wrap; align-items:center; gap:22px; list-style:none; margin:0; padding:0; }
  .compat__item {
    display:inline-flex; align-items:center;
    font-size:11px; letter-spacing:.04em; line-height:1;
  }
  .compat__item svg { display:block; height:19px; width:auto; }

  /* prompt cards */
  .pr { border-top:1px solid var(--hair); padding:1.3em 0; }
  .pr:last-child { border-bottom:1px solid var(--hair); }
  .pr__head { display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .pr__head .li__k { margin-bottom:0; }
  .pr__use {
    margin:.5em 0 .9em; opacity:.75;
    font-family:var(--sans); letter-spacing:-.005em;
  }
  .pr__text {
    margin:0; padding:1em 1.1em;
    background:rgba(69,110,44,.055);
    border:1px solid var(--hair);
    font-family:var(--mono); font-size:.92em; line-height:1.62;
    white-space:pre-wrap; word-break:break-word;
    max-height:16em; overflow:auto;
  }
  .pr__copy {
    flex:none; cursor:pointer;
    background:none; color:var(--line);
    border:1px solid var(--line);
    padding:.5em 1em;
    font-family:var(--mono); font-size:9.5px;
    letter-spacing:.16em; text-transform:uppercase; line-height:1;
    transition:background .18s ease, color .18s ease;
  }
  .pr__copy:hover { background:var(--line); color:var(--ground); }
  .pr__copy:focus-visible { outline:2px solid var(--line); outline-offset:2px; }
  .pr__copy.is-done { background:var(--line); color:var(--ground); }

  @media (max-width:760px) { .panel { width:92vw; } }

  /* Below grade is where a drawing carries its title block. The band was
     empty ground; it now holds the sheet's identification. */
  /* The title block sits in the band below grade, inside the hero, so the
     whole sheet reads on one screen. No background and no grain of its own -
     the ground it sits on is the drawing's, and the hero already lays grain
     over everything. */
  .after {
    position:absolute; left:0; right:0; bottom:0; z-index:2;
    padding:0 var(--gutter) clamp(14px,2.2vh,26px);
    font-family:var(--mono);
  }
  .colophon__in { width:100%; }
  .tblock {
    display:flex; align-items:flex-end; justify-content:space-between;
    gap:clamp(18px,3vw,56px); flex-wrap:wrap;
    border-top:1px solid var(--line);
    padding-top:clamp(11px,1.7vh,18px);
  }
  .tblock__grid { grid-template-columns:repeat(4,auto); }
  .tblock__grid { display:grid; grid-template-columns:repeat(4,1fr); margin:0; }
  .tblock__grid > div {
    padding:0 clamp(10px,1.2vw,20px);
    border-left:1px solid var(--hair);
  }
  .tblock__grid > div:first-child { border-left:0; padding-left:0; }
  .tblock__grid dt {
    color:var(--label); font-size:9.5px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
    margin-bottom:.85em;
  }
  .tblock__grid dd {
    margin:0; color:var(--text); font-size:clamp(10.5px,.8vw,12.5px);
    line-height:1.45; word-break:break-word;
  }
  .tblock__grid a {
    color:inherit; text-decoration:none;
    border-bottom:1px solid var(--hair); padding-bottom:1px;
  }
  .tblock__grid a:hover, .tblock__grid a:focus-visible { border-bottom-color:currentColor; }

  /* A drawing sheet carries an index. Below 760px .links is display:none and
     this is the only way left to reach AI Studio and Approach at all. */
  .tblock__index {
    display:flex; flex-wrap:wrap; align-items:baseline;
    gap:8px clamp(16px,2.2vw,32px);
    margin:clamp(12px,1.8vh,20px) 0 0;
    padding-top:clamp(10px,1.5vh,15px);
    border-top:1px solid var(--hair);
  }
  .tblock__index-k {
    color:var(--label); font-size:9.5px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  .tblock__index a {
    color:var(--text); text-decoration:none; cursor:pointer;
    font-family:var(--sans);
    font-weight:500; font-size:clamp(13px,.95vw,15px);
    letter-spacing:-.005em;
    border-bottom:1px solid transparent; padding-bottom:2px;
  }
  .tblock__index a:hover, .tblock__index a:focus-visible { border-bottom-color:currentColor; }
  .tblock__index a:focus-visible { outline:2px solid var(--line); outline-offset:3px; }
  .tblock__legal {
    display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
    margin:clamp(10px,1.5vh,16px) 0 0; padding-top:10px;
    border-top:1px solid var(--hair);
    color:var(--label); font-size:9.5px;
    letter-spacing:.16em; text-transform:uppercase;
  }
  @media (max-width:900px) {
    .after {
      position:static;
      padding:clamp(34px,5vh,56px) var(--gutter) clamp(18px,3vh,30px);
    }
  }
  @media (max-width:760px) {
    .tblock { flex-direction:column; align-items:flex-start; }
    .tblock__grid { grid-template-columns:repeat(2,1fr); row-gap:24px; }
    .tblock__grid > div:nth-child(3) { border-left:0; padding-left:0; }
  }

  /* ---- section pages ---------------------------------------------------
     Projects, AI Studio and Approach are pages now rather than slide-in
     panels. They reuse the panel's own body styles, so the content reads
     identically to where it came from; only the container changes. */
  body { background:var(--ground); }
  .site-head--page {
    position:static;
    border-bottom:1px solid var(--hair);
  }
  .site-head--page .links a[aria-current="page"] {
    color:var(--text-title);
    border-bottom-color:currentColor;
  }
  /* Hangs off the same left margin as the header and the title block, the
     way everything else on the sheet does - a centred column leaves the
     lockup stranded on its own. */
  .page {
    padding:clamp(38px,7vh,84px) var(--gutter) clamp(40px,7vh,90px);
    display:flex; flex-direction:column;
    min-height:calc(100svh - 230px);
  }
  .page__head, .page__body, .page__foot { max-width:70ch; }
  /* the panel measure was set for a 620px drawer; a page is not that */
  .page__body p { max-width:64ch; }
  .page__body .pr__text { max-height:none; }
  .page__head { margin-bottom:clamp(22px,3.4vh,38px); }
  .page__title {
    margin:0;
    font-family:var(--sans); font-weight:500;
    color:var(--text-title);
    font-size:clamp(1.9rem, 1.1rem + 2.4vw, 3rem);
    line-height:1.1; letter-spacing:-.02em;
  }
  .page__body { flex:1 1 auto; }
  .page__foot {
    flex:none;
    display:flex; align-items:center; justify-content:space-between;
    gap:16px; flex-wrap:wrap;
    margin-top:clamp(30px,5vh,56px);
    padding-top:clamp(14px,2vh,20px);
    border-top:1px solid var(--line);
    font-family:var(--mono); font-size:9.5px;
    letter-spacing:var(--pm-ls-label); text-transform:uppercase;
  }
  /* the page footer is a document footer, not the hero's below-grade band */
  .site-head--page ~ .after {
    position:static;
    padding:0 var(--gutter) clamp(18px,3vh,30px);
  }

  /* ---- the traverse -----------------------------------------------------
     Five stages as connected cards. The connector is orthogonal because a
     routing line turns at right angles, and it is MEASURED from the cards
     rather than drawn on a fixed grid - the cards are laid out by CSS, so
     the line has to follow them, not the other way round.

     The line runs straight through each card; the card's own ground hides
     that segment. That keeps it one continuous path, which is what makes a
     single stroke-dashoffset reveal possible. */
  .traverse {
    position:relative;
    padding:clamp(56px,9vh,120px) var(--gutter) clamp(60px,10vh,140px);
    background:var(--ground);
  }
  .traverse::after {
    content:""; position:absolute; inset:0; pointer-events:none;
    background-image:var(--grain); background-size:200px 200px;
    mix-blend-mode:multiply; opacity:var(--pm-grain-opacity);
  }
  .traverse__head { position:relative; z-index:1; max-width:56ch; margin-bottom:clamp(34px,6vh,72px); }
  .traverse__title {
    margin:0 0 .5em; color:var(--text-title);
    font-family:var(--sans); font-weight:500;
    font-size:clamp(1.6rem,1rem + 1.9vw,2.5rem);
    line-height:1.12; letter-spacing:-.02em; text-wrap:pretty;
  }
  .traverse__lede {
    margin:0; color:var(--text); font-family:var(--sans);
    font-size:clamp(14px,1vw,16px); line-height:1.6; letter-spacing:-.005em;
    max-width:52ch;
  }

  .traverse__plot { position:relative; z-index:1; }
  .tv__svg { position:absolute; inset:0; width:100%; height:100%; z-index:0; overflow:visible; }
  .tv__ghost, .tv__line { fill:none; stroke-linecap:butt; stroke-linejoin:miter; }
  .tv__ghost { stroke:var(--hair); stroke-width:1.5; }
  .tv__line  { stroke:var(--line); stroke-width:2;
               stroke-dasharray:var(--len,1); stroke-dashoffset:var(--off,1); }

  .tv__cards {
    position:relative; z-index:1;
    list-style:none; margin:0; padding:0;
    display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
    gap:clamp(64px,11vh,140px) clamp(40px,6vw,120px);
  }
  /* Alternating sides, one card per row. The row has to be explicit: left
     to itself the grid drops cards 1 and 2 into the SAME row, side by side,
     and then there is no vertical run between them for the line to make. */
  .tv__card:nth-child(1) { grid-column:2; grid-row:1; }
  .tv__card:nth-child(2) { grid-column:1; grid-row:2; }
  .tv__card:nth-child(3) { grid-column:2; grid-row:3; }
  .tv__card:nth-child(4) { grid-column:1; grid-row:4; }
  .tv__card:nth-child(5) { grid-column:2; grid-row:5; }

  .tv__card {
    background:var(--ground);
    border:1px solid var(--hair);
    padding:clamp(18px,2.2vw,28px);
    transition:border-color .3s ease, box-shadow .3s ease;
  }
  .tv__card.is-on { border-color:var(--line); }
  .tv__n {
    display:block; font-family:var(--mono); color:var(--label);
    font-size:9.5px; letter-spacing:var(--pm-ls-label); text-transform:uppercase;
    margin-bottom:.7em;
  }
  .tv__h {
    margin:0 0 .4em; color:var(--text-title);
    font-family:var(--sans); font-weight:500;
    font-size:clamp(15px,1.15vw,19px); letter-spacing:-.01em; line-height:1.2;
  }
  .tv__p {
    margin:0; color:var(--text); font-family:var(--sans);
    font-size:clamp(13px,.95vw,15px); line-height:1.5; letter-spacing:-.005em;
  }

  /* Narrow: one column, and the connector runs straight down between them. */
  @media (max-width:760px) {
    .tv__cards { grid-template-columns:minmax(0,1fr); gap:clamp(44px,7vh,72px); }
    .tv__card:nth-child(n) { grid-column:1; grid-row:auto; }
  }

  /* Reduced motion keeps the scroll-linked reveal - it only moves while the
     reader does - but drops the fades layered on top of it. */
  .tv--still .tv__card { transition:none; }

  /* the mark goes home, on every page */
  .lockup__home { display:inline-flex; text-decoration:none; color:inherit; border-radius:2px; }
  .lockup__home:focus-visible { outline:2px solid var(--line); outline-offset:4px; }
  .lockup__home:hover .lockup__type { color:var(--pm-ink-600); }
