/* Reader-controlled text size. Every authored size on the site is calc(<len> * var(--ts)),
   so this one number is the whole control; type-scale.js writes it to <html> and the inline
   snippet in each page's <head> applies the stored value before first paint.
   Declared outside the theme blocks on purpose: light and text size are independent choices, and
   a value living in :root[data-theme="day"] would be reset every time the paper changed. */
:root{ --ts:1 }
  :root{
    
    --paper-day:#FBFAF8; --paper-dusk:#E2DED4; --paper-night:#0D141D;
    --bg:var(--paper-day); --card:#FFFFFF; --card2:#F4F2EC;
    --line:#E5E2DA; --line2:#D2CEC4;
    /* The resting edge of the frosted .plate in a product hero, and the only edge it has once
       motion is turned down. --line is a hairline meant for dividers between rows of text and
       measures 1.24:1 on paper; the plate is a large translucent card sitting on a moving field,
       and at that weight it had no boundary at all. This is the paper's own hue with a slightly
       lifted chroma (roughly 1.6x --line's, keeping the relationship that token already has to
       its paper) set to a constant OKLab dL of 0.27 from the paper in all three themes.

       dL, not the contrast ratio, is what is held constant across themes: WCAG's luminance ratio
       is a poor predictor of appearance in the light-on-light regime this edge lives in, and
       equalising the ratio would have made day's edge perceptibly heavier than the other two.
       Ceiling is about 3.2:1 if it ever needs more; past that a 1px rim on a 16px radius stops
       reading as an edge and starts reading as a box drawn around the copy. */
    --line-deep:#949185;   /* 3.03:1 on --bg; --line is 1.24:1 and --line2 1.51:1 */
    --txt:#191917; --dim:#4F4C46; --dim2:#6B6860;
    --mint:#0E7A62;   /* was #0F7F66: 4.42:1 on --card2, now 4.65:1 worst case */ --mint-d:#0B6350;
    --amber:#8A5A0F; --rose:#A8383F; --blue:#22607F;

    /* ---- pillar accents -------------------------------------------------------------------
       One hue per product, used for every label that names a pillar: the numbered eyebrows,
       the router cards on the homepage, the .cap headers. The pairing was already latent in
       the markup -- /models/ has always carried .eyebrow.b and /governance/ .eyebrow.a -- but
       a later rule flattened BOTH to --faint, so the two classes rendered identically and the
       wayfinding they encoded did nothing. These restore it.

       Text tokens, so each is the AA-tuned value: they carry 12.5-15.5px uppercase labels,
       which is small text and wants 4.5:1, not the 3:1 a fill would need. Measured against
       this theme's --bg. */
    --p-models:#1F5FA8;    /* 6.17:1 on --bg */
    --p-context:#0C6E58;   /* 5.94:1 -- a shade off --mint so the label is not mistaken for a link */
    --p-gov:#8A5A0F;       /* 5.67:1 -- same value as --amber, which is where it came from */
    --p-docs:#9A3D8F;      /* 5.86:1 */

    /* ---- ring stops ------------------------------------------------------------------------
       Fills for the border that turns around the hero plate. Only three are defined here: the
       ring on a product page is locked to that one product, and there is no /documents/ page for
       the fourth to belong to. The homepage cycles all four and carries --b-docs in home.css.

       Re-derived rather than reused from --p-* above, and the reason is the property that makes
       those good text tokens: all four were walked to the same narrow contrast band, which
       leaves them near-ISOLUMINANT. Lightness is the one channel a dichromat keeps whole, so an
       isoluminant set is exactly the set that stops reading as colour under dichromacy. These
       hold each pillar's hue exactly (max drift 0.5deg, so the ring still reads as the product's
       colour) and buy their separation with a small alternating lightness stagger and a modest
       chroma gain instead -- +/-0.02 and 1.20-1.35x on the light papers, +/-0.06 and 1.30x on
       night. That stagger is what the four-colour homepage ring leans on for a reader who cannot
       see it change colour -- imperfectly, and home.css records exactly which themes it fails on
       and by how much. Here it costs nothing, since this ring is one colour, and it keeps the
       two files' tokens identical, which is the only way this palette stays maintainable. */
    --b-models:#1168C2; --b-context:#006D56; --b-gov:#8A5800;

    /* ---- eval tag swatches ----------------------------------------------------------------
       Categorical identity for the five /evals/ tags. Deliberately NOT the pillar accents
       above, for the same reason --dv-win/--dv-loss are not --mint/--amber: a token tuned to
       carry small text is pinned to one lightness band, and with five slots in that band the
       set collapses -- the AA-tuned values measured 10.7 apart in OKLab (floor is 15) and 3.8
       under deuteranopia (target 8). Five readable-as-text hues that also separate is not a
       thing this palette has; five fills that separate is.

       So the job is split. These are FILLS on an 8px swatch, which only needs 3:1, and that
       freedom is what buys the separation. The chip's TEXT stays on --dim, which measures
       6.55-8.20:1 on the tints below.

       The 3:1 is measured against the swatch's OWN CHIP, not against the paper. That matters
       and it is the thing to get wrong here: the chip is washed with 10% of the same hue, so a
       swatch sits on a ground tinted TOWARDS itself and loses contrast against it. Checked
       against paper, an earlier set of these passed and then measured 2.40:1 in place.
         day   vs own tint 3.09-6.93  normal 19.0  protan 14.7  deutan 12.2  -- all checks pass

       WHICH TAG GETS WHICH HUE is not free, and Quality is the reason to say so here. Four of
       the five are pinned by meaning: cost is money and takes the amber, and compression and
       memory take the Models blue and the Context mint so a chip agrees with the pillar page
       it belongs to. That leaves agents and quality to fill whatever the wheel has left, and
       with the other four fixed the ONLY hues that clear every gate are the red wedge at
       H0-H30 -- everything else collapses against a neighbour. So Quality, which is a
       measurement axis and must not read as a verdict on the card, takes the violet, and
       agents takes the wedge at H0, a berry that keeps blue in it rather than the H17 crimson
       that was here before. Moving Quality alone was not available. */
    --tag-agents:#96004D; --tag-memory:#00987F; --tag-compression:#00538A;
    --tag-cost:#9E6600;   --tag-quality:#9032DD; --tag-governance:#B23A1A;
    
    --faint:#747066;
    --surface:251,250,248;
    --wave-line:25,25,23;
    /* ---- the accent strand, one triplet per product -----------------------------------------
       RGB triplets rather than hexes because backdrop.css colours its layers with rgb() from them. The
       data-pillar block at the end of the token section points --wave-accent at one of these,
       and that indirection is the whole of the per-product recolour: /models/ gets a blue field,
       /governance/ an amber one, /context/ and the five legal subheros the green that has always
       been here.

       NOT the --p-* tokens. Those are AA-tuned to carry 12.5-15.5px uppercase labels; a canvas
       fill owes no contrast ratio and wants the opposite trade. Each of these is the pillar's
       hue verbatim at the lightness the existing accent already had -- OKLCH L 0.533 on the
       light papers, 0.782 on night -- with chroma pushed to the practical sRGB ceiling. Sharing
       L is what keeps the three fields equal in WEIGHT, so no product page's hero is louder than
       another's, and the chroma is what carries the hue once a strand is composited.

       Chroma is nearly free and it is the entire signal. Strands are stroked at alpha 0.10-0.18
       under `lighter`, so the page only ever sees roughly mix(paper, accent, 0.12), and in that
       mix the LIGHTNESS gap from paper (0.452 on day) swamps chroma completely. Measured, going
       to the gamut edge costs 3% of visible weight (dE from paper 3.45 -> 3.55) and doubles the
       separation between two products' composited fields (0.61 -> 1.02).

       --wave-context is byte-for-byte the value that has always been here, which is the check
       that this is the site's own rule and not one imposed on it: applying the construction at
       the context hue reproduces #0F7F66 exactly.

       THE HONEST LIMIT, because it should not have to be rediscovered. On the light papers only
       about 4% of the raw difference between two accents survives compositing at the working
       alpha, so /models/ and /context/ differ by roughly one JND. It is a colour CAST, not a
       colour. Nothing inside one lightness band fixes that -- two opposite hues at maximum
       chroma composite to about 1.3 dE -- and the equal-weight family is worth more than the
       extra separation would be. Night behaves completely differently (composited 4.6-7.6,
       an order of magnitude better) because compositing happens in linear light and OKLab's
       cube root expands the shadows: adding 6.6% of a bright colour to near-black paper is a
       large perceptual move, adding 12% of a dark one to near-white paper is a small one. So on
       day and dusk the wayfinding is still carried by the eyebrow, which is already pillar
       coloured, and the field agrees with it rather than announcing on its own. If a day field
       ever has to actually declare its product, the lever is --wave-alpha, not the accent. */
    --wave-models:12,107,202;    /* #0C6BCA */
    --wave-context:15,127,102;   /* #0F7F66 -- unchanged */
    --wave-gov:148,96,12;        /* #94600C */
    /* Declared ONCE, here; the :root[data-pillar] block further down is what repoints it.
       :root[data-theme="night"] and :root[data-pillar="models"] weigh exactly the same (0,2,0),
       so nothing about specificity decides this -- SOURCE ORDER does, and the order is the
       invariant worth guarding: the theme blocks sit above, the routing block below, so the
       routing wins. An earlier note here had that backwards and claimed a theme block would
       win; it would not, at this order. The live risk is the opposite one. Hoisting the three
       data-pillar lines up beside the other :root token blocks -- a tidy-looking refactor with
       no obvious downside -- puts them BEFORE the themes and hands night's --wave-accent back
       to the theme block, silently painting /models/ and /governance/ context green on night
       only. Keep the routing last. The themes retune the triplets above rather than
       redeclaring this, which is what keeps the question theoretical. */
    --wave-accent:var(--wave-context);
    --wave-alpha:1;
    --hl:#FFE1A8;
    --tier-hi:rgba(232,243,239,.5);
    --on-accent:#0D141D;
    /* Text painted ON a --mint fill. It has to flip with the theme: day and dusk mint is dark
       so white reads (5.28:1 / 7.01:1), but night mint is light, where white was 1.90:1. */
    --on-mint:#FFFFFF;
    /* Diverging pair for the per-field chart. Deliberately NOT --mint/--amber: those are tuned
       for small text on paper, and once both were darkened for AA they sat 13.5 apart in OKLab,
       which is under the 15 floor where full-colour readers stop telling them apart. These are
       chart fills, so they are free to be more saturated. Each theme's pair clears the lightness
       band, chroma floor, CVD separation, normal-vision floor and 3:1 vs its own surface. */
    --dv-win:#0B7A5E; --dv-loss:#B4530A;
    --on-hl:#191917;
    --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
    
    --sans:"Inter","SF Pro Text",-apple-system,BlinkMacSystemFont,"Segoe UI Variable Text","Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;

  }
  
  :root[data-theme="dusk"]{
    --bg:var(--paper-dusk); --surface:226,222,212;
    --card:#EDEAE0; --card2:#D8D3C6;
    --line:#CFCABC; --line2:#B6B0A0;
    --line-deep:#857D69;   /* 3.04:1 on dusk paper -- dusk's own hue, L solved for the ratio */
    --dim:#403D37; --dim2:#57544C; --faint:#645F55;
    /* Dusk inherited the accents from the day :root but paints them on darker paper, so links
       sat at 3.31:1 and the amber/rose labels below 4.5:1. Same hues, nearest passing lightness
       against dusk's --bg, --card and --card2. --blue already clears at 4.61:1. */
    --mint:#0C6551; --amber:#754C0D; --rose:#9E353B;
    --dv-win:#04704F; --dv-loss:#A8460A;
    /* Pillar accents on dusk paper. Same hues, nearest passing lightness. The day values fall
       to 4.40-4.79:1 here, which puts --p-gov under AA on the page and all four under it on
       the tinted card. These measure 5.42-5.92:1 on --bg, 4.87:1 worst case on --card2. */
    --p-models:#1B5192; --p-context:#0A5C49; --p-gov:#754C0D; --p-docs:#8A3480;
    /* Ring stops on dusk paper, same construction as day. Worst adjacency 18.1 normal / 12.9
       under the pessimistic of two published CVD simulators. */
    --b-models:#005AB3; --b-context:#005B47; --b-gov:#754A00;
    /* Dusk deliberately sets no --wave-* triplets and never has. The dusk pillar tokens differ
       from the day ones only by an AA lightness walk onto darker paper, which is a constraint on
       TEXT; the canvas is not text, so it inherits the day hues. Deriving from dusk's own hues
       instead lands 3/255 away -- under a JND, not worth a block. The measured cost is that the
       dusk field is 13% quieter than day, a deficit that already existed for the green and is
       left alone; the lever for it is --wave-alpha, not the accent. */
    /* Tag swatches: the three that fell under 3:1 against their own chip on the darker paper.
       Agents and quality clear it on both papers and are inherited from the day set above.
         dusk  vs own tint 3.15-5.44  normal 17.0  protan 11.3  deutan 9.6  -- all checks pass */
    --tag-cost:#956000; --tag-memory:#00826D; --tag-compression:#005191; --tag-governance:#A63615;
  }
  
  :root[data-theme="night"]{
    --bg:var(--paper-night); --surface:13,20,29;
    --card:#141D28; --card2:#1B2734;
    --line:#243040; --line2:#33445A;
    --line-deep:#4E6480;   /* 3.05:1 on night paper -- night's own hue, L solved for the ratio */
    --txt:#E8EEF3; --dim:#B9C4CE; --dim2:#8593A1; --faint:#748391;
    --mint:#5FCFB4; --mint-d:#54BDA4; --on-mint:#0D141D;   /* 9.75:1 on night mint */
    --dv-win:#35A88A; --dv-loss:#BC7A2E;
    --amber:#E3A049; --rose:#F08266; --blue:#7FB2CE;
    /* Pillar accents inverted for dark paper: the day values measure 2.87-3.13:1 here. These
       are 8.06-10.63:1 on --bg and 6.60:1 worst case on --card2. */
    --p-models:#9BC9F5; --p-context:#5FCFB4; --p-gov:#E3A049; --p-docs:#DE93CC;
    /* Ring stops on night paper. Night needed a bigger stagger (+/-0.06) and 1.30x chroma
       because its pillar tokens sit in an even narrower contrast band than the light ones,
       8.06-10.63:1, leaving less lightness variation to start from. */
    --b-models:#ACD6FF; --b-context:#00BA9B; --b-gov:#CF8500;
    /* Tag swatches, stepped for the dark surface rather than flipped from the day set.
         night  vs own tint 3.06-5.67  normal 15.7  protan 13.4  deutan 11.8  -- all checks pass */
    --tag-agents:#C50068; --tag-memory:#00AC90; --tag-compression:#578EFF;
    --tag-cost:#C88200;   --tag-quality:#A821C3; --tag-governance:#FF7A5C;
    --wave-line:232,238,243;
    /* Night retunes the triplets and leaves --wave-accent alone -- see the note on that
       declaration in the day block for why a --wave-accent here would silently break the
       product pages. --wave-context is unchanged and is the anchor the other two derive from:
       its L 0.782 / C 0.110 is held across the family and each pillar's hue substituted in.

       Night holds chroma EQUAL rather than chasing the gamut ceiling the way the light papers
       do, because its anchor is only 0.749 of that ceiling -- it came from a pillar TEXT token
       tuned for 8-10:1 on dark paper -- and it can afford to, since night retains ~35% of the
       raw difference through compositing where day retains ~4%.

       --wave-models is NOT --p-models, and this is the one place the difference is a defect
       rather than a preference: the field draws every ninth strand in --wave-line as a second
       population, and #9BC9F5 measures 14.5 from that white strand, under the floor of 15. A
       /models/ field built on the pillar token would have collapsed its two strand populations
       into a single pale wash. #7DBEFB measures 19.3.

       --wave-gov is the one place chroma goes DOWN from its pillar (0.1295 -> 0.1104): letting
       amber keep its extra chroma while blue sat at the family value would have made
       /governance/ visibly the loudest of the three fields. Equalising is what makes three
       pages feel like one site. */
    --wave-models:125,190,251;   /* #7DBEFB */
    --wave-context:95,207,180;   /* #5FCFB4 -- unchanged */
    --wave-gov:229,171,101;      /* #E5AB65 */
    --wave-alpha:.55;
    --tier-hi:rgba(95,207,180,.09);
  }
  /* ---- which product this page is ---------------------------------------------------------
     The three product pages carry data-pillar on <html>; the five legal subheros and /evals/
     carry nothing and keep the default green. Two of these routes exist and both matter.

     ON <html>, NOT ON <body>, and that is not a stylistic choice. backdrop.css paints the field on
     html::before and html::after, which inherit custom properties from <html>. A class on <body>
     would cascade --wave-accent to every DESCENDANT of body, but <html> is body's PARENT, so the
     value there would be unchanged and the field would still be green. On <html> it costs no JS.

     Authored into the static HTML rather than written by a script, so it is present at first
     paint and present with scripting disabled entirely. That makes it strictly better behaved
     than data-theme and data-motion, both of which are written by the inline <head> snippet and
     are simply absent with JS off -- which is why the no-JS net at the bottom of this file has
     to exist for those and does not have to exist for this.

     Nothing can clobber it: theme.js only ever calls setAttribute('data-theme') and motion.js
     only ever calls setAttribute('data-motion'). Neither reads or rewrites the other attributes
     on the element.

     The attribute values are the suffixes the tokens and the router classes already use, so
     data-pillar="gov" reads against --p-gov and .ctacard.k-gov without a translation table. */
  /* Three values, but the rules that consume them are keyed html[data-pillar], which matches
     ANY value. The rest of the token system already knows a fourth pillar (--p-docs, .k-docs),
     so data-pillar="docs" is a thing someone will plausibly write the day a /documents/ page
     ships. It would match the ring rules, find --tw-ring-1 unset, and -- because an unresolved
     var() poisons the whole declaration, not just the one stop -- fall back to background:none:
     an invisible ring on a plate that still got its deepened edge, with the wave left context
     green under a magenta eyebrow, and nothing anywhere saying why. Hence the explicit fallback
     on the gradient below. Add the routing line here when the page ships; the fallback only
     stops the failure being silent, it does not make "docs" correct. */
  :root[data-pillar="models"] { --wave-accent:var(--wave-models); --tw-ring-1:var(--b-models) }
  :root[data-pillar="context"]{ --wave-accent:var(--wave-context); --tw-ring-1:var(--b-context) }
  :root[data-pillar="gov"]    { --wave-accent:var(--wave-gov);     --tw-ring-1:var(--b-gov) }

  *{box-sizing:border-box}
  html{scroll-behavior:smooth}
  body{margin:0;background:var(--bg);color:var(--txt);font-family:var(--sans);font-size:calc((16.5px) * var(--ts));line-height:1.58;letter-spacing:-.005em;-webkit-font-smoothing:antialiased}
  a{color:inherit;text-decoration:none}
  
  .lede a,p a:not(.btn):not(.more){text-decoration:underline;text-underline-offset:3px}
  
  ::selection{background:var(--mint);color:var(--on-mint);text-shadow:none}
  ::-moz-selection{background:var(--mint);color:var(--on-mint);text-shadow:none}
  .wrap{max-width:1180px;margin:0 auto;padding:0 28px}
  
  /* Section label. Three things stack here -- label, headline, paragraph -- and before this
     they were separated by size alone: a 15.5px --faint eyebrow over a 32px --txt h2 over a
     16.5px --dim lede. --faint clears AA, but at .1em tracking in caps it reads as something
     printed faintly rather than as a label, so the eye went to the h2 and the label was scenery.

     Two changes fix it without adding weight. It comes DOWN in size, which stops it competing
     with the headline and lets it read as a caption to it; and it takes its pillar accent plus
     a short rule, so it reads as a marker. The rule is currentColor, so one declaration covers
     all three pillars and all three papers.

     .a and .b were already in the markup -- /governance/ has always carried .eyebrow.a and
     /models/ .eyebrow.b -- but the rule that used to sit here painted both --faint, so the two
     classes rendered identically. That is the invisibility being fixed, not a new scheme. */
  .eyebrow{
    display:flex;align-items:center;gap:10px;
    font-family:var(--sans);font-size:calc((13px) * var(--ts));font-weight:700;letter-spacing:.14em;
    text-transform:uppercase;color:var(--p-context);
  }
  .eyebrow::before{content:"";flex:none;width:22px;height:2px;border-radius:1px;background:currentColor}
  .eyebrow.b{color:var(--p-models)}
  .eyebrow.a{color:var(--p-gov)}
  .eyebrow.d{color:var(--p-docs)}
  /* .final is text-align:center, and text-align does not reach the children of a flex box --
     so making .eyebrow a flex container silently left-aligned the three closing eyebrows
     (/models/, /context/, /governance/) that sit inside one. Centre the flex line instead. */
  .final .eyebrow{justify-content:center}
  h1,h2,h3,h4{margin:0;font-family:var(--sans);line-height:1.16;letter-spacing:-.02em;font-weight:600}
  h1{font-size:calc((clamp(35.5px,5.5vw,56px)) * var(--ts));letter-spacing:-.03em;font-weight:500}
  h2{font-size:calc((clamp(24px,3vw,32.5px)) * var(--ts))}
  /* These sizes moved down a level with the markup: the subpages used to run h1 -> h2 -> h4,
     skipping h3 entirely, so a screen reader announced a level that was never there. The
     headings are now h3 (and h4 inside .tdom), and each keeps the size it already rendered at,
     so the demotion is visually inert. */
  h3{font-size:calc((16px) * var(--ts))} h4{font-size:calc((15.5px) * var(--ts))}
  p{margin:0}
  .lede{color:var(--dim);font-size:calc((16.5px) * var(--ts))}

  /* Bold in prose lifts to full ink. Body copy sits on --dim, so a <b> inside it was bolder
     but no darker, which is the weakest of the emphasis marks the site uses and the one it
     reaches for most. Until this rule existed every author worked around it by hand: there
     were 22 instances of style="color:var(--txt)" on a <b> across the four pages, which is
     the same decision made 22 times and available to be forgotten on the 23rd.
     Anything that wants a different colour -- .mnotice b, .note b, .esave b, .fct-n b -- is
     more specific and still wins. */
  .lede b,.lede strong,p b,p strong,li b,li strong,td b,td strong{color:var(--txt);font-weight:650}

  /* Skip link. Off-canvas rather than display:none or width:0, because a hidden element is not
     focusable and the whole point is that the first Tab reaches it. It targets
     <main tabindex="-1"> so focus actually moves, not just the scroll position. */
  .skip{
    position:absolute;left:-9999px;top:0;z-index:120;
    font-family:var(--sans);font-size:calc((14.5px) * var(--ts));font-weight:600;
  }
  .skip:focus{
    left:12px;top:12px;padding:10px 16px;border-radius:8px;
    background:var(--bg);color:var(--txt);border:1px solid var(--line2);
    text-decoration:none;outline:2px solid var(--mint);outline-offset:2px;
  }
  main:focus{outline:none}

  .vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

  /* ---- per-field diverging chart (models page) ------------------------------------------
     Who wins each field, and by how much. A plain column of "3.7x" and "1.1x" hides the fact
     that two of those numbers point the other way; putting parity on a line and letting the
     bars grow away from it makes the direction the first thing you read.

     Bar LENGTH is log2(ratio), so a 2x win and a 2x loss draw the same width. Positions are
     inline styles because they are computed from the eval, not from layout.

     Direction is encoded three times over, so colour is never load-bearing: which side of the
     parity line the bar sits on, the hue, and the words "fewer" / "more" in the value. */
  /* Model picker. A native <select> on purpose: it is the one control that already works with
     a keyboard, a screen reader and a thumb on every platform without us reimplementing it. */
  .mpick{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:20px}
  .mpick label{font-family:var(--sans);font-size:calc((12px) * var(--ts));font-weight:600;
    letter-spacing:.1em;text-transform:uppercase;color:var(--dim2)}
  .mpick select{
    font-family:var(--sans);font-size:calc((15px) * var(--ts));font-weight:600;
    color:var(--txt);background:var(--card);border:1px solid var(--line2);border-radius:9px;
    padding:8px 12px;cursor:pointer;
    /* 15em of a font that scales with --ts is 338px at the largest text size, which is wider
       than a small phone. Ask for the comfortable width, never exceed the column. */
    min-width:min(15em,100%);max-width:100%;
  }
  .mpick select:focus-visible{outline:2px solid var(--mint);outline-offset:2px}
  .mpanel[hidden]{display:none}
  /* Amber, not red: a retired model is a fact to register before reading the numbers, not an
     error. It sits above the heading because the numbers below it are still true, and someone
     who reads them first has already taken away the wrong thing. */
  .mnotice{
    margin:26px 0 0;padding:12px 16px;border-radius:10px;
    font-family:var(--sans);font-size:calc((14.5px) * var(--ts));line-height:1.55;
    color:var(--dim);
    background:color-mix(in srgb,var(--amber) 10%,transparent);
    border:1px solid color-mix(in srgb,var(--amber) 34%,transparent);
  }
  .mnotice b{color:var(--amber)}
  .mnotice + h3{margin-top:18px}
  .mpanel > h3:first-child{margin-top:30px}

  .dfield{margin:16px 0 0}
  .dfield-legend{display:flex;flex-wrap:wrap;gap:8px 18px;align-items:center;
    font-family:var(--sans);font-size:calc((13px) * var(--ts));color:var(--dim2);margin-bottom:12px}
  .dfield-key{display:inline-flex;align-items:center;gap:7px}
  .dfield-key i{width:22px;height:9px;border-radius:2px;display:block;flex:none}
  .dfield-key.w i{background:var(--dv-win)}
  .dfield-key.l i{background:var(--dv-loss)}

  .dfield-row{display:grid;grid-template-columns:11.5em 1fr 6.6em;align-items:center;
    gap:14px;padding:3px 0}
  .dfield-name{font-family:var(--sans);font-size:calc((14px) * var(--ts));color:var(--dim);
    text-align:right;overflow-wrap:anywhere}
  .dfield-track{
    position:relative;height:17px;
    /* recessive ticks at 1.25x the other way, then 1.25x, 1.5x, 2x, 3x our way; parity on top */
    background:
      linear-gradient(var(--line) 0 0) 4.19% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 31.17% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 42.23% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 59.66% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 84.24% 0/1px 100% no-repeat,
      linear-gradient(var(--line2) 0 0) 17.65% 0/1.5px 100% no-repeat;
  }
  /* The 3B's spread is a few percent, not the 31B's 3.7x, so it gets its own axis: ticks at
     -4/-2/+2/+4% and parity dead centre. Sharing the 31B's axis would draw every bar here as
     an invisible sliver; sharing its LABELS would invite comparing two different scales. */
  .dfield-track.m3b{
    background:
      linear-gradient(var(--line) 0 0) 10% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 30% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 70% 0/1px 100% no-repeat,
      linear-gradient(var(--line) 0 0) 90% 0/1px 100% no-repeat,
      linear-gradient(var(--line2) 0 0) 50% 0/1.5px 100% no-repeat;
  }
  .dfield-bar{position:absolute;top:2px;bottom:2px;display:block}
  /* Rounded only on the growing end, square against parity: the flat edge is what makes the
     baseline read as a baseline. */
  .dfield-bar.w{background:var(--dv-win);border-radius:0 4px 4px 0}
  .dfield-bar.l{background:var(--dv-loss);border-radius:4px 0 0 4px}
  /* Values wear ink, not the series colour: the fills are tuned to sit on a surface (3:1), which
     is not enough for 13px text, and dusk's loss fill measured 4.41:1 as a label. The bar beside
     it carries the identity, and the words "fewer" / "more" carry the direction. */
  .dfield-val{font-family:var(--mono);font-size:calc((13px) * var(--ts));white-space:nowrap;
    color:var(--dim)}

  .dfield-scale{display:grid;grid-template-columns:11.5em 1fr 6.6em;gap:14px;
    margin-top:6px;font-family:var(--sans);font-size:calc((11px) * var(--ts));
    letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
  .dfield-scale .t{position:relative;height:1.2em}
  .dfield-scale .t span{position:absolute;transform:translateX(-50%);white-space:nowrap}

  .dfield-more{margin-top:18px;font-family:var(--sans);font-size:calc((14px) * var(--ts))}
  .dfield-more summary{cursor:pointer;color:var(--mint)}
  .dfield-more table{margin-top:12px}

  @media(max-width:760px){
    /* The name column stops being a column and becomes a line above its own bar, so the track
       keeps a usable width at 390px instead of collapsing to a stub. */
    .dfield-row{grid-template-columns:1fr 5.6em;grid-template-areas:"name name" "track val";
      gap:2px 12px;padding:7px 0}
    .dfield-name{grid-area:name;text-align:left;font-size:calc((13.5px) * var(--ts))}
    .dfield-track{grid-area:track}
    .dfield-val{grid-area:val;text-align:right}
    .dfield-scale{grid-template-columns:1fr 5.6em}
    .dfield-scale > .lbl{display:none}
    /* On a ~235px track this label runs into "parity"; its gridline stays, so the two
       loss bars are still readable against a tick. */
    .dfield-scale .t span.lo{display:none}
  }
  
  section{padding:88px 0;border-top:1px solid var(--line);position:relative;z-index:0;
    scroll-margin-top:80px}
  section > .wrap{position:relative;z-index:1}

  
  
  /* The animated wave field in the hero of the product pages (the other pages have only the still field behind them, backdrop.css).
     Section 88px of padding is irrelevant here: the canvas fills the hero and sits under .wrap (z-index 1).
     The same height as the hero (the CTA) at every width. Below 980px it used to be capped at min(620px,72vh) with a fade, which on
     a phone left the field covering only the top of a tall hero; test/wave-height.test.mjs holds it to the hero's own height.
     The canvas also carries the page's own ground. The still field (backdrop.css) is fixed behind the whole page, so without a ground
     it ran under the animated one and the hero showed two fields on top of each other; the ground hides it where the hero is, and the
     still field starts below the rule the hero ends on (.subhero). */
  .hero canvas.flow{position:absolute;top:0;bottom:0;left:0;right:0;
    width:100%;height:100%;z-index:0;pointer-events:none;background:var(--bg)}
  /* Inline code inside prose: a header name, an endpoint path, a command. Given a chip so it
     reads as a literal you type rather than as emphasis. --card2 and --line are both redefined
     per theme, so this follows day, dusk and night without an override of its own.
     Slightly under 1em because the mono face runs large next to the sans at the same size, and
     the vertical padding is kept to 1px so a chip mid-paragraph does not open up the line. */
  .mono{
    font-family:var(--mono);font-size:.92em;
    background:var(--card2);border:1px solid var(--line);border-radius:5px;padding:1px 5px;
  }
  /* A literal in prose, chip or bare <code>, is one word to the browser: a URL or a path has no
     break opportunity, so a long one set the narrowest width its paragraph, card and page could
     take (/docs/ scrolled sideways on phones). It may break anywhere, and only where it cannot fit
     a line of its own; `anywhere`, not `break-word`, because only `anywhere` also lowers that
     narrowest width. Code blocks (<pre>) keep their lines and scroll.
     A table cell keeps its own rule. Laid out as a table, a column is given at least its
     narrowest width, so a URL column stays whole and the prose columns wrap around it; lowering
     that width split URLs mid-word where they fitted. A stacked row on a phone already breaks
     anywhere (table.stackable td), and inherit hands that down. */
  .mono,:not(pre)>code{overflow-wrap:anywhere}
  :is(td,th) :is(.mono,code){overflow-wrap:inherit}
  
  .head{max-width:none}
  .head h2{margin:12px 0 15px}

  
  
  .plate{position:relative;border-radius:16px;
    background:color-mix(in srgb,var(--bg) 32%,transparent);
    -webkit-backdrop-filter:blur(22px) saturate(1.25);backdrop-filter:blur(22px) saturate(1.25);
    border:1px solid color-mix(in srgb,var(--line) 90%,transparent)}
  .hero .plate{padding:30px 34px 32px;margin-left:-34px}

  /* ---- the product watermark on the hero plate ------------------------------------------
     The homepage names each product three ways -- a numbered eyebrow, a pillar hue, and a
     glyph sitting large and faint in the tile's top-right corner. The product page it links
     to carried only the first two, so the strongest of the three cues was dropped at exactly
     the moment the reader arrived to read about that product. This restores it, with the
     glyph the router card already uses for the same product, so the tile the reader clicked
     and the page they land on wear the same mark.

     Inlined per page rather than reached through <use href="#id">: the sprite <defs> lives in
     index.html alone, an external <use> is unreliable across engines and breaks currentColor
     where it does work, and one path per page is cheaper than shipping four to each of three
     pages. This is the same choice the router cards made -- they inline their paths too.

     THE CLIPPING IS ON THE GLYPH, NOT ON THE PLATE, and that distinction is the whole of a
     regression this rule shipped with once. Clipping the mark to the corner obviously wants
     .hero .plate{overflow:hidden} -- and that silently deletes the animated pillar ring below.
     The ring is a ::before at inset:-1px, so it paints entirely inside the plate's 1px BORDER
     band; overflow clips descendants to the PADDING box, which is the one region the ring does
     not occupy, so all four edges of it vanish. Nothing errors and the page looks deliberate.
     The rule that follows had already written the warning down -- it rejects overflow:hidden
     for this element on a different ground (the plate runs margin-left:-34px and is meant to
     hang outside its column) -- and it was not read. So: the span does its own clipping, with
     the corner radius the plate's inner edge actually has (16px box minus the 1px border).

     opacity .10, and the fill/opacity are restated on the svg rather than left to a shared
     rule. Both matter: the showcase learned this the hard way, where a missed restatement put
     an 88px glyph on the page at FULL opacity and dropped body copy over it to 1.49:1 at
     night. A watermark that competes with the copy is not decoration, it is damage. */
  .hero .plate > .ticon{
    position:absolute;top:0;right:0;
    width:clamp(104px,14vw,164px);aspect-ratio:1;
    z-index:0;pointer-events:none;
    overflow:hidden;border-top-right-radius:15px;
    color:var(--line-deep);
  }
  .hero .plate > .ticon svg{width:100%;height:100%;display:block;fill:currentColor;opacity:.10}
  html[data-pillar="models"]  .hero .plate > .ticon{color:var(--p-models)}
  html[data-pillar="context"] .hero .plate > .ticon{color:var(--p-context)}
  html[data-pillar="gov"]     .hero .plate > .ticon{color:var(--p-gov)}
  /* Lift the plate's own content over the mark. Without this the glyph, being positioned,
     paints on top of the crumb and the headline. */
  .hero .plate > :not(.ticon){position:relative;z-index:1}
  .head.plate{padding:24px 28px 26px;margin-left:-28px}
  
  @supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
    .plate{background:color-mix(in srgb,var(--bg) 92%,transparent)}
  }
  @media(max-width:980px){
    .hero .plate,.head.plate{margin-left:0;padding-left:22px;padding-right:22px}
  }

  /* ---- the hero plate's edge on a product page ---------------------------------------------
     Scoped to html[data-pillar], so this is the three product heroes and nothing else: the five
     legal subheros use the same .plate and keep the hairline they have.

     Two separate things, and the first one is the one that has to be right. The static border is
     the FINISHED state -- deeper than the hairline, because on a large translucent card sitting
     over a moving field --line at 1.24:1 read as no boundary at all -- and it must stand entirely
     on its own. Every path that removes the ring below lands here: reduced motion, motion off, an
     engine that will not register the @property, a browser without mask-composite. Nothing in the
     base rule may depend on a keyframe having advanced. That is the same footgun as the
     animation-fill-mode:both incident, where a section rendered empty because its resting state
     was frame 0 of an animation that never ran.

     The resting edge is NEUTRAL, not the product's colour, and that is deliberate. The ring stops
     measure 4.69-6.06:1 on the light papers, and a 1px rim at that weight on a 16px radius stops
     reading as an edge and starts reading as a box drawn around the copy -- the exact failure
     --line-deep was capped at ~3:1 to avoid. At rest the product is named by the eyebrow, which
     is already pillar coloured, and by the wave field behind the plate. The colour is what MOVES,
     which is the thing motion is being spent on. */
  html[data-pillar] .hero .plate{ border-color:var(--line-deep) }

  /* THE RING GEOMETRY, and the two traps in it.

     inset:-1px, not 0. An absolutely positioned child resolves inset against the containing
     block's PADDING box, so inset:0 would sit inside the border and leave the 1px edge showing
     underneath. At -1px the pseudo's border box is exactly the plate's, and border-radius:inherit
     is then exact rather than approximate.

     The mask is what makes this a ring rather than a wash. .plate carries backdrop-filter, which
     forces a stacking context AND makes the plate the containing block for this pseudo, so
     z-index:-1 does NOT push the gradient behind the card: inside a stacking context, negative-z
     children paint AFTER the root's own background and border, and the gradient would cover the
     whole frosted fill. The two-layer mask cuts the content box back out, leaving only the 1px
     padding band. z-index:-1 still earns its place by keeping the rim under the plate's own text.

     Not overflow:hidden with a rotated oversized child, which is the other way to build this.
     .hero .plate runs margin-left:-34px and deliberately hangs outside its column; clipping it
     would cut that off.

     Declared unconditionally rather than switched on at data-motion="full". "full" is the
     ABSENCE of the kill below, and it has to be: with JS off there is no data-motion attribute
     at all, so a positive selector would never match and the ring would be dead on exactly the
     pages that render without scripts. 22s rather than the homepage's 16s -- this is a page
     someone reads, and the edge should drift rather than circle. */
  html[data-pillar] .hero .plate::before{
    content:"";
    position:absolute;inset:-1px;z-index:-1;pointer-events:none;
    border-radius:inherit;
    padding:1px;
    /* Same mechanism as the CTA card on the homepage, locked to one colour instead of cycling
       four: a swell of this page's --tw-ring-1 travelling around an edge that is otherwise the
       resting --line-deep. Opaque throughout, so there is no alpha to interpolate and no frame
       at which the border thins out; at any frozen angle it is a deep edge with a coloured
       highlight resting on it, which is a finished-looking card rather than a stalled animation.

       `in oklab` and not `in oklch`: oklch would interpolate the HUE and sweep the ramp through
       colours nobody chose, where oklab crosses the a/b plane between exactly these two. Held
       over a 60deg plateau with long ramps so the highlight reads as a band travelling past
       rather than as a point.

       Written here rather than lifted into a custom property on .plate, which was the first
       shape of this and was silently broken: a var() inside a custom property is substituted on
       the element the PROPERTY is declared on, so the angle resolved against .plate -- where
       --tw-ring-a is not set and, being registered inherits:false, falls back to its 0deg
       initial value. The pseudo then got a gradient with 0deg baked in, the animation ran, and
       nothing moved. The angle must be substituted on the element the keyframes animate. */
    background:conic-gradient(in oklab from var(--tw-ring-a),
      var(--line-deep)   0deg  40deg,
      var(--tw-ring-1, var(--b-context)) 150deg 210deg,
      var(--line-deep) 320deg 360deg);
    -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
            mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;
            mask-composite:exclude;
    animation:tw-ringspin 22s linear infinite;
  }
  /* The angle has to be a REGISTERED property or it has no type and cannot be interpolated --
     the keyframes would jump instead of sweeping. @property is new to this codebase; on an
     engine that drops it (Firefox <128, Safari <16.4) the angle stays at its initial 0deg and
     the ring is a stationary highlight on a deep edge. Benign, because the rule above is already
     correct without it. inherits:false: it is consumed by the pseudo that animates it and must
     not leak into anything nested. */
  @property --tw-ring-a{ syntax:'<angle>'; inherits:false; initial-value:0deg }
  /* One keyframe on purpose. `to` alone starts the sweep from the property's own current value,
     so an animation that never advances -- reduced motion, the no-JS net's .001ms duration, a
     dropped @property -- leaves the ring at 0deg, which is an ordinary finished border. No
     fill-mode, ever. */
  @keyframes tw-ringspin{ to{ --tw-ring-a:360deg } }
  /* Keyed on html[data-pillar] rather than :root[data-pillar], and the two ring rules above
     match it deliberately. The kill has to COMPOUND onto <html> -- html cannot be a descendant
     of html, so the usual `:where(html[data-motion=...]) .thing` prefix form cannot reach a
     rule that already selects the root element. Compounded, and with :where() contributing no
     specificity of its own, this weighs exactly what the rule above weighs and wins purely on
     coming later, which is the contract every other kill on this site is written against.
     `:root` would have quietly broken that: it is a pseudo-class and adds a class-column point
     the base rules would then have kept.

     Removed, not frozen. A frozen ring would leave the plate wearing a stationary coloured rim
     at 4.69-6.06:1 against the 2.42:1 of the edge underneath -- so the quieter setting would end
     up with the LOUDER border. Dropping the pseudo hands the plate back its --line-deep edge,
     which is the state everything else here degrades to as well. */
  html:where([data-motion="reduced"],[data-motion="off"])[data-pillar] .hero .plate::before{ display:none }

  /* COLOUR COMES FROM THE TOKENS, NOT FROM LITERALS, and that is a correctness fix rather than
     tidying. This rule used to hardcode color:#8D8A82, which measures 3.08:1 on its own #F4F2EC
     background -- under the 4.5:1 that 13px body text owes -- and it was invisible in day while
     reading fine in the other two, because dusk and night had overrides and day was the value
     nobody re-checked. .note b was the same shape one level down: a day amber with a NIGHT
     override and no dusk one, so it sat at 3.96:1 on dusk.
     --dim and --amber already carry a per-theme value each, so pointing at them fixes all three
     themes at once and cannot drift again. Measured after the change, text against this rule's
     own background:
                      day    dusk   night
       .note  --dim    7.64   7.24   9.59
       .note b --amber 5.28   5.03   7.60
     The per-theme .note colour overrides further down are what a literal made necessary; they
     are gone with it, and the background overrides stay because the SURFACE still differs. */
  .note{background:#F4F2EC;border-bottom:1px solid #E5E2DA;color:var(--dim);font-family:var(--mono);font-size:calc((13px) * var(--ts));padding:9px 28px;text-align:center}
  .note b{color:var(--amber)}

  
  
  .pending{display:inline;font-family:var(--mono);font-size:.86em;color:#6B4508;background:rgba(232,165,74,.13);border:1px dashed #6b5330;border-radius:5px;padding:1px 6px;box-decoration-break:clone;-webkit-box-decoration-break:clone}

  

  /* Appearance popover. One 38px button in place of two 104px pills; see home.css for the
     reasoning. Fixed 38px because it is an icon, and the cluster already grows with --ts. */
  .appearance{position:relative;flex:none}
  .appearance-btn{
    display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;padding:0;
    border:1px solid var(--line2);border-radius:9px;background:transparent;cursor:pointer;
    color:var(--txt);transition:border-color .2s,color .2s;
  }
  .appearance-btn:hover{border-color:var(--txt)}
  .appearance-btn:focus-visible{outline:2px solid var(--mint);outline-offset:2px}
  .appearance-btn svg{display:block}
  .appearance-panel{
    position:absolute;top:calc(100% + 8px);right:0;z-index:80;
    display:flex;flex-direction:column;gap:14px;
    padding:16px;border-radius:12px;
    /* --card is already the raised surface in this stylesheet, and it flips with the theme,
       so the panel reads as sitting above the page rather than merging into it. At night a
       black drop shadow on near-black paper does nothing on its own. */
    background:var(--card);border:1px solid var(--line2);
    box-shadow:0 16px 40px rgba(0,0,0,.22);
  }
  .appearance-panel[hidden]{display:none}
  /* Same reasoning as home.css: --faint is tuned against the page, not against --card. */
  .appearance-panel .themeswitch button{color:var(--dim2)}
  /* flex-start, not the default stretch: every row used to be exactly as wide as the 104px
     pill it held, so the two were indistinguishable. The motion row can now also hold a line
     of explanation, and under stretch that widened the pills above it into long rounded
     troughs with three small glyphs huddled at the left end. The pill should be its own size
     whatever is sitting under it. */
  .ap-row{display:flex;flex-direction:column;align-items:flex-start;gap:7px}
  .ap-lbl{
    font-family:var(--sans);font-size:calc((11.5px) * var(--ts));font-weight:600;
    letter-spacing:.12em;text-transform:uppercase;color:var(--dim2);
  }
  /* Shown only when the page stood its own motion down, to say so.
     An explicit WIDTH, not a max-width. The panel is absolutely positioned and sizes to its
     content, and inside a column flex container a paragraph's max-width does not widen the
     box (the row is sized by the 104px pill above and the sentence then wraps to that,
     seven words tall). A width participates in the intrinsic sizing, so the panel opens to
     fit the note and closes back to the pills when there is no note to show.
     Scaled by --ts with everything else on the site, which holds the measure at roughly the
     same number of words per line however large the reader has asked for the text. */
  .ap-note{
    margin:0;width:calc(212px * var(--ts));
    font-family:var(--sans);font-size:calc((12px) * var(--ts));line-height:1.42;color:var(--dim2);
  }
  .ap-note[hidden]{display:none}
  /* The way back to auto, offered only once the reader has overridden something. A text
     button rather than a fourth pill position: handing the decision back is not a LEVEL, and
     it would not have been comparable to the three it sat beside. */
  .ap-reset{
    padding:0;border:0;background:none;cursor:pointer;text-align:left;
    font-family:var(--sans);font-size:calc((11.5px) * var(--ts));line-height:1.3;
    color:var(--dim2);text-decoration:underline;text-underline-offset:2px;
  }
  .ap-reset:hover{color:var(--mint)}
  .ap-reset:focus-visible{outline:2px solid var(--mint);outline-offset:2px;border-radius:3px}
  .ap-reset[hidden]{display:none}
  @media(max-width:560px){
    .appearance-panel{right:auto;left:0}
  }
  .btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border-radius:999px;padding:10px 18px;font-size:calc((16px) * var(--ts));font-weight:500;font-family:var(--sans);text-decoration:none;border:1px solid transparent;cursor:pointer;white-space:nowrap}
  .btn-p{background:var(--txt);border-color:var(--txt);color:var(--bg)}
  
  .btn-p:hover{opacity:.86}
  .btn-s{border-color:var(--line2);color:var(--txt);background:transparent}
  
  .btn-s:hover{background:var(--card2)}
  .btn-lg{padding:12px 24px;font-size:calc((15.5px) * var(--ts));border-radius:999px}

  .hero{padding:76px 0 80px;border-top:none}
  .hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:54px;align-items:center}
  .hero .sub{margin-top:22px;font-size:calc((20px) * var(--ts));color:var(--dim)}
  .hero .btns{display:flex;gap:12px;margin-top:30px;flex-wrap:wrap}
  .strip{margin-top:24px;font-family:var(--sans);font-size:calc((13.5px) * var(--ts));color:var(--dim2)}

  
  .stack{background:transparent;border:1px solid var(--line);border-radius:14px;padding:22px}
  .stack .t{font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin-bottom:16px}
  .layer{display:grid;grid-template-columns:104px 1fr;gap:14px;align-items:center;padding:13px 0;border-bottom:1px dashed var(--line)}
  .layer:last-child{border-bottom:none}
  .layer .lbl{font-family:var(--mono);font-size:calc((11.5px) * var(--ts));letter-spacing:.1em;text-transform:uppercase}
  .bars{display:flex;flex-direction:column;gap:5px}
  .bar{height:11px;border-radius:3px;position:relative}
  .bar.before{background:#E5E2DA}
  .bar .cap{position:absolute;right:-2px;top:-4px;font-family:var(--mono);font-size:calc((11px) * var(--ts));color:var(--dim2);transform:translateX(100%);padding-left:8px;white-space:nowrap}
  .bar.before .cap{right:9px;transform:none;padding-left:0;top:-3px}
  .bar.after .cap{color:inherit}
  .layer.m .lbl{color:var(--blue)} .layer.m .bar.after{background:var(--blue);color:var(--blue)}
  .layer.c .lbl{color:var(--mint)} .layer.c .bar.after{background:var(--mint);color:var(--mint)}
  .layer.g .lbl{color:var(--amber)} .layer.g .bar.after{background:var(--amber);color:var(--amber)}

  .doors{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:36px}
  .door{background:transparent;border:1px solid var(--line);border-radius:14px;padding:26px;display:flex;flex-direction:column;transition:.18s;text-decoration:none}
  .door:hover{border-color:var(--line2)}
  .door .k{font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--faint)}
  .door.m .k,.door.c .k,.door.g .k{color:var(--faint)}
  .door h3{margin:11px 0 9px}
  .door p{color:var(--dim);font-size:calc((16px) * var(--ts));flex:1}
  .door .who{margin-top:16px;padding-top:14px;border-top:1px solid var(--line);font-size:calc((13.5px) * var(--ts));color:var(--dim2);font-family:var(--sans)}
  .door .go{margin-top:14px;font-size:calc((15.5px) * var(--ts));font-weight:600;color:var(--mint)}
  .door.m .go,.door.c .go,.door.g .go{color:var(--mint)}

  .card{background:transparent;border:1px solid var(--line);border-radius:14px;padding:24px}
  .card h3{margin-bottom:8px}
  .card p{color:var(--dim);font-size:calc((16px) * var(--ts))}
  /* The /security/ status cards: the supplied shield beside its status, used at a size where its
     own small print can be read. It stays a row on a phone, where the card is still ~300px. */
  .certcard{display:flex;align-items:center;gap:20px}
  .certcard img{flex:none;display:block;width:clamp(84px,22vw,108px);height:auto}
  .certcard h3{margin-bottom:6px}
  .cols2{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:34px}
  .cols3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:34px}
  .cols4{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:34px}
  .split{display:grid;grid-template-columns:1fr 1fr;gap:46px;align-items:start;margin-top:36px}
  
  .split>*,.cols2>*,.cols3>*,.cols4>*,.doors>*,.prices>*{min-width:0}

  
  
  table{width:100%;border-collapse:collapse;margin-top:26px;font-size:calc((16px) * var(--ts));
    background:transparent;border:none;border-top:1px solid var(--line2);
    margin-left:-10px;width:calc(100% + 20px)}
  
  th,td{text-align:left;padding:13px 26px 13px 10px;border-bottom:1px solid var(--line);
    vertical-align:top;color:var(--txt)}
  th:last-child,td:last-child{padding-right:10px}
  tr:last-child td{border-bottom:none}
  
  th{font-family:var(--sans);font-size:calc((11px) * var(--ts));letter-spacing:.11em;text-transform:uppercase;
    color:var(--dim);font-weight:600;border-bottom-color:var(--line2);background:transparent;
    line-height:1.5;padding-bottom:10px}
  
  td.n,td.nb,td.na{font-family:var(--mono);color:var(--mint)}
  
  td.b{font-family:var(--mono);color:var(--dim)}
  
  td.p{font-family:var(--sans);color:var(--txt)}
  td small{color:var(--dim2);font-size:calc((13.5px) * var(--ts));font-family:var(--sans)}
  tr.hl td{background:rgba(15,127,102,.06)}
  tr.hl td:first-child{border-radius:6px 0 0 6px}
  tr.hl td:last-child{border-radius:0 6px 6px 0}

  .code{font-family:var(--mono);font-size:calc((13.5px) * var(--ts));color:var(--dim);background:rgba(244,242,236,.55);border:1px solid var(--line);border-radius:10px;padding:14px 16px;overflow-x:auto;margin-top:20px}
  .code .c{color:var(--dim2)} .code .g{color:var(--mint)}

  
  .term{
    --t-bg:#0b1119; --t-card:#141D28; --t-line:#243040; --t-line2:#33445A;
    --t-txt:#E8EEF3; --t-dim:#8593A1; --t-mint:#5FCFB4;
    margin-top:20px;background:var(--t-bg);border:1px solid var(--t-line);border-radius:10px;overflow:hidden}
  .term-bar{display:flex;align-items:center;gap:9px;padding:8px 12px;background:var(--t-card);border-bottom:1px solid var(--t-line)}
  .term-dots{display:flex;gap:6px}
  .term-dots i{width:9px;height:9px;border-radius:50%;background:var(--t-line2)}
  .term-ttl{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.14em;text-transform:uppercase;color:var(--t-dim)}
  .term-body{padding:12px 12px 13px;font-family:var(--mono);font-size:calc((13.5px) * var(--ts));line-height:1.65;color:var(--t-txt);overflow-x:auto}
  .term-line{display:flex;align-items:flex-start;gap:9px;padding:3px 5px;margin:0 -5px;border-radius:6px}
  .term-line:hover{background:rgba(255,255,255,.045)}
  .term-p{flex:none;color:var(--t-mint);user-select:none}
  .term-line code{flex:1;min-width:0;font:inherit;color:var(--t-txt);white-space:pre-wrap;word-break:break-word}
  .term-cp{flex:none;opacity:0;transition:opacity .12s,color .12s,border-color .12s;cursor:pointer;
    background:transparent;border:1px solid var(--t-line2);border-radius:5px;padding:1px 7px;
    font-family:var(--mono);font-size:calc((10.5px) * var(--ts));letter-spacing:.1em;text-transform:uppercase;color:var(--t-dim)}
  .term-line:hover .term-cp{opacity:1}
  .term-cp:hover{color:var(--t-txt)}
  .term-cp:focus-visible{opacity:1;outline:2px solid var(--t-mint);outline-offset:2px}
  .term-cp.ok{opacity:1;color:var(--t-mint);border-color:var(--t-mint)}
  
  @media (hover:none){.term-cp{opacity:1}}
  html:not(.term-js) .term-cp{display:none}
  .term-out{padding:3px 5px;color:var(--t-mint)}
  .term-cur{display:flex;align-items:center;gap:9px;padding:3px 5px}
  .term-cur i{display:inline-block;width:7.5px;height:15px;background:var(--t-txt);animation:tblink 1.05s step-end infinite}
  @keyframes tblink{0%,49%{opacity:1}50%,100%{opacity:0}}
  :where(html[data-motion="reduced"],html[data-motion="off"]) .term-cur i{animation:none;opacity:.5}
  .caveat{margin-top:24px;background:rgba(251,247,233,.5);border:1px solid #E8DFC0;border-radius:12px;padding:19px 21px}
  .caveat .k{font-family:var(--mono);font-size:calc((13.5px) * var(--ts));font-weight:600;letter-spacing:.10em;text-transform:uppercase;color:var(--amber)}
  .caveat p{margin-top:8px;color:var(--dim);font-size:calc((16px) * var(--ts))}
  .caveat p + p{margin-top:11px}
  /* --card2, not the literal #F4F2EC it used to be: that is day's card surface, and with no dusk
     override this neutral variant kept a DAY paper on a dusk page while the amber .caveat beside
     it changed correctly. Legible either way -- 6.75 and 9.67 in dusk -- so this is a theming
     fix, not a contrast one. The night override below stays: its translucency is deliberate and
     more specific than this rule. */
  .caveat.n{background:var(--card2);border-color:var(--line)} .caveat.n .k{color:var(--dim2)}

  .lat{margin-top:28px}
  .latrow{display:grid;grid-template-columns:200px 1fr 92px;gap:14px;align-items:center;padding:8px 0}
  .latrow .nm{font-size:calc((14.5px) * var(--ts));color:var(--dim)}
  .latbar{height:20px;border-radius:4px;background:#E5E2DA}
  .latbar.us{background:var(--amber)}
  .latrow .v{font-family:var(--mono);font-size:calc((14px) * var(--ts));text-align:right;color:var(--dim)}
  .latrow.us .nm,.latrow.us .v{color:var(--amber);font-weight:600}

  .demo{background:transparent;border:1px solid var(--line);border-radius:14px;padding:20px}
  .demo-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:13px;border-bottom:1px solid var(--line)}
  .demo-head .t{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.13em;color:var(--dim2);text-transform:uppercase}
  .toggle{display:flex;align-items:center;gap:9px;cursor:pointer;user-select:none}
  .toggle .sw{width:40px;height:22px;border-radius:12px;background:#E5E2DA;position:relative;transition:.22s;flex:none}
  .toggle .sw::after{content:"";position:absolute;width:16px;height:16px;border-radius:50%;background:#7d8fa1;top:3px;left:3px;transition:.22s}
  .toggle.on .sw{background:rgba(138,90,15,.32)}
  .toggle.on .sw::after{left:21px;background:var(--amber)}
  .toggle span{font-size:calc((14px) * var(--ts));color:var(--dim)}
  .qrow{padding:12px 0;border-bottom:1px dashed var(--line)}
  .qrow:last-of-type{border-bottom:none}
  .q{font-size:calc((15.5px) * var(--ts))}
  .tile-tag{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.07em;color:var(--dim2);text-transform:uppercase;margin-top:4px;display:block}
  
  .qrow .a{margin-top:7px;font-size:calc((14px) * var(--ts));color:var(--dim);background:rgba(244,242,236,.6);border-left:2px solid var(--line2);padding:8px 11px;border-radius:0 7px 7px 0}
  .qrow .a.blocked{color:var(--amber);border-left-color:var(--amber);background:rgba(232,165,74,.07)}
  .logline{margin-top:13px;padding-top:12px;border-top:1px solid var(--line);font-family:var(--mono);font-size:calc((11.5px) * var(--ts));color:var(--dim2);min-height:50px}

  /* The live topic-lock panel on /governance/. Reuses .demo/.demo-head/.logline above; everything
     from here is the input half that replaced the scripted toggle. */
  .gd-pick{display:flex;align-items:center;gap:8px}
  .gd-pick span{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.13em;color:var(--dim2);text-transform:uppercase}
  .gd-pick select{font:inherit;font-size:calc((13.5px) * var(--ts));color:var(--txt);background:var(--card);border:1px solid var(--line2);border-radius:8px;padding:5px 9px;max-width:min(52vw,230px)}
  .gd-form{margin-top:15px}
  .gd-lab{display:block;font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.13em;color:var(--dim2);text-transform:uppercase;margin-bottom:7px}
  .gd-form textarea{width:100%;box-sizing:border-box;font:inherit;font-size:calc((15px) * var(--ts));line-height:1.5;color:var(--txt);background:var(--card);border:1px solid var(--line2);border-radius:10px;padding:10px 12px;resize:vertical;min-height:62px}
  .gd-form textarea:focus{outline:2px solid var(--mint-d);outline-offset:1px;border-color:transparent}
  .gd-actions{display:flex;align-items:center;gap:13px;margin-top:11px;flex-wrap:wrap}
  .gd-actions .btn{padding:8px 18px;font-size:calc((14px) * var(--ts))}
  .gd-actions .btn:disabled{opacity:.55;cursor:default}
  .gd-hint{font-size:calc((13px) * var(--ts));color:var(--dim2)}
  .gd-retry{font:inherit;font-size:calc((13px) * var(--ts));color:var(--txt);background:var(--card2);border:1px solid var(--line2);border-radius:999px;padding:4px 12px;cursor:pointer}
  .gd-retry:hover{border-color:var(--mint-d)}
  .gd-tries{margin-top:14px;padding-top:12px;border-top:1px dashed var(--line);display:flex;flex-wrap:wrap;gap:7px;align-items:baseline}
  .gd-tries .t{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.13em;color:var(--dim2);text-transform:uppercase;margin-right:2px}
  .gd-try{font:inherit;font-size:calc((13px) * var(--ts));text-align:left;color:var(--dim);background:var(--card2);border:1px solid var(--line);border-radius:999px;padding:5px 12px;cursor:pointer;transition:.16s}
  .gd-try:hover{color:var(--txt);border-color:var(--line2)}
  .gd-note{margin-top:10px;font-size:calc((13px) * var(--ts));line-height:1.55;color:var(--dim2)}
  .gd-out{margin-top:15px;min-height:1px}
  .gd-card{border:1px solid var(--line2);border-left-width:3px;border-radius:0 10px 10px 0;padding:12px 14px;background:var(--card2)}
  .gd-card.no{border-left-color:var(--amber);background:rgba(232,165,74,.07)}
  .gd-card.ok{border-left-color:var(--mint-d);background:rgba(122,178,150,.08)}
  .gd-card.err{border-left-color:var(--line2);font-size:calc((14px) * var(--ts));color:var(--dim)}
  .gd-v{font-size:calc((15.5px) * var(--ts));display:flex;flex-wrap:wrap;gap:6px;align-items:baseline}
  .gd-card.no .gd-v b{color:var(--amber)} .gd-card.ok .gd-v b{color:var(--mint-d)}
  .gd-sub{font-size:calc((13.5px) * var(--ts));color:var(--dim)}
  .gd-m{margin-top:9px;font-size:calc((14px) * var(--ts));display:flex;flex-wrap:wrap;gap:7px;align-items:baseline}
  .gd-k{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.1em;color:var(--dim2);text-transform:uppercase}
  .gd-why{margin-top:5px;font-size:calc((13.5px) * var(--ts));color:var(--dim)}
  .gd-meta{margin-top:10px;display:flex;flex-wrap:wrap;gap:14px;font-family:var(--mono);font-size:calc((11.5px) * var(--ts));color:var(--dim2)}
  @media(max-width:560px){
    .demo-head{flex-wrap:wrap}
    .gd-pick select{max-width:100%}
  }
  .logline div{margin-bottom:3px}
  .logline .amb{color:var(--amber)} .logline .grn{color:var(--mint-d)}

  .audit{background:transparent;border:1px solid var(--line);border-radius:14px;padding:21px;font-family:var(--mono);font-size:calc((13.5px) * var(--ts));margin-top:28px;overflow-x:auto}
  .audit .kv{display:grid;grid-template-columns:180px 1fr;gap:6px 18px}
  .audit .k{color:var(--dim2)} .audit .v{color:var(--txt)}
  .audit .v.amb{color:var(--amber)} .audit .v.grn{color:var(--mint)}

  .path{background:transparent;border:1px solid var(--line);border-radius:14px;padding:23px}
  .path .t{font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--faint)}
  .path .time{font-size:calc((24px) * var(--ts));font-weight:700;margin:11px 0 3px;letter-spacing:-.02em}
  .path ul{margin:13px 0 0;padding-left:17px;color:var(--dim);font-size:calc((14.5px) * var(--ts))}
  .path li{margin-bottom:4px}

  
  .terms{display:inline-flex;gap:2px;margin:26px 0 0;padding:3px;border-radius:999px;
    border:1px solid var(--line2)}
  .terms button{font-family:var(--sans);font-size:calc((14.5px) * var(--ts));color:var(--dim2);cursor:pointer;
    border:0;background:none;border-radius:999px;padding:7px 15px;
    transition:background .22s,color .22s}
  .terms button[aria-pressed="true"]{background:var(--hl);color:var(--on-hl)}
  .terms .tag{font-size:calc((11.5px) * var(--ts));color:var(--mint);margin-left:6px}
  .terms button[aria-pressed="true"] .tag{color:var(--on-hl);opacity:.7}
  [data-term="monthly"] .y-only{display:none}
  [data-term="yearly"]  .m-only{display:none}
  .tsave{font-family:var(--sans);font-size:calc((13.5px) * var(--ts));color:var(--mint);margin-top:2px}

  .prices{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:34px}
  /* Top padding clears the .badge pill straddling the border, so it scales with --ts;
     without that a reader on a large type size gets the pill over the plan name. */
  .pr{background:transparent;border:1px solid var(--line);border-radius:14px;padding:calc(22px * var(--ts)) 22px 22px;display:flex;flex-direction:column;position:relative}
  .pr.hi{border-color:var(--mint);box-shadow:inset 0 0 0 1px var(--mint);background:var(--tier-hi)}
  .pr .nm{font-weight:650;font-size:calc((16.5px) * var(--ts))}
  .pr .amt{font-size:calc((28px) * var(--ts));font-weight:700;margin:9px 0 2px;letter-spacing:-.03em}
  .pr .amt small{font-size:calc((15.5px) * var(--ts));color:var(--dim);font-weight:400}
  .pr .yr{font-size:calc((13.5px) * var(--ts));color:var(--dim2);font-family:var(--mono)}
  .pr ul{list-style:none;padding:0;margin:16px 0;font-size:calc((14.5px) * var(--ts));color:var(--dim);flex:1}
  .pr li{padding:5px 0;border-bottom:1px solid var(--line)}
  .pr li:last-child{border-bottom:none}
  .pr li b{color:var(--txt);font-weight:600}
  .badge{position:absolute;top:-10px;left:22px;right:22px;width:max-content;max-width:calc(100% - 44px);background:var(--mint);color:var(--on-mint);font-family:var(--sans);font-weight:600;font-size:calc((10.5px) * var(--ts));line-height:1.2;letter-spacing:.11em;padding:3px 9px;border-radius:20px;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .gate{margin-top:28px;background:transparent;border:1px solid var(--line);border-radius:12px;padding:19px 21px}
  .gate .k{font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.14em;text-transform:uppercase;color:var(--mint-d)}
  .gate p{margin-top:8px;color:var(--dim);font-size:calc((16px) * var(--ts))}

  /* Content disclosure styling is deliberately scoped. Unqualified details/summary rules also
     match the Products menu in the header and change both its geometry and arrow. */
  .topicdetails{border-bottom:1px solid var(--line);padding:15px 0}
  .topicdetails summary{cursor:pointer;font-weight:600;font-size:calc((16px) * var(--ts));list-style:none;display:flex;justify-content:space-between;gap:16px}
  .topicdetails summary::-webkit-details-marker{display:none}
  .topicdetails summary::after{content:"+";color:var(--mint-d);font-weight:400;font-size:calc((19.5px) * var(--ts));line-height:1}
  .topicdetails[open] summary::after{content:"–"}
  .topicdetails p{margin-top:10px;color:var(--dim);font-size:calc((16px) * var(--ts))}
  .topicdetails p + p{margin-top:11px}

  .final{text-align:center;padding:96px 0}
  .final .btns{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
  
  .final .btns-lead{margin:0 0 34px}
  .final .btns-trail{margin-top:28px}
  /* The footer is outside .wrap on these pages, so it carries the page's side padding and column
     width itself; without them its columns touched the viewport edges on a wide screen. */
  footer{border-top:1px solid var(--line);padding:34px 28px;color:var(--dim2);font-size:calc((14.5px) * var(--ts))}
  footer > *{max-width:1124px;margin-left:auto;margin-right:auto}
  .fgrid{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap}

  @media(max-width:980px){
    .hero-grid,.split,.cols2{grid-template-columns:1fr}
    .doors,.cols3{grid-template-columns:1fr}
    .cols4,.prices{grid-template-columns:1fr 1fr}
    .latrow{grid-template-columns:140px 1fr 78px}
    
    table{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
    
  }
  @media(max-width:560px){
    .cols4,.prices{grid-template-columns:1fr}
    .audit .kv{grid-template-columns:1fr}
    .wrap{padding:0 18px}
    
    .latrow{grid-template-columns:1fr 0 74px}
    .latrow .latbar{display:none}

    /* nowrap keeps button labels on one line, which is right until the label is longer than the
       screen: "Data processing addendum" is 327px in a 305px column at the largest text size.
       Let labels wrap here rather than push the page sideways. */
    .btn{white-space:normal;text-align:center}
  }

  
  /* The breadcrumb is retired from every page (2026-09-06) but its markup is left in place for
     now and hidden here, so the change is one rule to revert. Pulling the 23 <div class="crumb">
     lines is a later pass. display:none also drops it from the accessibility tree, which is the
     intent: a hidden crumb should not be announced either. */
  .crumb{display:none}
  .more{display:inline-flex;align-items:center;gap:7px;margin-top:24px;font-size:calc((16px) * var(--ts));
    font-weight:600;color:var(--mint);text-decoration:none}
  .more:hover{text-decoration:underline}
  .more.b{color:var(--p-models)} .more.a{color:var(--p-gov)} .more.d{color:var(--p-docs)}
  .topicdetails{margin-top:38px}
  .topicdetails summary{cursor:pointer;width:max-content;max-width:100%;padding:10px 16px;border:1px solid var(--line2);
    border-radius:999px;color:var(--txt);font-weight:650}
  .topicdetails[open] summary{margin-bottom:24px;background:var(--hl);color:var(--on-hl)}
  /* The hero is the CTA band, and it ends on a rule. Above the rule is the animated field on the page's own ground (`.hero canvas.flow`),
     below it the still field (backdrop.css) and the content. --line-deep and not --line: at 1.24:1 the old hairline did not read as an
     edge, and the two fields, one stopping and one starting at the same row, ran together as one. The band takes the rule, so the
     section after it drops the hairline every section otherwise opens with; the bottom padding keeps the plate off the rule. */
  .subhero{padding:54px 0 48px;border-top:none;border-bottom:1px solid var(--line-deep)}
  .subhero + section{border-top:none}
  .subhero h1{font-size:calc((clamp(30px,5vw,47.5px)) * var(--ts))}
  .subhero .lede{margin-top:16px;font-size:calc((19.5px) * var(--ts));line-height:1.52;letter-spacing:-.012em}

  
  .heroline{list-style:none;margin:14px 0 0;padding:0;color:var(--dim);font-size:calc((16.5px) * var(--ts))}
  .heroline li{position:relative;padding:5px 0 5px 18px}
  .heroline li::before{content:"";position:absolute;left:0;top:15px;width:7px;height:7px;
    border-radius:2px;background:var(--mint-d)}
  .heroline li b{color:var(--txt);font-weight:650}

  
  .fig{color:var(--txt);font-weight:650;white-space:nowrap;position:relative;
    display:inline-block;transition:color .22s ease,transform .22s ease}
  .fig::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1.5px;
    background:currentColor;transform:scaleX(0);transform-origin:left;
    transition:transform .3s cubic-bezier(.22,.61,.36,1);opacity:.5}
  .card:hover .fig,.door:hover .fig,tr:hover .fig,.head:hover .fig,.path:hover .fig{
    color:var(--mint);transform:translateY(-2px)}
  .card:hover .fig::after,.door:hover .fig::after,tr:hover .fig::after,
  .head:hover .fig::after,.path:hover .fig::after{transform:scaleX(1)}
  
  .fig:nth-of-type(2){transition-delay:.05s} .fig:nth-of-type(3){transition-delay:.1s}
  .fig:nth-of-type(2)::after{transition-delay:.05s} .fig:nth-of-type(3)::after{transition-delay:.1s}
  
  @media(hover:none){
    .fig{color:var(--mint)}
    .fig::after{transform:scaleX(1)}
  }
  :where(html[data-motion="reduced"],html[data-motion="off"]) .fig,:where(html[data-motion="reduced"],html[data-motion="off"]) .fig::after{transition:none}
  :where(html[data-motion="reduced"],html[data-motion="off"]) .card:hover .fig,:where(html[data-motion="reduced"],html[data-motion="off"]) .door:hover .fig,:where(html[data-motion="reduced"],html[data-motion="off"]) tr:hover .fig,:where(html[data-motion="reduced"],html[data-motion="off"]) .head:hover .fig,:where(html[data-motion="reduced"],html[data-motion="off"]) .path:hover .fig{transform:none}

  
  .key{color:var(--txt);font-weight:600;position:relative;
    transition:color .22s ease}
  .key::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1.5px;
    background:currentColor;transform:scaleX(0);transform-origin:left;
    transition:transform .3s cubic-bezier(.22,.61,.36,1);opacity:.5}
  
  section:hover .key,.card:hover .key,.door:hover .key,tr:hover .key,
  .head:hover .key,.path:hover .key,.step:hover .key{color:var(--mint)}
  section:hover .key::after,.card:hover .key::after,.door:hover .key::after,
  tr:hover .key::after,.head:hover .key::after,.path:hover .key::after,
  .step:hover .key::after{transform:scaleX(1)}
  
  @media(hover:none){
    .key{color:var(--mint)}
    .key::after{transform:scaleX(1)}
  }
  :where(html[data-motion="reduced"],html[data-motion="off"]) .key,:where(html[data-motion="reduced"],html[data-motion="off"]) .key::after{transition:none}

  

  
  @media(max-width:720px){
    table.stackable{display:block;border:none;background:none;overflow:visible}
    table.stackable thead{display:none}
    table.stackable tbody{display:block;min-width:0}
    table.stackable tr{display:block;background:transparent;border:1px solid var(--line);
      border-radius:12px;padding:12px 14px;margin-bottom:10px}
    /* flex-wrap is load-bearing, not cosmetic. The cell's value is a bare text node, so it is
       an ANONYMOUS flex item that no selector can reach to give it min-width:0, and a flex item
       will not shrink below its content without it. On the prose cells (td.p on /subprocessors/
       and /dpa/) that meant a 279px cell holding 383px of text and pushing the whole document
       sideways at every phone width. With wrap, long values drop to their own full-width line
       and wrap normally; short ones still sit beside the label as before. */
    table.stackable td{display:flex;flex-wrap:wrap;justify-content:space-between;gap:2px 14px;
      border:none;padding:3px 0;font-size:calc((16px) * var(--ts));overflow-wrap:anywhere}
    table.stackable td::before{content:attr(data-l);color:var(--dim2);font-family:var(--mono);
      font-size:calc((12.5px) * var(--ts));letter-spacing:.08em;text-transform:uppercase;flex:none}
    
    table.stackable td.cut{font-size:calc((19.5px) * var(--ts));font-weight:700;color:var(--mint);
      padding-top:8px;margin-top:6px;border-top:1px solid var(--line)}
  }

  
  .ctarow{display:flex;gap:12px;flex-wrap:wrap;align-items:center;justify-content:center;
    margin:52px 0 8px;padding-top:40px;border-top:1px solid var(--line);text-align:center}
  .ctarow .note-s{font-size:calc((14.5px) * var(--ts));color:var(--dim2);flex-basis:100%;margin-top:2px}

  
  /* minmax(0,1fr), not 1fr: a plain 1fr track is minmax(auto,1fr), and that auto minimum is
     min-content, so three columns of prose refused to go narrower than their longest line and
     pushed /governance/ 60px wider than a phone screen at every width. */
  .tally{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin-top:30px;
    border-top:1px solid var(--line2)}
  @media(max-width:640px){
    /* Three stat columns on a phone leave about 45px each. One per row instead. */
    .tally{grid-template-columns:1fr}
    .tally > div{padding:18px 0;border-right:0;border-bottom:1px solid var(--line)}
    .tally > div:first-child{padding-top:20px}
    .tally > div:last-child{border-bottom:0;padding-bottom:0}
  }
  .tally > div{padding:22px 28px 20px;border-right:1px solid var(--line)}
  .tally > div:first-child{padding-left:0}
  .tally > div:last-child{border-right:0;padding-right:0}
  .tally .t-n{font-family:var(--sans);font-weight:250;font-size:calc((40px) * var(--ts));line-height:1;
    letter-spacing:-.03em;color:var(--txt);transition:color .25s}
  .tally > div:hover .t-n{color:var(--mint)}
  .tally .t-k{font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;letter-spacing:.13em;
    text-transform:uppercase;color:var(--faint);margin-top:8px}
  .tally p{margin-top:9px;font-size:calc((15.5px) * var(--ts));color:var(--dim);line-height:1.5}

  .topicgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));
    gap:0 32px;margin-top:34px}
  .tdom{padding:18px 0 20px;border-top:1px solid var(--line)}
  .tdom .n{display:block;font-family:var(--sans);font-weight:250;font-size:calc((29px) * var(--ts));
    line-height:1;letter-spacing:-.03em;color:var(--txt);transition:color .25s}
  .tdom:hover .n{color:var(--mint)}
  .tdom h4{margin:6px 0 5px;font-size:calc((15.5px) * var(--ts));font-family:var(--sans);letter-spacing:-.01em;
    text-transform:none;color:var(--txt);font-weight:600}
  .tdom p{font-size:calc((14.5px) * var(--ts));color:var(--dim);line-height:1.5}

  
  .steps{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:24px;counter-reset:s}
  .step{background:transparent;border:1px solid var(--line);border-radius:14px;padding:20px}
  .step::before{counter-increment:s;content:counter(s);display:inline-flex;align-items:center;
    justify-content:center;width:26px;height:26px;border-radius:50%;background:var(--mint);
    color:#fff;font-weight:600;font-size:calc((14.5px) * var(--ts));margin-bottom:10px}
  .step h3{margin-bottom:6px}
  .step p{color:var(--dim);font-size:calc((15.5px) * var(--ts))}
  @media(max-width:820px){.steps{grid-template-columns:1fr}}

  
  .leadform label{display:block;font-size:calc((14.5px) * var(--ts));color:var(--dim);margin-bottom:14px}
  .leadform input,.leadform select,.leadform textarea{display:block;width:100%;margin-top:6px;
    background:rgba(255,255,255,.6);color:var(--txt);border:1px solid var(--line2);border-radius:10px;
    padding:11px 13px;font-size:calc((15.5px) * var(--ts));font-family:var(--sans)}
  .leadform input:focus,.leadform select:focus,.leadform textarea:focus{outline:none;
    border-color:var(--mint-d);box-shadow:0 0 0 3px rgba(15,127,102,.10)}
  .leadform textarea{resize:vertical}
  .leadform button{border:0;cursor:pointer;font-family:var(--sans)}
  .fgrid2{display:grid;grid-template-columns:1fr 1fr;gap:0 16px}
  @media(max-width:640px){.fgrid2{grid-template-columns:1fr}}

  
  .leadform label.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

  
  .prices.five{grid-template-columns:repeat(5,1fr);gap:12px}
  .prices.five .pr{padding:calc(18px * var(--ts)) 16px 18px}
  .prices.five .pr .amt{font-size:calc((24px) * var(--ts))}
  .prices.five .pr ul{font-size:calc((14px) * var(--ts))}
  @media(max-width:1240px){.prices.five{grid-template-columns:repeat(3,1fr)}}
  @media(max-width:900px){.prices.five{grid-template-columns:repeat(2,1fr)}}
  @media(max-width:560px){.prices.five{grid-template-columns:1fr}}

  
  th small{display:block;font-weight:400;font-size:calc((11px) * var(--ts));letter-spacing:.02em;color:var(--dim2);margin-top:2px;text-transform:none}

  
  
  .head h2,.card h3,.door h3,.path .t,.step h3,.tdom h4,.demo-head .t,
  section > .wrap > h3,section > .wrap > h4{
    display:inline-block;
    background-image:linear-gradient(var(--hl),var(--hl));
    background-size:0% 100%;background-repeat:no-repeat;background-position:left center;
    transition:background-size .28s cubic-bezier(.22,.61,.36,1);
    padding:2px 5px;margin-left:-5px;border-radius:5px;
  }
  
  .card:hover h3,.door:hover h3,.path:hover .t,.step:hover h3,.tdom:hover h4,
  .demo:hover .demo-head .t,section:hover .head h2,
  section:hover > .wrap > h3,section:hover > .wrap > h4{
    background-size:100% 100%;color:var(--on-hl)}

  
  :root[data-theme="dusk"] .note{background:#D8D3C6;border-bottom-color:#C2BCAC}
  :root[data-theme="dusk"] .code{background:rgba(216,211,198,.55)}
  :root[data-theme="dusk"] .qrow .a{background:rgba(216,211,198,.6)}
  :root[data-theme="dusk"] .caveat{background:rgba(238,228,203,.5);border-color:#D3BD96}
  /* The neutral variant needs its own dusk rule for the same reason it has a night one: the line
     above is `:root[data-theme] .caveat`, specificity 0,3,0, which outranks the plain `.caveat.n`
     at 0,2,0. Without this the neutral caveat renders AMBER on dusk -- the one theme where the
     two variants were indistinguishable -- and no amount of editing the base rule fixes it,
     because the base rule is not what wins. */
  :root[data-theme="dusk"] .caveat.n{background:var(--card2);border-color:var(--line)}
  :root[data-theme="dusk"] .leadform input,
  :root[data-theme="dusk"] .leadform select,
  :root[data-theme="dusk"] .leadform textarea{background:rgba(240,237,229,.6)}

  :root[data-theme="night"] .note{background:#141D28;border-bottom-color:#243040}
  :root[data-theme="night"] .code{background:rgba(20,29,40,.75)}
  :root[data-theme="night"] .qrow .a{background:rgba(27,39,52,.7)}
  :root[data-theme="night"] .caveat{background:rgba(51,39,15,.45);border-color:#5A4520}
  :root[data-theme="night"] .caveat.n{background:rgba(27,39,52,.6);border-color:#243040}
  :root[data-theme="night"] .leadform input,
  :root[data-theme="night"] .leadform select,
  :root[data-theme="night"] .leadform textarea{background:rgba(20,29,40,.8)}
  :root[data-theme="night"] .pending{color:#E3A049;background:rgba(227,160,73,.10);border-color:#5A4520}
  
  :root[data-theme="night"] th{background:transparent}
  :root[data-theme="night"] tr.hl td{background:rgba(95,207,180,.08)}
  

  
  .themeswitch{position:relative;display:inline-flex;align-items:center;flex:none;
    padding:3px;border-radius:999px;border:1px solid var(--line2);background:transparent}
  .themeswitch .thumb{position:absolute;top:3px;left:3px;width:32px;height:32px;
    border-radius:999px;background:var(--hl);z-index:0;
    transition:transform .42s cubic-bezier(.22,.61,.36,1), background .3s}
  :root[data-theme="dusk"]  .themeswitch .thumb{transform:translateX(32px)}
  :root[data-theme="night"] .themeswitch .thumb{transform:translateX(64px)}
/* The TYPE and MOTION switches wear the theme switch's pill, but their thumbs follow their own
   position rather than the paper's, hence a data attribute on each group instead of the one on
   <html>.

   The :root prefix is LOAD-BEARING, and the reason is the whole of this bug. The note here used
   to say these were "declared after, so the theme rules above cannot drag it along", and source
   order does not decide this: the theme rules score four class-level components
   (:root, [data-theme], .themeswitch, .thumb) against these three, so they won on specificity
   from anywhere in the file. Every one of these switches was pinned to the theme's own position
   in dusk and night (the text-size thumb sat under "Large" whatever was actually selected).

   And it did not read as a thumb in the wrong place, it read as a control with NO state: the
   selected button paints itself var(--on-hl), the ink meant to sit on the cream thumb, so with
   the thumb elsewhere the one glyph telling you what was selected turned near-black on a
   near-black panel and disappeared.

   :root here adds nothing but a fourth component, which ties the specificity and hands the
   decision back to source order (which is what the old note assumed it already had). */
:root .typeswitch[data-ts-step="0"] .thumb{transform:translateX(0)}
:root .typeswitch[data-ts-step="1"] .thumb{transform:translateX(32px)}
:root .typeswitch[data-ts-step="2"] .thumb{transform:translateX(64px)}
:root .motionswitch[data-mo-step="0"] .thumb{transform:translateX(0)}
:root .motionswitch[data-mo-step="1"] .thumb{transform:translateX(32px)}
:root .motionswitch[data-mo-step="2"] .thumb{transform:translateX(64px)}
  .themeswitch button{position:relative;z-index:1;width:32px;height:32px;padding:0;border:0;
    background:none;cursor:pointer;color:var(--faint);display:inline-flex;align-items:center;
    justify-content:center;transition:color .3s}
  .themeswitch button[aria-checked="true"]{color:var(--on-hl)}
  .themeswitch button:hover{color:var(--dim)}
  .themeswitch svg{display:block;overflow:visible}
  .ti-core{transition:transform .42s cubic-bezier(.22,.61,.36,1), r .42s ease}
  .ti-rays{transform-origin:12px 12px;
    transition:transform .5s cubic-bezier(.22,.61,.36,1), opacity .32s ease}
  .ti-shade{transition:transform .46s cubic-bezier(.22,.61,.36,1)}
  .themeswitch button[aria-checked="false"] .ti-rays{opacity:.55}
  .i-day .ti-rays{opacity:1;transform:rotate(-35deg) scale(.72)}
  .themeswitch button[aria-checked="true"] .i-day .ti-rays{transform:rotate(0deg) scale(1)}
  .i-dusk .ti-rays{transform:scale(.86)}
  .themeswitch button[aria-checked="true"] .i-dusk .ti-rays{transform:scale(1)}
  .i-night .ti-shade{transform:translate(2.6px,-2.6px)}
  .themeswitch button[aria-checked="true"] .i-night .ti-shade{transform:translate(0,0)}
  :where(html[data-motion="reduced"],html[data-motion="off"]) .themeswitch .thumb,:where(html[data-motion="reduced"],html[data-motion="off"]) .ti-core,:where(html[data-motion="reduced"],html[data-motion="off"]) .ti-rays,:where(html[data-motion="reduced"],html[data-motion="off"]) .ti-shade{transition:none}

:root.theme-sweep *,
:root.theme-sweep *::before,
:root.theme-sweep *::after{transition:none !important}

::view-transition-group(root){animation:none}
::view-transition-old(root){animation:none;mix-blend-mode:normal;z-index:1}
::view-transition-new(root){
  mix-blend-mode:normal;z-index:9999;
  animation:theme-sweep 640ms cubic-bezier(.22,.61,.36,1) both;
}
@keyframes theme-sweep{
  from{clip-path:circle(0 at var(--sweep-x) var(--sweep-y))}
  to{clip-path:circle(var(--sweep-r) at var(--sweep-x) var(--sweep-y))}
}

.theme-wave{
  position:fixed;border-radius:50%;z-index:9999;pointer-events:none;
  transform:translate(-50%,-50%) scale(0);will-change:transform;
}
:where(html[data-motion="reduced"],html[data-motion="off"]) .theme-wave{display:none}
/* THE NO-JS NET. Every reduced-motion rule in this file is keyed on data-motion, which the
   inline snippet in each page's <head> writes from the reader's setting, the OS preference and
   this session's cost measurement together (see motion.js). With scripts off, none of that runs
   and the attribute is never written, so the OS preference is honoured directly here, for the
   only case that can reach it.

   Blunt on purpose. It is a reset rather than the hand-tuned end states above because without
   scripts there is nothing to hand-tune AROUND: the choreography that needs an end state is
   gated on html.tw-motion, which only cta-motion.js ever adds, so nothing can be caught
   half-way through a transition here. What is left to stop is decoration that loops. */
@media (prefers-reduced-motion:reduce){
  html:not([data-motion]) *,
  html:not([data-motion]) *::before,
  html:not([data-motion]) *::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  /* The hero plate's ring is the one thing on these pages the blunt reset above cannot finish on
     its own: freezing it leaves a stationary coloured rim that is HEAVIER than the resting edge
     it covers, so a reader asking for less would get a more insistent card. Removing it hands
     back the --line-deep edge, which is the same state the data-motion kill produces. */
  html:not([data-motion])[data-pillar] .hero .plate::before{ display:none }
}


.bkoverlay{
  position:fixed;inset:0;z-index:10000;display:none;
  align-items:center;justify-content:center;
  background:rgba(10,12,10,.6);padding:24px;
}
.bkoverlay.open{display:flex}
.bkpanel{
  
  position:relative;width:100%;max-width:760px;height:min(680px,90vh);
  background:#fff;border:1px solid #E5E2DA;border-radius:16px;
  box-shadow:0 24px 64px rgba(0,0,0,.35);overflow:hidden;
}
.bkpanel iframe{width:100%;height:100%;border:0;display:block}
.bkclose{
  position:absolute;top:10px;right:10px;z-index:1;
  width:34px;height:34px;border-radius:50%;
  background:#F4F2EC;border:1px solid #E5E2DA;color:#191917;
  font-size:calc((19.5px) * var(--ts));line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
.bkclose:hover{background:#E5E2DA}
@media(max-width:640px){
  .bkoverlay{padding:0}
  .bkpanel{max-width:none;height:100vh;border-radius:0}
}

/* ---- Eval use-case panel (/evals/) ---------------------------------------
   Evals are shown as use cases a reader can filter to, not as a paper. The set
   is meant to grow, so a card carries its own tags and nothing here counts or
   orders them: adding an <article> with data-tags is the whole edit.

   The pair is one unit. A before and an after only mean something together, so
   they sit on one line with the arrow between them rather than as two tiles a
   reader has to associate by eye. Everything else about the run goes in the
   rows beneath, which is where a number that is not the headline belongs. */
/* .itabs rides the same pills as .efilter. They look identical on purpose, but they are not the
   same control: a filter narrows a set and a tab swaps one panel for another, so the tabs carry
   role="tab" and aria-selected while the filters stay a plain pressed-button group. */
.efilter,.itabs{display:flex;flex-wrap:wrap;gap:8px;margin-top:24px}
.efilter button,.itabs button{
  font-family:var(--sans);font-size:calc((13.5px) * var(--ts));color:var(--dim2);cursor:pointer;
  border:1px solid var(--line2);background:none;border-radius:999px;padding:7px 15px;
  transition:background .22s,color .22s,border-color .22s;
}
.itabs button[aria-selected="true"]{background:var(--hl);color:var(--on-hl);border-color:transparent}

/* The filter row is also the legend. Each button wears the same swatch, in the same shape and
   colour, as the chip it selects -- so the mapping is learned once at the top of the page and
   then read off the cards without coming back. "All" has no tag and so has no swatch.

   Scoped to .efilter[data-tag] so .itabs, which shares the pill above, is untouched: a tab is
   not a tag and has nothing to put in a swatch.

   Pressed goes to the tag's own tint rather than --hl. --hl is one amber for everything, which
   here would mean the act of choosing a tag hid which tag was chosen; and against a fixed amber
   the tag swatches do not all hold 3:1. On its own tint each one does, by construction. */
.efilter button{display:inline-flex;align-items:center}
/* The swatch is declared for every tagged button and then withdrawn from All, rather than
   excluded with :not([data-tag="all"]) here. The :not() reads better but it adds an attribute
   selector to this rule, which out-specifies the single-attribute per-tag rules below -- so the
   base border-radius:50% beat every shape override and every button kept the circle. */
.efilter button[data-tag]::before{
  content:"";display:inline-block;vertical-align:-1px;flex:none;
  width:9px;height:9px;margin-right:8px;border-radius:50%;background:var(--tag,var(--dim2));
}
/* The bar is three kinds of tag, not one list: what the run exercised, the public benchmark it
   was run on, and what came out of it. Flat, an eleven-chip row read as one undifferentiated
   pile and gave a reader no way to see that LOCOMO and MMLU are the same KIND of thing while
   Governance and Token cost are not. One labelled row per kind. The colours already said this
   (a benchmark takes its capability's hue, a measurement is outline-only); the rows say it in
   words so it does not depend on noticing the fill. */
.efilter{flex-direction:column;align-items:stretch;gap:8px}
.frow{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.frow-k{
  font-family:var(--sans);font-size:calc((10.5px) * var(--ts));font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--dim2);
  flex:none;min-width:88px;
}
/* "All" clears every row at once, so it sits above the groups rather than inside one. */
.frow-all{padding-bottom:2px}
@media(max-width:560px){
  .frow{gap:6px}
  .frow-k{min-width:100%;margin-bottom:-2px}
}
.efilter button[data-tag="all"]::before{content:none}
.efilter button[data-tag="agents"]{--tag:var(--tag-agents)}
.efilter button[data-tag="memory"]{--tag:var(--tag-memory)}
/* A named benchmark takes the colour of the capability it tested, so LOCOMO and LongMemEval
   read as conversation memory and AgentBench as agent workflows. The hexagon below is what
   says "this is a benchmark" rather than a capability, and it generalises to the next one. */
.efilter button[data-tag="locomo"]{--tag:var(--tag-memory)}
.efilter button[data-tag="longmemeval"]{--tag:var(--tag-memory)}
.efilter button[data-tag="agentbench"]{--tag:var(--tag-agents)}
.efilter button[data-tag="mmlu"]{--tag:var(--tag-compression)}
.efilter button[data-tag="compression"]{--tag:var(--tag-compression)}
.efilter button[data-tag="cost"]{--tag:var(--tag-cost)}
.efilter button[data-tag="quality"]{--tag:var(--tag-quality)}
.efilter button[data-tag="governance"]{--tag:var(--tag-governance)}
.efilter button[data-tag="compression"]::before{border-radius:2px}
.efilter button[data-tag="agents"]::before{border-radius:1px;transform:rotate(45deg)}
.efilter button[data-tag="locomo"]::before,
.efilter button[data-tag="longmemeval"]::before,
.efilter button[data-tag="agentbench"]::before,
.efilter button[data-tag="mmlu"]::before{border-radius:0;transform:none;clip-path:polygon(25% 0,75% 0,100% 50%,75% 100%,25% 100%,0 50%)}
.efilter button[data-tag="cost"]::before{height:5px;width:11px;border-radius:1px}
.efilter button[data-tag="quality"]::before{border-radius:0;clip-path:polygon(50% 0,100% 100%,0 100%)}
/* Governance is a workload tag (what was run), so it joins the tinted-fill family below; a pentagon keeps it apart from the four shapes already taken. */
.efilter button[data-tag="governance"]::before{border-radius:0;clip-path:polygon(50% 0,100% 38%,82% 100%,18% 100%,0 38%)}

.efilter button[data-tag="all"][aria-pressed="true"]{background:var(--hl);color:var(--on-hl);border-color:transparent}
.efilter button[data-tag]:not([data-tag="all"])[aria-pressed="true"]{
  background:color-mix(in srgb,var(--tag) 16%,transparent);
  border-color:color-mix(in srgb,var(--tag) 55%,transparent);
  color:var(--txt);
}
.efilter button:focus-visible,.itabs button:focus-visible{outline:2px solid var(--mint);outline-offset:2px}
.ipanel[hidden]{display:none}
.ipanel{margin-top:20px}

.evalgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px;margin-top:22px}
/* One column before the cards get narrow enough to break the pair onto two lines. */
@media(max-width:860px){ .evalgrid{grid-template-columns:1fr} }
.evalcard{border:1px solid var(--line);border-radius:14px;padding:24px;display:flex;flex-direction:column;scroll-margin-top:82px}
.evalcard[hidden]{display:none}

/* ---- eval tags ------------------------------------------------------------------------
   Ten identical grey chips across four cards told a reader nothing until they had read all
   ten. They are the page's index, so they now carry which tag they are.

   THREE channels, deliberately, because no one of them is enough on its own:

   1. FAMILY -> chip shape. Workload, category, and named-benchmark tags say what was run;
      token cost and quality say what was counted. The former get a tinted fill, the measurement
      two an open outline, so the row splits into what-this-is and what-we-measured before a
      single word is read.

   2. TAG -> swatch colour. An 8px mark in the tag's own hue. It is a fill, not text, which
      is the whole reason the palette works -- see the --tag-* block for why the text tokens
      could not do this job.

   3. TAG -> swatch shape. The run and topic tags use circles and polygons; the measurement
      tags use a bar and a triangle. All three papers do clear the CVD target, so this is not there
      to rescue a failing palette -- it is there so the chip does not depend on one having
      been achieved, and so the row still reads in greyscale, in print and in forced colours.

   The label stays --dim in every chip. Text wears ink, the swatch beside it carries the
   identity -- the same split the diverging chart on /models/ already makes. */
.etags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:13px}
.etag{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono);font-size:calc((10.5px) * var(--ts));letter-spacing:.07em;
  text-transform:uppercase;color:var(--dim);border:1px solid transparent;
  border-radius:999px;padding:3px 9px 3px 8px;
}
/* The swatch. --tag is set per tag below, so everything from here down is written once. */
.etag::before{
  content:"";flex:none;width:8px;height:8px;border-radius:50%;
  background:var(--tag,var(--dim2));
}
/* Workload: tinted fill, no rule. 10% of the swatch hue over the card is enough to group these
   tags at a glance, while --dim stays well clear of 4.5:1 on top of it. */
.etag[data-tag="agents"],.etag[data-tag="memory"],.etag[data-tag="locomo"],
.etag[data-tag="longmemeval"],.etag[data-tag="agentbench"],.etag[data-tag="mmlu"],
.etag[data-tag="compression"],.etag[data-tag="governance"]{
  background:color-mix(in srgb,var(--tag) 10%,transparent);
}
/* Measurement: outline, no fill. The absence of the wash is the family cue. */
.etag[data-tag="cost"],.etag[data-tag="quality"]{
  border-color:color-mix(in srgb,var(--tag) 45%,transparent);
}
.etag[data-tag="agents"]{--tag:var(--tag-agents)}
.etag[data-tag="memory"]{--tag:var(--tag-memory)}
.etag[data-tag="locomo"]{--tag:var(--tag-memory)}
.etag[data-tag="longmemeval"]{--tag:var(--tag-memory)}
.etag[data-tag="agentbench"]{--tag:var(--tag-agents)}
.etag[data-tag="mmlu"]{--tag:var(--tag-compression)}
.etag[data-tag="compression"]{--tag:var(--tag-compression)}
.etag[data-tag="cost"]{--tag:var(--tag-cost)}
.etag[data-tag="quality"]{--tag:var(--tag-quality)}
.etag[data-tag="governance"]{--tag:var(--tag-governance)}
/* Swatch shapes. Geometry rather than a glyph, so nothing depends on a font shipping the
   character and the mark is the tag colour rather than text in it. */
.etag[data-tag="compression"]::before{border-radius:2px}
.etag[data-tag="agents"]::before{border-radius:1px;transform:rotate(45deg)}
.etag[data-tag="locomo"]::before,
.etag[data-tag="longmemeval"]::before,
.etag[data-tag="agentbench"]::before,
.etag[data-tag="mmlu"]::before{border-radius:0;transform:none;clip-path:polygon(25% 0,75% 0,100% 50%,75% 100%,25% 100%,0 50%)}
.etag[data-tag="governance"]::before{border-radius:0;clip-path:polygon(50% 0,100% 38%,82% 100%,18% 100%,0 38%)}
.etag[data-tag="cost"]::before{height:4px;width:10px;border-radius:1px}
.etag[data-tag="quality"]::before{border-radius:0;clip-path:polygon(50% 0,100% 100%,0 100%)}
/* Set by evals.js on the chip that matched the active filter. Deeper wash and a rule, on both
   families, so an outline chip can be marked without being turned into a filled one. */
.etag.on{
  background:color-mix(in srgb,var(--tag) 22%,transparent);
  border-color:color-mix(in srgb,var(--tag) 60%,transparent);
  color:var(--txt);
}
.evalcard h3{
  margin:0;font-family:var(--sans);font-size:calc((19px) * var(--ts));font-weight:600;
  letter-spacing:-.01em;color:var(--txt);line-height:1.3;
}

.epair{display:flex;align-items:baseline;gap:11px;flex-wrap:wrap;margin-top:18px}
.epair .from{
  font-family:var(--sans);font-weight:250;font-size:calc((25px) * var(--ts));
  letter-spacing:-.02em;color:var(--dim2);
}
.epair .arrow{color:var(--faint);font-size:calc((17px) * var(--ts))}
.epair .to{
  font-family:var(--sans);font-weight:250;font-size:calc((40px) * var(--ts));line-height:1;
  letter-spacing:-.03em;color:var(--txt);transition:color .25s;
}
.evalcard:hover .epair .to{color:var(--mint)}
.epair-k{
  font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;letter-spacing:.13em;
  text-transform:uppercase;color:var(--faint);margin-top:9px;
}

.erows{margin-top:18px;border-top:1px solid var(--line)}
.erows > div{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;padding:9px 0;
  border-bottom:1px solid var(--line);font-size:calc((14.5px) * var(--ts));
}
.erows > div:last-child{border-bottom:0}
.erows .k{color:var(--dim);min-width:0}
.erows .v{font-family:var(--mono);color:var(--txt);white-space:nowrap}
.erows .v.win{color:var(--mint)}

.emethod{
  margin:16px 0 0;padding-top:14px;border-top:1px solid var(--line);
  font-size:calc((13.5px) * var(--ts));color:var(--dim2);line-height:1.55;
}
.enone{margin-top:22px;font-size:calc((15.5px) * var(--ts));color:var(--dim2)}

/* Metric chip plus the two labelled panels beneath it. The chip names what is being counted,
   the panels name each side of the comparison, so a number is never floating without its label.
   Deliberately not shaped like .etag above it: that row is a filter control and this is a
   caption, and a reader should not try to click this one.

   No background fill on the winning panel. tr.hl gets one, but it needs a per-theme override to
   stay legible in night, and a mint border carries the same emphasis without that. */
.emetric{
  display:inline-block;margin-top:17px;
  font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--mint);border:1px solid var(--mint);
  border-radius:6px;padding:4px 9px;
}
.epanels{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:11px}
/* Side by side is the whole point, so these stay two-up even on a phone: the numbers are short
   and stacking them turns a comparison into a list. */
.epanel{border:1px solid var(--line);border-radius:11px;padding:13px 14px;min-width:0}
.epanel.win{border-color:var(--mint)}
.epanel-k{
  font-family:var(--sans);font-size:calc((11.5px) * var(--ts));font-weight:600;letter-spacing:.03em;
  color:var(--dim2);
}
.epanel.win .epanel-k{color:var(--mint)}
.epanel-n{
  font-family:var(--sans);font-weight:250;font-size:calc((29px) * var(--ts));line-height:1.1;
  letter-spacing:-.03em;color:var(--txt);margin-top:5px;
}
.esave{margin-top:13px;font-size:calc((14.5px) * var(--ts));color:var(--dim2);line-height:1.55}
.esave b{color:var(--mint);font-weight:600}

/* ---- Benchmark cards: bars, stat rows, cost -------------------------------
   The bar is the point. Two numbers in a table make a reader do the division;
   two bars drawn to the same scale make the gap the first thing they see. Width
   is set inline per row because it IS the datum, not decoration: it is
   with/without as a percentage, computed once and written into the markup
   rather than derived in script, so the page says the same thing with JS off.

   Cost figures carry data-tokens and data-rate. The billing side's drift check
   redoes that arithmetic against the rate the catalog publishes, so a stale or
   invented figure fails rather than sitting there looking plausible. Never
   hand-write a dollar amount here without those attributes. */
.bstats{display:flex;flex-wrap:wrap;gap:26px 40px;margin-top:18px}
.bstat-n{
  font-family:var(--sans);font-weight:250;font-size:calc((34px) * var(--ts));line-height:1;
  letter-spacing:-.03em;color:var(--mint);
}
.bstat-k{
  font-family:var(--sans);font-size:calc((10.5px) * var(--ts));font-weight:600;letter-spacing:.13em;
  text-transform:uppercase;color:var(--faint);margin-top:7px;
}
.bstat.plain .bstat-n{color:var(--txt)}

/* The aggregate above the grid. Hidden while a filter is on, because a total
   across everything is a lie once the reader is looking at a subset. */
.bsummary{border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:20px 0;margin-top:22px}
.bsummary[hidden]{display:none}

.bsub{font-family:var(--sans);font-size:calc((14.5px) * var(--ts));color:var(--dim2);font-weight:400}
.bflow{
  font-family:var(--mono);font-size:calc((12.5px) * var(--ts));color:var(--dim2);
  margin-top:7px;line-height:1.7;word-break:break-word;
}

.brows{margin-top:17px}
.brow + .brow{margin-top:13px}
.brow-t{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  font-size:calc((14px) * var(--ts))}
.brow-k{color:var(--dim)}
.brow-v{font-family:var(--mono);color:var(--txt);white-space:nowrap}
.bbar{height:7px;border-radius:4px;background:var(--card2);margin-top:6px;overflow:hidden}
.bbar > i{display:block;height:100%;border-radius:4px;background:var(--line2)}
.brow.win .bbar > i{background:var(--mint)}
.brow.win .brow-v{color:var(--mint)}

.bfoot{
  margin:15px 0 0;padding-top:13px;border-top:1px solid var(--line);
  font-size:calc((13px) * var(--ts));color:var(--dim2);line-height:1.55;
}
/* The footnote under each eval card is retired from view (2026-09-06) but left in the markup
   and hidden here, the same treatment as .crumb: one rule to revert, and pulling the five
   <p class="bfoot"> blocks is a later pass. The provenance those paragraphs carried is still on
   /research/ and in the claims audit. */
.bfoot{display:none}
/* The bullet notes under the last two eval cards go the same way (2026-09-06). The recall card's
   four required provenance elements (our own run, self-judged, the benchmark, the sample size)
   moved into its subtitle so the rule still holds with the bullets hidden. Scoped to the
   eval cards: .blim is also the tile list on the use-case sub-pages, which stays. */
.evalcard .blim{display:none}
/* Each card ends on the link to its write-up, pinned to the bottom so the five line up. */
.evalcard .more{margin-top:auto;padding-top:16px;font-size:calc((15px) * var(--ts))}
@media(max-width:520px){ .bstats{gap:18px 26px} .bstat-n{font-size:calc((28px) * var(--ts))} }
/* Count badge inside a filter button. Sits on the button's own colour so it inverts with it. */
.ecount{
  display:inline-block;min-width:1.35em;padding:0 .35em;margin-left:.15em;border-radius:999px;
  font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:600;text-align:center;
  background:var(--card2);color:var(--dim2);
}
/* The badge sits on whatever the button is currently painted, which is now five different
   tints rather than one amber, so it can no longer be a fixed black wash -- on night that was
   a dark patch on a dark button. Mixing INTO currentColor tracks the label in every theme. */
.efilter button[aria-pressed="true"] .ecount{
  background:color-mix(in srgb,currentColor 15%,transparent);color:inherit;
}

/* Per-category comparison: four numbers across four fields is a table, not a sentence. */
.bcat{width:100%;border-collapse:collapse;margin-top:16px;
  font-size:calc((12.5px) * var(--ts));font-family:var(--mono)}
.bcat th,.bcat td{padding:6px 8px;text-align:right;border-bottom:1px solid var(--line)}
.bcat th:first-child,.bcat td:first-child{text-align:left;font-family:var(--sans);color:var(--dim)}
.bcat thead th{color:var(--dim2);font-family:var(--sans);font-weight:500;
  font-size:calc((11.5px) * var(--ts))}
.bcat td{color:var(--dim2)}
.bcat .us{color:var(--mint)}
.bcat tr.won .us{font-weight:700}
.blim{margin-top:14px;padding-left:0;list-style:none;
  font-size:calc((12.5px) * var(--ts));line-height:1.55;color:var(--dim2)}
.blim li{position:relative;padding-left:15px;margin-top:5px}
.blim li::before{content:"";position:absolute;left:0;top:.62em;width:5px;height:1px;
  background:var(--line2)}


/* Research post byline: author, publication date and topic tags, under the h1.
 * Lives in app.css rather than research.css because research.css belongs to the INDEX
 * only, and public/research/README.md requires a write-up to render correctly for a
 * reader who arrives on a direct link with no index stylesheet loaded.
 * Uses the existing tokens so it themes with everything else. */
.byline{
  display:flex; flex-wrap:wrap; align-items:center; gap:9px 16px;
  margin-top:20px; color:var(--dim2);
  font-size:calc((13.5px) * var(--ts));
}
.byline .who{ color:var(--txt); font-weight:600 }
.byline .sep{ opacity:.45 }
.research-tags{ margin:14px 0 0 }
.byline .research-tags{ margin:0 }


/* Consecutive body paragraphs. `p{margin:0}` above is deliberate for cards and
 * table cells, but inside an article it makes paragraphs collide, which the research
 * write-ups were working around with hand-placed <br/>. .lede keeps its own larger
 * margin by specificity, so a standfirst still reads as a standfirst. */
main p + p{ margin-top:14px }


/* The bring-your-own-workload ask on a research write-up.
 *
 * It is the one thing on the page we want a reader to act on, and it sits at the foot of a
 * long piece, so it needs to catch the eye at the moment they arrive rather than while they
 * are still at the top. A scroll-triggered play would be the richer answer, but the research
 * posts load neither motion.css nor cta-motion.js, so it would cost a new script on three
 * pages to animate one box. A slow continuous ring does the same job with nothing added.
 *
 * The ring is the tw-newcard gesture from motion.css, slowed and looped: same colour, same
 * "look at this card" reading, so it is not a new idea for the reader to learn. Hovering
 * pauses it, on the principle that a reader who has found it does not need to be waved at.
 *
 * Gated twice on purpose. `data-motion` is the reader's own setting and is authoritative;
 * the media query catches the OS preference for anyone who has not chosen here. At either,
 * the border alone carries the emphasis and nothing moves. */
@keyframes tw-byo{
  0%,100% { box-shadow:0 0 0 0  color-mix(in srgb, var(--mint) 0%,  transparent) }
  50%     { box-shadow:0 0 0 5px color-mix(in srgb, var(--mint) 15%, transparent) }
}
.caveat.byo{
  border-color:color-mix(in srgb, var(--mint) 42%, var(--line));
  animation:tw-byo 4.5s cubic-bezier(.4,0,.6,1) infinite;
}
.caveat.byo .k{ color:var(--mint) }
.caveat.byo:hover{ animation-play-state:paused; border-color:var(--mint) }
:where(html[data-motion="reduced"],html[data-motion="off"]) .caveat.byo{ animation:none }
@media (prefers-reduced-motion:reduce){
  html:not([data-motion="full"]) .caveat.byo{ animation:none }
}

/* ---- site footer -----------------------------------------------------------------------
   The same markup is used site-wide. On wide screens the product and resource lists flank the
   mark; on phones the mark becomes a compact header and the lists stay side by side. Keeping
   those lists in two columns avoids the long, mostly empty vertical footer the old stacked
   mobile layout created. */
.foot{border-top:0}
.footgrid{
  display:grid;
  grid-template-columns:minmax(0,1fr) clamp(150px,18vw,210px) minmax(0,1fr);
  grid-template-areas:"product mark more";
  align-items:stretch;gap:clamp(28px,5vw,72px);
  padding:clamp(28px,4vw,48px);
  border:1px solid var(--line);border-radius:22px;
  background:color-mix(in srgb,var(--mint) 3%,var(--bg));
}
.footcol{display:flex;flex-direction:column;gap:0;min-width:0}
.footcol:first-child{grid-area:product}
.footcol:last-child{grid-area:more}
.footcol-h{
  margin:0 0 12px;
  font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:700;
  letter-spacing:.15em;text-transform:uppercase;color:var(--dim2);
}
.footcol > a{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:42px;padding:8px 0;border-bottom:1px solid var(--line);
  font-size:calc((15px) * var(--ts));color:inherit;
  transition:color .18s ease,padding-left .18s ease;
}
.footcol > a::after{
  content:"\2192";flex:none;color:var(--mint);opacity:0;transform:translateX(-5px);
  transition:opacity .18s ease,transform .18s ease;
}
.footcol > a:hover{color:var(--mint);padding-left:4px;text-decoration:none}
.footcol > a:hover::after,.footcol > a[aria-current="page"]::after{
  opacity:1;transform:translateX(0)
}
.footcol > a[aria-current="page"]{color:var(--mint);font-weight:650}
.footcol > a:focus-visible{outline:2px solid var(--mint);outline-offset:4px;border-radius:2px}
.footmid{
  grid-area:mark;display:grid;place-items:center;min-height:100%;padding:24px;
  border:1px solid var(--line);border-radius:18px;background:var(--bg);opacity:1;
}
.footmid svg{display:block;width:90px;max-width:100%;height:auto;opacity:.78}
.footlegal{
  display:flex;gap:10px 28px;flex-wrap:wrap;justify-content:space-between;text-align:left;
  margin-top:20px;padding-top:18px;border-top:1px solid var(--line);
}
.footlegal a,.foot-credit a{padding:0;border-radius:2px;font-size:inherit}
/* The company line is the last row of the footer's own text: the links come first at every width and it sits under them on a
   line of its own. The flex basis takes the whole row, so it wraps even where it would fit beside the links; on a phone the row
   is a grid and this does nothing. */
.footlegal > :last-child{flex:0 0 100%}

/* ---- startup-programme row -------------------------------------------------------------
   Sits between the legal row and the glyph credit, in both stylesheets, because the footer
   markup is shared and these two files are separate copies of its layout.

   Modelled on the badge-and-name rows other startups use: a programme that issues a badge is
   shown as its badge, one that does not is shown as its name, and the two sit on one baseline.
   That mix is why the marks are plain text rather than the pills this row started as -- a pill
   beside a supplied badge image reads as two different kinds of thing. Heights are normalised
   on the image, never the box, so a badge with its own frame keeps its own proportions.

   `.footprog > a` -- see the note on .footcol > a: home.css paints every footer link through
   `.foot a` at (0,1,1), which outranks a bare class, and the night theme is where that shows.
   The marks live one level deeper here, so the selector carries .footprog-row. */
/* The bottom margin is the gap the removed attribution paragraph used to provide; without
   it the glyph credit sits 10px under the marks and reads as part of this block. */
/* auto, not 0, on the sides: `footer > *` centres every footer band in a 1124px measure, and a
   margin shorthand that names the sides overrides it. This row used to say 0 and sat at the left
   edge of the viewport on a wide screen while the legal line above it and the credit below it sat
   centred. */
.footprog{margin:18px auto 16px}
.footprog-k,.footcert-k{
  margin:0 0 10px;
  font-family:var(--sans);font-size:calc((11px) * var(--ts));font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--faint);
}
.footprog-row{display:flex;flex-wrap:wrap;align-items:center;gap:10px clamp(20px,3vw,34px)}
.footprog-row > a{
  display:inline-flex;align-items:center;padding:0;border-radius:3px;
  font-size:calc((13px) * var(--ts));font-weight:650;color:var(--dim2);
  background-image:none;transition:color .18s ease;
}
.footprog-row > a:hover{color:var(--mint);text-decoration:none;background-size:0 0}
.footprog-row > a:focus-visible{outline:2px solid var(--mint);outline-offset:4px}
/* The badge is the supplied artwork and is never recoloured, tinted, cropped or given a border
   of ours -- whatever frame is in the file is part of the mark. What IS ours is the plate under
   it. Both files we were given are light-ground (NVIDIA's inside its own black frame, AWS's on
   bare white), so without a plate the night theme gets two white rectangles bleeding onto near
   black paper with hard edges. The plate makes that a deliberate card instead, and on the two
   light papers it is nearly invisible against them. No border on the plate: NVIDIA's badge
   already carries one and a second would read as a double frame. */
.footprog-row > a.has-badge{
  padding:6px 8px;border-radius:7px;background:#fff;
  transition:box-shadow .18s ease,transform .18s ease;
}
.footprog-row > a.has-badge:hover{box-shadow:0 1px 8px rgb(0 0 0 / .16);transform:translateY(-1px)}
.prog-img{display:block;width:auto;height:36px;max-width:210px;object-fit:contain}
.prog-img-dark{display:none}

/* The badge pair, if a programme supplies one. A single-image badge stays as it is in all three
   themes, which is correct for artwork that carries its own white frame. */
:root[data-theme="night"] .prog-img-light{display:none}
:root[data-theme="night"] .prog-img-dark{display:block}

/* ---- certification row -----------------------------------------------------------------
   Above the programme row, in both stylesheets for the same reason. The two marks are shields
   drawn on their own white ground, so unlike the programme badges they take no plate from us;
   on night's paper they read as two white cards, which is what a badge is. Sized by height so
   the pair shares a line whatever the file's ratio, and tall enough that the shield's own title
   (SOC 2, ISO 27001) can be read. Its "in progress" label cannot, at this size, so the status is
   also said in words beside them. The anchors carry .footcert-row like .footprog-row does, for
   the same specificity reason. */
.footcert{margin:18px auto 0}
.footcert-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px clamp(16px,2.4vw,26px)}
.footcert-row > a.cert-m{
  display:block;padding:0;border-radius:6px;line-height:0;background-image:none;
  transition:transform .18s ease;
}
.footcert-row > a.cert-m:hover{transform:translateY(-2px)}
.footcert-row > a.cert-m:focus-visible{outline:2px solid var(--mint);outline-offset:4px}
.footcert .cert-img{display:block;width:auto;height:88px}
.footcert-t{margin:0;max-width:30ch;font-size:calc((13px) * var(--ts));line-height:1.5;color:var(--dim2)}
.footcert-t a{padding:0;border-radius:2px;font-size:inherit}

/* ---- programmes left, security right, one line ------------------------------------------------
   The programme row and the certification row used to stack, which put a second full row of height
   into every footer. They now share the line: the programmes where they always were, on the left,
   and the security marks on the right. .foottrust is the flex container (scripts/site-chrome.mjs
   stamps it) and margin-left:auto keeps the security block against the right edge even when the
   line wraps. Top-aligned, so the two kickers share a line and the taller shields hang below it.
   Under 820px there is no room for both, so they stack, and security goes first, above the
   sponsors. */
.foottrust{
  display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;
  gap:18px 40px;margin:18px auto 16px;
}
.foottrust > .footprog,.foottrust > .footcert{margin:0}
.foottrust > .footcert{margin-left:auto}
@media (max-width:820px){
  .foottrust{flex-direction:column;align-items:flex-start;gap:16px;margin:16px auto 14px}
  .foottrust > .footcert{order:-1;margin-left:0}
}

/* Left, not centred: it used to follow the space-between legal row directly, where a
   centred line read as a footer sign-off. The programme block now sits between them and
   is left-anchored, and a centred line under two left-aligned ones reads as unmoored.
   All three fine-print rows share one edge. */
/* Left, not centred: it used to follow the space-between legal row directly, where a
   centred line read as a footer sign-off. The programme block now sits between them and
   is left-anchored, and a centred line under two left-aligned ones reads as unmoored.
   All three fine-print rows share one edge. */
.foot-credit{margin-top:10px;font-size:calc((12px) * var(--ts));text-align:left}

@media (max-width:700px){
  .footgrid{
    grid-template-columns:repeat(2,minmax(0,1fr));
    grid-template-areas:"mark mark" "product more";
    gap:24px 28px;padding:20px;border-radius:18px;
  }
  .footmid{place-items:center start;min-height:80px;padding:16px 18px}
  .footmid svg{width:66px}
  .footcol-h{margin-bottom:8px}
  .footcol > a{min-height:40px;font-size:calc((14px) * var(--ts))}
  .footlegal{display:grid;gap:8px;justify-content:start;text-align:left;margin-top:18px}
  .footprog{margin:16px 0 14px}
  .footprog-row{gap:10px 22px}
  .footcert .cert-img{height:76px}
  .footcert-t{max-width:none;flex:1 1 100%}
  .foot-credit{text-align:left}
}

/* ---- tag filter shared by /models/ and /use-cases/ (tagfilter.js) -----------------------
   The same pill as .efilter and .itabs, kept as its own class because the eval filter's
   buttons wear a per-tag colour swatch and this one does not: the model catalogue's tags are
   attributes (served, dense, ours) with nothing to colour-code, and the industry filter's are
   places. Pressed goes to --hl like the tabs do, since with no swatch there is no per-tag tint
   to prefer. */
.tfilter{display:flex;flex-wrap:wrap;gap:8px;margin-top:24px}
.tfilter button{
  font-family:var(--sans);font-size:calc((13.5px) * var(--ts));color:var(--dim2);cursor:pointer;
  border:1px solid var(--line2);background:none;border-radius:999px;padding:7px 15px;
  display:inline-flex;align-items:center;gap:7px;
  transition:background .22s,color .22s,border-color .22s;
}
.tfilter button[aria-pressed="true"]{background:var(--hl);color:var(--on-hl);border-color:transparent}
.tfilter button:focus-visible{outline:2px solid var(--mint);outline-offset:2px}
/* The count behind a tag, written by tagfilter.js from the tiles themselves. */
.fcount{
  font-family:var(--mono);font-size:calc((11px) * var(--ts));line-height:1;
  padding:3px 6px;border-radius:999px;color:var(--dim);
  background:color-mix(in srgb,var(--dim2) 14%,transparent);
}
.tfilter button[aria-pressed="true"] .fcount{color:var(--on-hl);background:rgba(0,0,0,.08)}

/* ---- the model catalogue on /models/ ---------------------------------------------------
   One tile per model, which is the site's own vocabulary for a thing you can run. A served
   model wears the Models blue on its edge and its status chip; a build that is compressed and
   waiting is left on the hairline, so the three you can call today read first at a glance.
   No size or quality figure sits on a tile for a build that has not been published: the
   served build's numbers are in the quality section, which its tile links to. */
.mcat{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin-top:22px}
@media(max-width:980px){.mcat{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:600px){.mcat{grid-template-columns:1fr}}
.mtile{
  border:1px solid var(--line);border-radius:14px;padding:20px 20px 18px;
  display:flex;flex-direction:column;gap:10px;transition:border-color .18s;
}
.mtile[hidden]{display:none}
.mtile:hover{border-color:var(--line2)}
.mtile.served{border-color:color-mix(in srgb,var(--p-models) 42%,var(--line))}
.mtile h3{margin:0;font-size:calc((18px) * var(--ts))}
.mtile .mbase{margin:0;color:var(--dim);font-size:calc((14.5px) * var(--ts))}
.mtags{display:flex;flex-wrap:wrap;gap:6px}
.mtag{
  display:inline-flex;align-items:center;
  font-family:var(--mono);font-size:calc((10.5px) * var(--ts));letter-spacing:.07em;
  text-transform:uppercase;color:var(--dim);border:1px solid var(--line2);
  border-radius:999px;padding:3px 9px;
}
.mtag[data-tag="served"]{background:color-mix(in srgb,var(--p-models) 12%,transparent);border-color:transparent;color:var(--p-models)}
.mtag[data-tag="ready"]{background:color-mix(in srgb,var(--dim2) 11%,transparent);border-color:transparent}
/* The chip that matched the active filter, so a tile still says why it survived. */
.mtag.on{border-color:var(--txt);color:var(--txt)}
.mfacts{margin:2px 0 0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:5px 12px;font-size:calc((14px) * var(--ts))}
.mfacts div{display:contents}
.mfacts dt{color:var(--dim2);font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.06em;text-transform:uppercase;padding-top:2px}
.mfacts dd{margin:0;color:var(--txt)}
.mtile .more{margin-top:auto;padding-top:8px;font-size:calc((15px) * var(--ts))}

/* ---- use cases by industry on /use-cases/ ---------------------------------------------
   The four pieces, as a legend: a tile in the product's hue and the one line that says what it
   does in a use case. Every card below repeats the same three or four rows in the same order
   and the same colours, so once the legend is read the cards read as a table. */
.pieces{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-top:26px}
@media(max-width:980px){.pieces{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.pieces{grid-template-columns:1fr}}
.piece{border:1px solid var(--line);border-radius:12px;padding:14px 16px;font-size:calc((14px) * var(--ts));color:var(--dim)}
.piece b{display:flex;align-items:center;gap:8px;color:var(--txt);font-size:calc((14.5px) * var(--ts));margin-bottom:4px}
.piece b::before{content:"";width:12px;height:12px;border-radius:3px;background:var(--pc);flex:none}
.piece.d{--pc:var(--p-docs)} .piece.g{--pc:var(--p-gov)} .piece.c{--pc:var(--p-context)} .piece.m{--pc:var(--p-models)}

.ind[hidden]{display:none}
.ind .head{max-width:none}
.ucgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin-top:26px}
@media(max-width:980px){.ucgrid{grid-template-columns:1fr 1fr}}
@media(max-width:640px){.ucgrid{grid-template-columns:1fr}}
.uc{
  border:1px solid var(--line);border-radius:14px;padding:22px;
  display:flex;flex-direction:column;gap:10px;transition:border-color .18s;
}
.uc:hover{border-color:var(--line2)}
.uc h3{margin:0;font-size:calc((18px) * var(--ts))}
.uc p{margin:0;color:var(--dim);font-size:calc((15px) * var(--ts))}
/* The rows: which piece, then what it holds for this job. The mark before the label is the
   piece's tile, in its own hue, so the row is readable as colour and as a word. */
.ucf{margin:6px 0 0;padding-top:12px;border-top:1px solid var(--line);display:flex;flex-direction:column;gap:9px}
.ucf div{display:grid;grid-template-columns:104px minmax(0,1fr);gap:10px;align-items:start;font-size:calc((14px) * var(--ts))}
.ucf dt{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:calc((11px) * var(--ts));letter-spacing:.07em;text-transform:uppercase;padding-top:2px}
.ucf dt::before{content:"";width:9px;height:9px;border-radius:2px;background:currentColor;flex:none}
.ucf .d dt{color:var(--p-docs)} .ucf .g dt{color:var(--p-gov)} .ucf .m dt{color:var(--p-models)} .ucf .c dt{color:var(--p-context)}
.ucf dd{margin:0;color:var(--txt)}
@media(max-width:400px){.ucf div{grid-template-columns:1fr;gap:3px}}
.ind .more.a{margin-top:18px}
