
:root{
  --paper:#faf9f7; --paper-2:#f2f0ec; --card:#fffefc;
  /* --ink-4 carries the affiliate disclosure, the "read on / source" line and
     the struck official price. At #9b9ba3 those sat at 2.62:1 on paper, which
     fails WCAG AA at any size, and 2.42:1 in the footer. The quiet text is
     exactly the text that has to stay legible: a disclosure nobody can read
     has not disclosed anything. Both grounds now clear 4.5:1. */
  --ink:#16161a; --ink-2:#3d3d44; --ink-3:#55555d; --ink-4:#66666e;
  --rule:#dedbd4; --rule-2:#c9c5bc;
  --dark:#16161a; --dark-2:#1e1e23; --on-dark:#f4f3f1; --on-dark-2:#b4b4bc;
  --teal:#14615c; --teal-lift:#2f9188; --on-teal:#ffffff;
  --radius:10px; --tap:44px;
  /* Shadows are tinted to the ground rather than black. A pure black shadow
     on a warm paper background reads as a sticker sitting on the page; a
     tinted one reads as the page having depth. */
  --lift-1:0 1px 2px rgb(28 26 22/.05), 0 2px 6px rgb(28 26 22/.04);
  --lift-2:0 2px 4px rgb(28 26 22/.06), 0 8px 20px rgb(28 26 22/.07);
  --lift-3:0 4px 10px rgb(28 26 22/.08), 0 18px 44px rgb(28 26 22/.10);
  --s0:.9375rem; --s1:1.0625rem; --s2:1.375rem; --s3:1.875rem; --s4:2.75rem;
  --bay:clamp(4rem,8vw,7.5rem);
  /* Geist covers Latin, and the site is written in thirteen languages, six of
     which it has no glyphs for. Only the Korean fallbacks were listed, so a
     Japanese, Chinese, Thai or Arabic page fell through to whatever the
     browser picked -- which on Windows is a different face per script and on
     several is a serif. Each script names its platform face first and its
     Noto last, so a machine with neither still lands on something designed
     for that script. */
  --sans:"Geist","Geist Fallback",-apple-system,BlinkMacSystemFont,
    "Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",
    "Hiragino Sans","Yu Gothic","Noto Sans JP",
    "PingFang SC","Microsoft YaHei","Noto Sans SC",
    "PingFang TC","Microsoft JhengHei","Noto Sans TC",
    "Thonburi","Leelawadee UI","Noto Sans Thai",
    "Geeza Pro","Segoe UI","Noto Sans Arabic",
    system-ui,sans-serif;
  --mono:"Geist Mono","Geist Mono Fallback",ui-monospace,SFMono-Regular,Menlo,monospace;
}
@media (prefers-color-scheme:dark){
  :root{
    --paper:#101013; --paper-2:#0b0b0e; --card:#17171b;
    --ink:#edecea; --ink-2:#c3c3c9; --ink-3:#a3a3ab; --ink-4:#8a8a92;
    --rule:#2a2a31; --rule-2:#3a3a43;
    --dark:#08080a; --dark-2:#101013; --on-dark:#f4f3f1; --on-dark-2:#a3a3ab;
    --teal:#4ea79e; --teal-lift:#63c0b6; --on-teal:#08201e;
    --lift-1:0 1px 2px rgb(0 0 0/.30), 0 2px 6px rgb(0 0 0/.22);
    --lift-2:0 2px 4px rgb(0 0 0/.34), 0 8px 20px rgb(0 0 0/.30);
    --lift-3:0 4px 10px rgb(0 0 0/.40), 0 18px 44px rgb(0 0 0/.36);
  }
}

@font-face{font-family:"Geist";src:url("/assets/fonts/Geist-Variable.woff2")
  format("woff2");font-weight:100 900;font-display:swap}
@font-face{font-family:"Geist Mono";
  src:url("/assets/fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight:100 900;font-display:swap}

/* Fallbacks cut to the same measurements as the fonts they stand in for.
   "Geist Fallback" was already named in --sans and --mono and never defined,
   so it did nothing at all: a first-time reader got the system font, then
   Geist arrived and every line on the page reflowed, because Geist sets 8.5%
   wider and 5.5% taller per em than the system face. That reflow is the site's
   only failing Core Web Vital -- Cloudflare showed CLS partly red while LCP
   and INP were green -- and Core Web Vitals are a ranking signal on a site
   whose whole problem is being found.

   The numbers are measured, not copied: a canvas at 1000px reported Geist at
   0.92 em ascent and 0.22 descent, and 105.31% of Arial's width for the same
   string. The overrides are divided by size-adjust because size-adjust scales
   the em they are expressed against.

   The line gap had to be measured a second way. A canvas fontBoundingBox
   gives ascent and descent and not the gap, so the first attempt matched the
   width exactly and left the line box 8% short -- which still reflows, just
   vertically. line-height:normal is ascent + descent + gap, so the gap is the
   difference between the laid-out line box (1.24 em) and the two metrics
   (1.14 em), again divided by size-adjust.

   swap stays rather than optional. With the metrics matched the swap costs
   almost nothing, and optional would show some first-time readers the
   fallback for a whole page load to avoid a shift that is no longer there. */
@font-face{font-family:"Geist Fallback";
  src:local("Arial"),local("Helvetica Neue"),local("Segoe UI"),local("Roboto");
  size-adjust:105.31%;ascent-override:87.36%;descent-override:20.89%;
  line-gap-override:9.50%}
@font-face{font-family:"Geist Mono Fallback";
  src:local("Menlo"),local("Consolas"),local("DejaVu Sans Mono"),
      local("Courier New");
  size-adjust:99.98%;ascent-override:95.52%;descent-override:24.50%;
  line-gap-override:0%}

/* Logical properties throughout, not physical ones. Arabic is one of the
   thirteen locales and dir="rtl" only mirrors the page for properties that
   are written in terms of start and end. A text-align:left survives the
   mirror unchanged and quietly ruins the column it is in, which nobody who
   does not read Arabic will ever see. */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);
  font-size:var(--s1);line-height:1.6;-webkit-font-smoothing:antialiased}
/* The ground is a surface, not a fill. A single soft radial lifts the top of
   the page a shade warmer than the bottom, and a fixed grain -- drawn once as
   a data-URI so it costs no request -- gives the cream a tooth under raking
   light. Both are almost subliminal; the point is that the page stops looking
   like a blank canvas without anything on it announcing itself. */
body::before{content:"";position:fixed;inset:0;z-index:-2;pointer-events:none;
  background:radial-gradient(120% 80% at 50% -10%,
    color-mix(in srgb,var(--teal) 6%,transparent),transparent 55%)}
body::after{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  opacity:.5;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E")}
@media (prefers-color-scheme:dark){
  body::after{mix-blend-mode:screen;opacity:.4}
}
h1,h2,h3{margin:0;line-height:1.08;letter-spacing:-0.025em;font-weight:560}
p{margin:0}
a{color:inherit}
img{max-width:100%;display:block}
svg{display:block}

/* Every figure on the site is set here. tabular-nums is the whole reason: a
   comparison whose digits do not line up cannot be compared. */
.num{font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;letter-spacing:-0.02em}

.skip{position:absolute;inset-inline-start:-9999px;top:0;background:var(--card);
  padding:.75rem 1rem;border-radius:var(--radius);z-index:20}
.skip:focus{inset-inline-start:.75rem;top:.75rem}
.wrap{width:min(76rem,100% - 2.5rem);margin-inline:auto}
.bay{padding-block:var(--bay)}

.top{border-bottom:1px solid var(--rule);
  background:color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
  position:sticky;top:0;z-index:10}
@supports not (backdrop-filter:blur(1px)){.top{background:var(--paper)}}
@media (prefers-reduced-transparency:reduce){.top{background:var(--paper);
  backdrop-filter:none;-webkit-backdrop-filter:none}}
.top .wrap{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.5rem;
  min-height:62px;padding-block:.75rem}
.brand{display:flex;align-items:center;gap:.625rem;text-decoration:none;
  color:var(--teal);margin-inline-end:auto}
.brand svg{width:40px;height:auto;flex:none}
.brand b{color:var(--ink);font-weight:600;letter-spacing:-0.015em}
.brand span{color:var(--ink-4);font-size:var(--s0)}
.nav{display:flex;flex-wrap:wrap;gap:1.25rem;font-size:var(--s0)}
.nav a{color:var(--ink-3);text-decoration:none}
.nav a:hover{color:var(--ink)}

/* The hero. The number is the picture: a reader who sees the shared price
   beside the struck official one has understood the site before reading a
   word, which is the only thing the first screen has to achieve. */
/* The hero had a texture and no subject: the words sat on the left and the
   right two thirds of the first screen was empty ground. The photograph is
   the brand mark made physical -- four slots, one filled -- which is what
   this site is about, and it is lit in the same studio as every article
   image so the first screen and the reading section read as one publication.
   Pinned right so the slab occupies the space the words do not.

   The scrim is a horizontal gradient rather than the old radial one, because
   what has to stay dark is the reading side, and which side that is depends
   on the writing direction. */
.hero{background:var(--dark) url("/assets/img/hero-slots.webp")
  right center/cover no-repeat;
  color:var(--on-dark);
  padding-block:clamp(3.5rem,9vw,7rem);position:relative;isolation:isolate}
.hero::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to right,
    rgb(16 16 19/.96) 0%, rgb(16 16 19/.93) 46%,
    rgb(16 16 19/.62) 66%, rgb(16 16 19/.34) 100%)}
[dir="rtl"] .hero{background-position:left center}
[dir="rtl"] .hero::after{background:linear-gradient(to left,
    rgb(16 16 19/.96) 0%, rgb(16 16 19/.93) 46%,
    rgb(16 16 19/.62) 66%, rgb(16 16 19/.34) 100%)}
/* Below the fold of a phone the slab is not visible anyway, and a cover-fit
   crop of a 21:9 photograph on a tall narrow box shows one empty corner of
   it. Darker there, and the words get the whole width. */
@media (max-width:44rem){
  .hero::after{background:rgb(16 16 19/.9)}
}
.hero .rule{height:1px;background:rgb(255 255 255/.16);margin-bottom:clamp(2rem,6vw,5rem)}
.figures{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25em 1rem}
.shared{font-size:clamp(3.5rem,13vw,9rem);color:var(--teal-lift);
  font-weight:600;line-height:.9}
.official{font-size:clamp(1.5rem,5vw,3.5rem);color:rgb(255 255 255/.72);
  font-weight:500;text-decoration:line-through;padding-inline-end:.15em;
  text-decoration-thickness:.055em;text-underline-offset:0}
.unit{font-family:var(--sans);font-size:var(--s1);color:var(--on-dark-2);
  letter-spacing:normal;margin-inline-start:.35rem}
.cur{font-family:var(--sans);font-size:.66em;letter-spacing:normal;
  margin-inline-start:.12em;font-weight:500}
.official .cur{font-size:.7em}
.hero h1{margin-top:clamp(1.5rem,4vw,2.5rem);font-size:clamp(1.6rem,3.6vw,2.5rem);
  max-width:24ch;text-wrap:balance}
.hero .sub{margin-top:.75rem;color:var(--on-dark-2);max-width:52ch}
.hero .cta{margin-top:1.75rem}
.hero .stamp{color:var(--on-dark-2)}

.cta{display:inline-flex;align-items:center;gap:.5rem;min-height:var(--tap);
  padding:.75rem 1.5rem;background:var(--teal);color:var(--on-teal);
  text-decoration:none;border-radius:999px;font-weight:540;
  transition:transform .18s cubic-bezier(.16,1,.3,1),filter .18s}
.cta:hover{filter:brightness(1.1)}
.cta{position:relative;transition:transform .18s cubic-bezier(.16,1,.3,1),
  box-shadow .25s ease}
.cta:hover{box-shadow:0 4px 22px color-mix(in srgb,var(--teal) 32%,transparent)}
.cta:active{transform:translateY(1px)}
.cta-ghost{background:transparent;color:inherit;border:1px solid currentColor}
.cta-note{display:block;margin-top:.625rem;color:var(--ink-4);font-size:.8125rem}
.hero .cta-note{color:var(--on-dark-2)}

/* The written section. Reads as an article rather than a caption: a longer
   measure than the surrounding cards, a first line that is not indented into
   a column, and links that are visibly links inside running text. */
.writeup{margin-top:1.75rem;max-width:64ch}
.writeup p{margin-top:.85rem;color:var(--ink-2);line-height:1.7}
.writeup p:first-of-type{color:var(--ink);font-size:var(--s1)}
.writeup a{color:var(--ink);text-decoration:underline;
  text-underline-offset:.18em;text-decoration-thickness:.08em;
  text-decoration-color:var(--rule-2)}
.writeup a:hover{text-decoration-color:currentColor}

/* An article's opening and closing prose. After .writeup, not
   before it: both are one class plus a pseudo-class, so source
   order decides, and written first these lost every property
   they shared -- the lead paragraph stayed at body size, which
   is the one thing on the page that must not. The lead carries the weight -- it
   is what a reader who arrived from a search actually reads -- so it sits at
   a larger size than the table beneath it and is not indented into a column.
   The close is a caveat and is set quieter, after the numbers rather than
   before them, where somebody who wants it will look. */
.article-lead{margin:0 0 2rem;max-width:66ch}
.article-lead p:first-of-type{font-size:var(--s2);line-height:1.45;
  letter-spacing:-0.012em;color:var(--ink)}
.article-close{margin:2rem 0 0;max-width:66ch;
  border-top:1px solid var(--rule);padding-top:1.25rem}
.article-close p{font-size:var(--s0);color:var(--ink-3);line-height:1.65}

.eyebrow{font-family:var(--mono);font-size:.75rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-4)}

/* Latin typography stops at the Latin alphabet.
   The eyebrow is a mono face, tracked out 0.16em and uppercased. None of the
   three means anything in Arabic, Thai, Hangul or Han: Geist Mono has no
   glyphs for any of them, so those labels were already being set in a system
   font at a tracking chosen for a face they were not set in, and uppercase is
   a no-op. On Arabic it is worse than pointless -- the letters join, and
   letter-spacing pulls the joins apart into disconnected shapes. */
html[lang="ar"] .eyebrow,html[lang="th"] .eyebrow,html[lang="ko"] .eyebrow,
html[lang="ja"] .eyebrow,html[lang^="zh"] .eyebrow{
  font-family:var(--sans);font-size:.8125rem;letter-spacing:.02em;
  text-transform:none;font-weight:560}
html[lang="ar"] .eyebrow{letter-spacing:normal}

/* Headings sit at line-height 1.08 with the tracking pulled in, which is
   right for Latin and wrong for scripts that put ink above and below where
   Latin does not. Arabic and Thai stack marks two levels deep and were being
   given a box that cut them; Hangul and Han are square and need air between
   lines rather than tightening. Tracking goes back to normal everywhere here:
   negative tracking on a cursive script closes the joins. */
html[lang="ar"] h1,html[lang="ar"] h2,html[lang="ar"] h3,
html[lang="th"] h1,html[lang="th"] h2,html[lang="th"] h3{
  line-height:1.45;letter-spacing:normal}
html[lang="ko"] h1,html[lang="ko"] h2,html[lang="ko"] h3,
html[lang="ja"] h1,html[lang="ja"] h2,html[lang="ja"] h3,
html[lang^="zh"] h1,html[lang^="zh"] h2,html[lang^="zh"] h3{
  line-height:1.28;letter-spacing:normal}
html[lang="ar"] .lede h1,html[lang="th"] .lede h1,
html[lang="ko"] .lede h1,html[lang="ja"] .lede h1,
html[lang^="zh"] .lede h1{letter-spacing:normal}
.head{margin-bottom:1.75rem}
.head h2{font-size:var(--s3);margin-top:.5rem}
.head p{margin-top:.5rem;color:var(--ink-3);max-width:56ch}

/* Gapless bento. The hairlines are the grid's own background showing through
   one-pixel gaps, so no cell owns a border and none can disagree with its
   neighbour about which side the line is on. */
/* Flex rather than grid, and for one reason: a grid with a fixed column count
   leaves a hole whenever a shelf holds a number of services the count does not
   divide. Seven products in four columns left one empty box at the end of the
   row, which reads as a missing item rather than as a design. Here the last
   row's cells simply grow to fill the width, at every breakpoint, without the
   builder having to know how many there are.
   The hairlines are the container's own background showing through 1px gaps,
   so no cell owns a border and none can disagree with its neighbour. */
.bento{display:flex;flex-wrap:wrap;gap:1px;background:var(--rule);
  border:1px solid var(--rule);overflow:hidden;border-radius:var(--radius)}
.cell{background:var(--card);padding:1.25rem;min-height:9.5rem;
  flex:1 1 15rem;position:relative;
  display:flex;flex-direction:column;justify-content:space-between;
  text-decoration:none;
  transition:background .2s,transform .28s cubic-bezier(.16,1,.3,1),
             box-shadow .28s cubic-bezier(.16,1,.3,1)}
/* Lifts toward the reader on hover. The z-index is what stops the raised cell
   being clipped by the neighbours it is meant to rise above. */
/* A one-pixel top sheen catches the eye like an edge under light, so a card
   reads as a surface a shade proud of the page rather than a drawn box. */
.cell{position:relative}
.cell::before{content:"";position:absolute;inset:0 0 auto;height:1px;
  background:linear-gradient(90deg,transparent,
    color-mix(in srgb,var(--ink) 8%,transparent) 30%,
    color-mix(in srgb,var(--ink) 8%,transparent) 70%,transparent);
  opacity:0;transition:opacity .3s ease}
.cell:hover::before{opacity:1}
.cell:hover{background:var(--card);transform:translateY(-3px);
  box-shadow:var(--lift-3);z-index:2}
.cell:hover .cell-now{color:var(--teal)}
.cell:active{transform:translateY(-1px);box-shadow:var(--lift-1)}
.cell .icon{transition:transform .28s cubic-bezier(.16,1,.3,1)}
.cell:hover .icon{transform:scale(1.06) rotate(-1.5deg)}
.cell-name{font-weight:520;letter-spacing:-0.01em}
.cell-prices{display:flex;flex-direction:column;align-items:flex-end;
  gap:.125rem;margin-top:1.5rem}
.cell-was{font-size:var(--s0);color:var(--ink-4);text-decoration:line-through}
.cell-now{font-size:var(--s2);color:var(--teal);font-weight:560}
/* Grows far harder than a service cell, so it takes the leftover width rather
   than letting the last service stretch into it. */
.cell-photo{background:var(--dark) center/cover;min-height:9.5rem;
  flex:999 1 6rem}

/* Two services, one hard split, mirrored rows. Neither side is the default. */
.dip{display:grid;grid-template-columns:1fr;border-radius:var(--radius);
  overflow:hidden;border:1px solid var(--rule);box-shadow:var(--lift-2)}
@media (min-width:48rem){.dip{grid-template-columns:1fr 1fr}}
.dip-side{padding:clamp(1.5rem,4vw,2.5rem)}
.dip-light{background:var(--card);color:var(--ink)}
.dip-dark{background:var(--dark);color:var(--on-dark)}
.dip-side h3{font-size:var(--s3)}
.rows{margin:1.5rem 0 0;padding:0;list-style:none}
.rows li{display:flex;flex-wrap:wrap;gap:.5rem 1rem;
  justify-content:space-between;align-items:baseline;padding-block:.875rem;
  border-top:1px solid var(--rule)}
.dip-dark .rows li{border-color:rgb(255 255 255/.14)}
.rows li:first-child{border-top:0}
.k{color:var(--ink-3);font-size:var(--s0)}
.dip-dark .k{color:var(--on-dark-2)}
.keep{color:var(--teal);font-weight:600;font-size:var(--s2)}
.dip-dark .keep{color:var(--teal-lift)}

/* Editorial side-image. Photograph carries the weight; the panel carries the
   claim. Stacks to photo-then-text on a phone. */
.split{display:grid;grid-template-columns:1fr;border-radius:var(--radius);
  overflow:hidden}
@media (min-width:52rem){.split{grid-template-columns:1.5fr 1fr}}
.split-img{background:var(--paper-2) center/cover;min-height:16rem}
.split-panel{background:var(--dark);color:var(--on-dark);
  padding:clamp(1.75rem,4vw,3rem);display:flex;flex-direction:column;
  justify-content:center;gap:1rem}
.split-panel h2{font-size:var(--s3)}
.split-panel p{color:var(--on-dark-2);max-width:46ch}

/* The service's own mark. Square, never stretched, and never the thing the
   eye lands on first: the price is. */
.icon{width:34px;height:34px;border-radius:8px;object-fit:cover;flex:none;
  background:var(--paper-2)}

/* ------------------------------------------------------- the first screen */
/* What the site is for, and the only picture on it that is not decoration:
   the marks of the services themselves. Forty at once say "this is about AI
   subscriptions" faster than a sentence can, and they were already in the
   build -- they were 404ing on every page, which is its own story. */
.home-hero{border-bottom:1px solid var(--rule);
  padding-block:clamp(2.5rem,7vw,5.5rem);overflow:hidden}
.home-hero-in{display:grid;gap:clamp(2rem,5vw,4rem);align-items:center;
  grid-template-columns:1fr}
@media (min-width:60rem){.home-hero-in{grid-template-columns:1.05fr .95fr}}
.home-say h1{margin-top:.75rem;font-size:clamp(2rem,5.2vw,3.4rem);
  max-width:17ch;text-wrap:balance;letter-spacing:-0.03em;line-height:1.06}
.home-say .sub{margin-top:1rem;color:var(--ink-2);max-width:52ch;
  font-size:var(--s1);line-height:1.6}
.home-acts{margin-top:1.75rem;display:flex;flex-wrap:wrap;gap:.625rem}
.cta-quiet{background:transparent;color:var(--ink);
  border:1px solid var(--rule-2)}
.cta-quiet:hover{border-color:var(--ink);background:transparent}

.wall{display:grid;gap:.5rem;
  grid-template-columns:repeat(auto-fill,minmax(46px,1fr))}
/* A tile, not a bare image. Several of these marks are a white wordmark on a
   white field -- Grammarly, Rita, ChatGPT -- and on the paper background they
   vanished into it, so the wall showed a dozen blank squares. The hairline
   and the slightly sunk ground give every mark an edge whatever it is. */
.icon-wall{width:100%;height:auto;aspect-ratio:1;border-radius:11px;
  background:var(--paper-2);box-shadow:inset 0 0 0 1px var(--rule);
  opacity:.92;transition:opacity .3s ease,transform .3s ease}
.wall:hover .icon-wall{opacity:.55}
.wall .icon-wall:hover{opacity:1;transform:translateY(-2px)}

/* The catalogue, folded behind two lines and an arrow. */
.fold{border:1px solid var(--rule);border-radius:var(--radius);
  background:var(--card);overflow:hidden}
.fold summary{display:flex;align-items:center;justify-content:space-between;
  gap:1rem;padding:1.25rem 1.5rem;cursor:pointer;list-style:none}
.fold summary::-webkit-details-marker{display:none}
.fold summary:focus-visible{outline:2px solid var(--teal);outline-offset:-3px}
.fold-say{display:flex;flex-direction:column;gap:.25rem;min-width:0}
.fold-say b{font-size:var(--s2);letter-spacing:-0.02em}
.fold-say small{color:var(--ink-3);font-size:var(--s0)}
/* The sharpest few prices, in the summary. A fold labelled only "catalogue"
   asks the reader to take it on trust that opening it is worth doing. */
.fold-peek{display:flex;flex-wrap:wrap;gap:.4rem .875rem;margin-top:.35rem}
.peek{display:inline-flex;align-items:center;gap:.35rem}
.peek-now{font-family:var(--mono);font-size:var(--s0);color:var(--teal);
  font-variant-numeric:tabular-nums;letter-spacing:-0.02em}
.fold-more{display:flex;align-items:center;gap:.4rem;flex:none;
  color:var(--teal);font-size:var(--s0);font-weight:520}
.fold-more svg{transition:transform .25s ease}
.fold[open] .fold-more svg{transform:rotate(180deg)}
.fold-body{border-top:1px solid var(--rule)}

/* ------------------------------------------------------------- on a phone */
/* Phones are large and this was built as though they were not: the first
   screen spent itself on one headline, one paragraph and two stacked pill
   buttons, and the header took three rows to say the site's name. Everything
   below is the same design at a size that fits more of itself on screen --
   nothing is redrawn, only the air is taken out. */
@media (max-width:44rem){
  :root{--bay:2.5rem}
  body{font-size:var(--s0);line-height:1.55}
  /* Two rows, not three. The bar wrapped brand, then nav, then the language
     button onto separate lines, so the sticky header ate a fifth of the
     screen before the page began. The globe goes up beside the name -- it is
     the one control a reader who cannot read this page needs first -- and the
     nav takes the second row on its own. */
  .top .wrap{gap:.4rem .75rem;min-height:0;padding-block:.45rem}
  .brand{margin-inline-end:auto;order:1}
  .brand span{display:none}          /* the tagline wrapped to its own line */
  .brand svg{width:28px}
  .lang{order:2}
  .lang summary{padding:.3rem .5rem}
  .lang-now{font-size:var(--s0)}
  .nav{order:3;flex-basis:100%;gap:1rem;font-size:var(--s0)}
  .home-hero{padding-block:1.75rem 1.5rem}
  .home-hero-in{gap:1.5rem}
  .home-say h1{font-size:clamp(1.7rem,7.4vw,2.2rem);line-height:1.1;
    max-width:none;margin-top:.5rem}
  .home-say .sub{margin-top:.7rem;font-size:var(--s0);line-height:1.5;
    max-width:none}
  .home-acts{margin-top:1.1rem;gap:.5rem;flex-wrap:nowrap}
  .home-acts .cta{flex:1 1 0;justify-content:center;text-align:center;
    padding:.7rem .9rem;font-size:var(--s0);white-space:nowrap}
  .wall{gap:.375rem;grid-template-columns:repeat(auto-fill,minmax(38px,1fr))}
  .fold summary{padding:.9rem 1rem;gap:.625rem}
  .fold-say b{font-size:var(--s1)}
  .fold-say small{display:none}      /* the currency note repeats below */
  .fold-more span{display:none}
  .fold-peek{gap:.35rem .7rem}
  .peek-now{font-size:.8125rem}

  /* A service is a row, not a card. Each cell was three hundred and forty
     pixels tall to hold a name, a plan and two numbers, so the catalogue ran
     to fourteen thousand pixels and a phone showed three services a screen. */
  .cell{padding:.7rem .875rem}
  .cell-top{align-items:center;gap:.6rem}
  .cell .icon{width:28px;height:28px;border-radius:7px}
  .cell-name{font-size:var(--s0)}
  .cell-name small{display:block;color:var(--ink-4);font-size:.75rem}
  .cell-prices{flex-direction:row;align-items:baseline;gap:.5rem;
    margin-top:.35rem}
  .cell-now{font-size:var(--s1)}
  .cell-was{font-size:.75rem}
  .head{margin-bottom:1.1rem}
  .head h2{font-size:var(--s2)}
  .post-text{padding:.9rem}
  .post-text b{font-size:var(--s1)}
  .next-read{margin-top:1.75rem;padding-top:1.1rem}
  .article-lead{margin-bottom:1.25rem}
  .article-lead p:first-of-type{font-size:var(--s1);line-height:1.5}
}
.icon-sm{width:24px;height:24px;border-radius:6px}
.kick{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem}
.cell-top{display:flex;align-items:flex-start;gap:.625rem}
.cell-name small{display:block;color:var(--ink-4);font-weight:400;
  font-size:.8125rem;margin-top:.125rem}
.dip-side h3{display:flex;align-items:center;gap:.625rem}

.chips{display:flex;flex-wrap:wrap;gap:.375rem;justify-content:flex-end}
.chip{border:1px solid var(--rule);border-radius:999px;padding:.125rem .625rem;
  font-size:.8125rem;color:var(--ink-3)}

/* The seller's own notes, quoted. These carry the caveats, which is exactly
   why they are set as readable body text rather than tucked into small print. */
.notes{margin-top:2rem;border-top:1px solid var(--rule);padding-top:1.5rem}
.note-list{margin:1rem 0 0;padding-inline-start:1.1rem;color:var(--ink-2)}
.note-list li{margin-top:.625rem}
.note-list li:first-child{margin-top:0}
.pair-notes{display:grid;gap:2rem;grid-template-columns:1fr}
@media (min-width:52rem){.pair-notes{grid-template-columns:1fr 1fr}}

.detail{display:grid;gap:2rem;grid-template-columns:1fr}
@media (min-width:56rem){.detail{grid-template-columns:1.6fr 1fr;
  align-items:start}}
.detail-main{min-width:0}
.detail-side{background:var(--card);border:1px solid var(--rule);
  border-radius:var(--radius);padding:1.5rem;position:sticky;top:5rem;
  box-shadow:var(--lift-2)}
@media (max-width:55.99rem){.detail-side{position:static}}

/* A shelf: photographic band, then its services. The band is what stops the
   catalogue reading as forty identical boxes. It carries no baked-in text,
   because the label above it changes with the reader's language. */
.shelf{margin-bottom:clamp(2.5rem,6vw,4rem)}
.band{background:var(--dark) center/cover;color:var(--on-dark);
  position:relative;isolation:isolate}
/* Physical direction, mirrored explicitly for RTL. A 90deg gradient does not
   flip with dir, so on the Arabic pages the heading mirrored to the right and
   landed on the transparent end, over the bright part of the photograph. */
.band::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to right,rgb(0 0 0/.72),rgb(0 0 0/.20) 68%)}
[dir="rtl"] .band::after{
  background:linear-gradient(to left,rgb(0 0 0/.72),rgb(0 0 0/.20) 68%)}
.band-in{display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem 1rem;
  padding-block:clamp(2rem,5vw,3.25rem)}
.band-in h3{font-size:clamp(1.35rem,3vw,2rem);margin-inline-end:auto}
.band-in p{color:var(--on-dark-2);font-size:var(--s0)}
.shelf .bento{border-top:0;border-top-left-radius:0;border-top-right-radius:0}

/* Same page, another language. Sits at the end of the header row and wraps
   with it, because a language list that cannot wrap is the thing that made
   every page on the old site scroll sideways at 390px. */
/* The language switcher, behind the globe.
   Spelled out, thirteen names wrapped the sticky header onto a second row on
   every page of the site to hold a list nobody needs until they need it. */
.lang{position:relative;font-size:var(--s0)}
.lang summary{display:flex;align-items:center;gap:.4rem;cursor:pointer;
  list-style:none;color:var(--ink-3);padding:.35rem .6rem;border-radius:8px;
  border:1px solid var(--rule);background:var(--card);
  transition:border-color .2s ease,color .2s ease}
.lang summary::-webkit-details-marker{display:none}
.lang summary:hover{color:var(--ink);border-color:var(--rule-2)}
.lang summary:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.lang svg{flex:none}
.lang .chev{transition:transform .2s ease}
.lang[open] .chev{transform:rotate(180deg)}
.lang-now{font-weight:520;color:var(--ink)}
.lang-list{position:absolute;inset-inline-end:0;top:calc(100% + .5rem);
  z-index:40;background:var(--card);border:1px solid var(--rule);
  border-radius:var(--radius);box-shadow:var(--lift-3);padding:.5rem;
  display:grid;grid-template-columns:1fr 1fr;gap:.125rem;min-width:19rem}
.lang-list a{color:var(--ink-3);text-decoration:none;padding:.5rem .625rem;
  border-radius:8px;white-space:nowrap}
.lang-list a:hover{color:var(--ink);background:var(--paper-2)}
.lang-list a[aria-current]{color:var(--ink);background:var(--paper-2);
  font-weight:560}

/* On a phone the list is the screen. A dropdown pinned to a button in the
   corner would put thirteen targets in a column narrower than a thumb. */
@media (max-width:44rem){
  .lang-list{position:fixed;inset:auto 0 0 0;top:auto;border-radius:0;
    border-inline:0;border-bottom:0;max-height:70vh;overflow:auto;
    grid-template-columns:1fr 1fr;gap:.25rem;padding:.75rem .75rem 1.25rem;
    min-width:0}
  .lang-list a{padding:.85rem .75rem;font-size:var(--s1)}
  .lang[open]::before{content:"";position:fixed;inset:0;z-index:39;
    background:rgb(0 0 0/.4)}
}

/* A month's difference is easy to wave away; a year's is the number the
   reader is actually deciding about. */
.annual{margin-top:1.25rem;padding-top:1.25rem;border-top:1px solid var(--rule);
  display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem 1rem;
  justify-content:space-between}
.annual b{font-size:var(--s3)}
.annual small{flex-basis:100%;color:var(--ink-4);font-size:.8125rem;
  line-height:1.5}

.calc{margin-top:2rem;background:var(--card);border:1px solid var(--rule);
  border-radius:var(--radius);padding:1.5rem}
.calc-row{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1rem;
  margin-top:1rem}
.calc-row label{color:var(--ink-3);font-size:var(--s0)}
.calc-range{flex:1 1 12rem;accent-color:var(--teal);height:var(--tap);
  min-width:0}
.calc-m{font-size:var(--s2);min-width:2.5ch;text-align:end}
.calc-out{display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem 1rem;
  justify-content:space-between;margin-top:1rem;padding-top:1rem;
  border-top:1px solid var(--rule)}
.calc-out b{font-size:var(--s3)}
.calc small{display:block;margin-top:.75rem;color:var(--ink-4);
  font-size:.8125rem}
.tick{font-variant-numeric:tabular-nums}

/* Reading. The header photograph is the article's own; the cards below use
   the same images at card size so the list and the pieces read as one set. */
.post-head{background:var(--dark) center/cover;color:var(--on-dark);
  position:relative;isolation:isolate}
.post-head::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to right,rgb(0 0 0/.82),rgb(0 0 0/.42))}
[dir="rtl"] .post-head::after{
  background:linear-gradient(to left,rgb(0 0 0/.82),rgb(0 0 0/.42))}
.post-head-in{padding-block:clamp(3rem,8vw,6rem);max-width:44rem}
.post-head-in h1{font-size:clamp(1.75rem,4vw,var(--s4));margin-top:.75rem;
  text-wrap:balance}
.post-head-in p{margin-top:1rem;color:var(--on-dark-2);max-width:52ch}
.post-head-in .stamp{color:var(--on-dark-2);margin-top:1.5rem}

.posts{display:grid;gap:1px;background:var(--rule);
  border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;
  grid-template-columns:1fr}
@media (min-width:44rem){.posts{grid-template-columns:1fr 1fr}}

/* Editorial rhythm rather than a stack of identical tiles.
   Five articles fitted in three rows and read as a page. Twelve fills six
   identical rows, which reads as a directory: nothing is more important than
   anything else, so nothing is worth opening. The lead piece takes the full
   width with its picture beside its text, and everything after it drops to a
   three-up grid at a smaller size. Same components, one decision about which
   piece leads. */
@media (min-width:60rem){
  .posts{grid-template-columns:repeat(3,1fr)}
  .post:first-child{grid-column:1 / -1;flex-direction:row;align-items:stretch}
  /* 16:9 and never cropped to fit the card.
     These thumbnails carry words -- a headline, a label each side, a VS on
     the split -- and the lead card used aspect-ratio:auto with a minimum
     height, so the card decided the crop and the crop took the headline off
     the top and the labels off the bottom. A picture with type in it cannot
     be treated as a texture. The image sets the height now and the text
     column fits beside it. */
  .post:first-child .post-img{flex:0 0 52%;aspect-ratio:16/9;min-height:0}
  .post:first-child .post-text{justify-content:center;padding:2.5rem 3rem;
    gap:.75rem}
  .post:first-child .post-text b{font-size:var(--s3);letter-spacing:-0.025em}
  .post:first-child .post-text small{font-size:var(--s1);max-width:44ch}
  .post:nth-child(2),.post:nth-child(3){grid-column:span 3}
  .post:nth-child(2),.post:nth-child(3){flex-direction:row}
  .post:nth-child(2) .post-img,.post:nth-child(3) .post-img{
    flex:0 0 34%;aspect-ratio:16/9;min-height:0}
  .post:nth-child(2) .post-text,.post:nth-child(3) .post-text{
    justify-content:center;padding:1.75rem 2.25rem}
  .post:nth-child(2) .post-text b,.post:nth-child(3) .post-text b{
    font-size:var(--s2)}
}
/* Right-to-left has to mirror, or the lead article's picture sits on the
   wrong side of its own headline. flex-direction:row already follows the
   writing direction; what does not is which edge the picture is pinned to,
   and that is handled by order rather than by a physical property. */
/* The front page's band is a doorway, not the index: four articles at one
   size, so nothing here competes with the reading page's own hierarchy. */
.posts-band{grid-template-columns:1fr}
@media (min-width:44rem){.posts-band{grid-template-columns:1fr 1fr}}
@media (min-width:60rem){
  .posts-band{grid-template-columns:repeat(4,1fr)}
  .posts-band .post:first-child,
  .posts-band .post:nth-child(2),
  .posts-band .post:nth-child(3){grid-column:auto;flex-direction:column}
  .posts-band .post .post-img{flex:none;aspect-ratio:16/9;min-height:0}
  .posts-band .post .post-text{padding:1.25rem;justify-content:flex-start}
  .posts-band .post .post-text b{font-size:var(--s1);letter-spacing:-0.015em}
  .posts-band .post .post-text small{font-size:var(--s0);max-width:none}
}
/* Where to go next. Quiet: it sits at the end of something the reader has
   just finished, so it should read as an offer rather than as a demand. The
   rule above it does the separating; there is no box. */
.next-read{margin-top:2.5rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.next-read ul{list-style:none;margin:.75rem 0 0;padding:0;
  display:flex;flex-direction:column;gap:.6rem}
.next-read a{color:var(--ink);text-decoration:none;font-size:var(--s1);
  letter-spacing:-0.012em;display:inline-block;
  border-bottom:1px solid var(--rule-2);padding-bottom:.15rem;
  transition:border-color .2s ease}
.next-read a:hover{border-bottom-color:var(--ink)}

/* ------------------------------------------------- editorial components */
/* The reference brief for these was a set of inline-styled boxes: purple
   gradients, coloured left borders, emoji labels. The ideas are right and the
   execution could not ship here -- this site has one stylesheet, the audit
   fails a build on any class without a rule, DESIGN.md bans AI-purple
   gradients, and GamsGo asked in writing that the site not resemble their own.
   So each component was rebuilt on the tokens already in the sheet, and the
   emoji labels dropped: they render differently in thirteen languages and
   change the line height of an Arabic or Thai row they sit in. */

/* The answer, at the top, before the reader has to scroll for it. */
.answer{background:var(--dark);color:var(--on-dark);border-radius:var(--radius);
  padding:1.75rem 1.75rem 1.5rem;margin:1.5rem 0 2rem;max-width:66ch}
.answer p:first-child{font-size:var(--s0);color:var(--on-dark-2);
  letter-spacing:.06em;text-transform:uppercase;margin:0 0 .6rem}
.answer b{display:block;font-size:var(--s2);line-height:1.35;
  letter-spacing:-0.02em;font-weight:560;margin-bottom:.65rem}
.answer small{display:block;font-size:var(--s1);color:var(--on-dark-2);
  line-height:1.6}

/* One note, set aside. Three kinds, told apart by a rule down the side
   rather than by a filled panel, so a page with several does not turn into a
   stack of coloured boxes. */
.aside{border-inline-start:3px solid var(--rule-2);padding:.15rem 0 .15rem 1.1rem;
  margin:1.5rem 0;max-width:64ch}
.aside p:first-child{font-weight:560;margin:0 0 .35rem;font-size:var(--s0);
  letter-spacing:.02em}
.aside p+p{margin:0;color:var(--ink-2);line-height:1.7}
.aside.tip{border-inline-start-color:var(--teal)}
.aside.tip p:first-child{color:var(--teal)}
.aside.warn{border-inline-start-color:#a8631f}
.aside.warn p:first-child{color:#a8631f}
.aside.ok{border-inline-start-color:var(--ink-3)}
.aside.ok p:first-child{color:var(--ink)}

/* A procedure, numbered. */
.steps{list-style:none;counter-reset:step;margin:1.5rem 0;padding:0;
  max-width:64ch}
.steps li{counter-increment:step;display:flex;gap:1rem;margin-bottom:1.1rem}
.steps li::before{content:counter(step);flex:none;width:1.9rem;height:1.9rem;
  border-radius:50%;background:var(--dark);color:var(--on-dark);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:.8125rem;font-weight:560}
.steps b{display:block;margin-bottom:.2rem}
.steps span{color:var(--ink-2);line-height:1.7}

/* Things to have ready. */
.checks{background:var(--paper-2);border-radius:var(--radius);
  padding:1.25rem 1.5rem;margin:1.5rem 0;max-width:60ch}
.checks p:first-child{font-weight:560;margin:0 0 .7rem}
.checks ul{list-style:none;margin:0;padding:0;line-height:2}
.checks li{padding-inline-start:1.5rem;position:relative;color:var(--ink-2)}
.checks li::before{content:"";position:absolute;inset-inline-start:0;top:.75em;
  width:.55rem;height:.3rem;border-inline-start:2px solid var(--teal);
  border-bottom:2px solid var(--teal);transform:rotate(-45deg)}

/* A figure worth stopping on, with where it came from. */
.quote{margin:1.75rem 0;padding-inline-start:1.25rem;
  border-inline-start:3px solid var(--ink);max-width:60ch}
.quote p:first-child{font-size:var(--s2);font-weight:520;line-height:1.45;
  letter-spacing:-0.015em;margin:0 0 .4rem}
.quote cite{font-style:normal;font-size:var(--s0);color:var(--ink-3)}

/* Two options, side by side. */
.versus-cards{display:grid;gap:1px;background:var(--rule);margin:1.75rem 0;
  border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;
  grid-template-columns:1fr}
@media (min-width:36rem){.versus-cards{grid-template-columns:1fr 1fr}}
.versus-cards>div{background:var(--card);padding:1.25rem 1.375rem}
.versus-cards b{display:block;margin-bottom:.5rem;font-size:var(--s1)}
.versus-cards p{margin:0;color:var(--ink-2);line-height:1.7;font-size:var(--s0)}

/* Questions and their answers, folded. <details> so the page is not a wall of
   text a reader has to scan past, and so a search engine still reads every
   answer -- content inside details is in the DOM and is indexed. */
.faq{margin:2rem 0;max-width:66ch}
.faq h2{font-size:var(--s2);margin-bottom:.75rem}
.faq details{border-top:1px solid var(--rule)}
.faq details:last-of-type{border-bottom:1px solid var(--rule)}
.faq summary{cursor:pointer;list-style:none;padding:.95rem 0;
  font-weight:520;display:flex;justify-content:space-between;gap:1rem}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";color:var(--ink-4);font-family:var(--mono);
  flex:none}
.faq details[open] summary::after{content:"2"}
.faq details p{margin:0 0 1rem;color:var(--ink-2);line-height:1.7;
  max-width:62ch}

/* Where a reader can check this for themselves. */
.sources{margin:2rem 0;padding-top:1.25rem;border-top:1px solid var(--rule);
  max-width:64ch}
.sources ul{list-style:none;margin:.6rem 0 0;padding:0;line-height:1.9}
.sources a{color:var(--ink);text-decoration:underline;
  text-underline-offset:.18em;text-decoration-color:var(--rule-2)}
.sources a:hover{text-decoration-color:currentColor}
.sources span{color:var(--ink-3);font-size:var(--s0)}

/* ------------------------------------------------- the reading index */
/* One feature, then a list.
   It was twelve full-width cards, each a 16:9 photograph with the headline
   beside it in a whisper: three articles filled two thousand pixels and the
   page read as a gallery somebody had left the captions on. Somebody scanning
   a dozen pieces wants the twelve titles. */
.lede-card{display:grid;gap:0;text-decoration:none;color:inherit;
  border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;
  background:var(--card);grid-template-columns:1fr;
  transition:border-color .25s ease}
.lede-card:hover{border-color:var(--rule-2)}
@media (min-width:52rem){.lede-card{grid-template-columns:1.15fr 1fr}}
.lede-img{background:var(--dark) center/cover;aspect-ratio:16/9;display:block}
.lede-text{padding:1.75rem 2rem;display:flex;flex-direction:column;
  justify-content:center;gap:.5rem}
.lede-text .stamp{font-family:var(--mono);font-size:.75rem;color:var(--ink-4);
  letter-spacing:.06em}
.lede-text b{font-size:var(--s3);line-height:1.15;letter-spacing:-0.028em}
.lede-text small{color:var(--ink-3);font-size:var(--s1);line-height:1.55;
  max-width:46ch}

/* Sort, as buttons. Latest and picks are always true; most-read appears the
   day real view counts exist and not before. */
.tabs{display:flex;gap:.375rem;margin:2rem 0 1.25rem;flex-wrap:wrap}
.tab{font:inherit;font-size:var(--s0);font-weight:520;cursor:pointer;
  padding:.45rem .9rem;border-radius:999px;border:1px solid var(--rule);
  background:transparent;color:var(--ink-3);
  transition:color .2s ease,border-color .2s ease,background .2s ease}
.tab:hover{color:var(--ink);border-color:var(--rule-2)}
.tab[aria-selected="true"]{background:var(--dark);color:var(--on-dark);
  border-color:var(--dark)}
.tab:focus-visible{outline:2px solid var(--teal);outline-offset:2px}

/* The grid. A card carries its picture, its headline and enough summary to
   decide on -- which the list rows did not, and the full-width photographs
   drowned. */
.tiles{display:grid;gap:1px;background:var(--rule);
  border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;
  grid-template-columns:1fr}
@media (min-width:34rem){.tiles{grid-template-columns:1fr 1fr}}
@media (min-width:62rem){.tiles{grid-template-columns:repeat(3,1fr)}}
.tile{background:var(--card);text-decoration:none;color:inherit;
  display:flex;flex-direction:column;
  transition:transform .28s cubic-bezier(.16,1,.3,1),box-shadow .28s ease}
.tile:hover{transform:translateY(-3px);z-index:2;
  box-shadow:0 6px 26px color-mix(in srgb,var(--teal) 14%,rgb(28 26 22/.10))}
.tile[hidden]{display:none}
.tile-img{display:block;aspect-ratio:16/9;background:var(--dark) center/cover}
.tile-text{padding:1.1rem 1.2rem 1.35rem;display:flex;flex-direction:column;
  gap:.35rem;flex:1}
.tile-text .stamp{font-family:var(--mono);font-size:.7rem;color:var(--ink-4);
  letter-spacing:.06em}
.tile-text b{font-size:var(--s1);line-height:1.3;letter-spacing:-0.018em}
.tile-text small{color:var(--ink-3);font-size:var(--s0);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden}

.more-wrap{display:flex;justify-content:center;margin-top:1.5rem}
.more{font:inherit;font-size:var(--s0);font-weight:520;cursor:pointer;
  padding:.7rem 1.6rem;border-radius:999px;border:1px solid var(--rule-2);
  background:transparent;color:var(--ink);transition:background .2s ease}
.more:hover{background:var(--paper-2)}
.more:focus-visible{outline:2px solid var(--teal);outline-offset:2px}

/* Said out loud on every translated page. A machine translation presented as
   native writing is what a search engine treats as spam; a labelled one is
   not, and a reader deserves to be told either way. */
.translated{margin:0 0 1.25rem;padding:.6rem .9rem;border-radius:8px;
  background:var(--paper-2);display:inline-block;font-size:var(--s0)}
.translated a{color:var(--ink);text-decoration:underline;
  text-underline-offset:.16em}

/* Matchup cards, not an underlined list. Each shows both marks and the pair,
   sits directly under the diptych, and closes the run of empty page the flat
   list left below it. */
.vs-grid{display:grid;gap:1px;background:var(--rule);margin-top:1.5rem;
  border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;
  grid-template-columns:1fr}
@media (min-width:34rem){.vs-grid{grid-template-columns:1fr 1fr}}
@media (min-width:56rem){.vs-grid{grid-template-columns:repeat(3,1fr)}}
.vs-card{background:var(--card);text-decoration:none;color:inherit;
  padding:1.1rem 1.25rem;display:flex;flex-direction:column;gap:.6rem;
  transition:background .2s ease}
.vs-card:hover{background:var(--paper-2)}
.vs-marks{display:flex;align-items:center;gap:.5rem}
.vs-x{font-family:var(--mono);font-size:.7rem;color:var(--ink-4);
  text-transform:uppercase;letter-spacing:.1em}
.vs-title{font-size:var(--s1);font-weight:520;letter-spacing:-0.015em;
  line-height:1.25}
.vs-card:hover .vs-title{text-decoration:underline;
  text-underline-offset:.16em;text-decoration-color:var(--rule-2)}

/* A figure in the article body. Full column width, its own caption, sitting
   in the reading measure rather than bleeding past it. */
.body-img{margin:2rem 0;max-width:100%}
.body-img img{display:block;width:100%;height:auto;border-radius:var(--radius);
  background:var(--dark)}
.body-img figcaption{margin-top:.6rem;font-size:var(--s0);color:var(--ink-3);
  line-height:1.5;max-width:60ch}

.band-more{margin-top:1.25rem}
.band-more a{color:var(--teal);font-weight:520;text-decoration:none}
.band-more a:hover{text-decoration:underline;text-underline-offset:.2em}

[dir="rtl"] .post:first-child .post-img,
[dir="rtl"] .post:nth-child(2) .post-img,
[dir="rtl"] .post:nth-child(3) .post-img{order:2}
.post{background:var(--card);display:flex;flex-direction:column;
  text-decoration:none;position:relative;
  transition:transform .3s cubic-bezier(.16,1,.3,1),
             box-shadow .3s cubic-bezier(.16,1,.3,1)}
.post:hover{transform:translateY(-4px);box-shadow:var(--lift-3);z-index:2}
.post-img{overflow:hidden}
/* contain, not cover. Every article image is 16:9 and every slot is 16:9, so
   in practice these agree -- but a future image at another ratio would be
   cropped by cover, and these carry type. Letterboxing an odd one is a
   blemish; beheading its headline is a broken picture. */
.post-img{display:block;aspect-ratio:16/9;
  background:var(--dark) center/contain no-repeat;
  transition:transform .4s cubic-bezier(.16,1,.3,1)}
.post:hover .post-img{transform:scale(1.03)}
.post-text{padding:1.25rem;display:flex;flex-direction:column;gap:.5rem}
.post-text b{font-size:var(--s2);letter-spacing:-0.015em;line-height:1.2}
.post-text small{color:var(--ink-3);font-size:var(--s0);line-height:1.55}
.post-go{color:var(--teal);font-size:var(--s0);font-weight:520;
  margin-top:.25rem}
.post-note{margin-top:2.5rem}
.post-note h2{display:flex;align-items:center;gap:.625rem;font-size:var(--s2)}

/* Restored deliberately. All three went missing in a stylesheet rewrite and
   the pages that used them still rendered, just wrongly, which is exactly the
   failure the unstyled-class check in tests/audit.py exists to catch. */
.lede{max-width:52ch}
.lede h1{font-size:clamp(2.25rem,5.5vw,var(--s4));letter-spacing:-0.035em;
  text-wrap:balance}
.lede p{margin-top:1rem;color:var(--ink-3);font-size:var(--s2);max-width:46ch}
.scroller{max-width:100%}
.calc-sum{display:inline-flex;align-items:baseline}

.close{text-align:center;padding-block:var(--bay)}
.close h2{font-size:clamp(1.75rem,4vw,var(--s4));max-width:22ch;
  margin-inline:auto;text-wrap:balance}
.close p{margin-top:.75rem;color:var(--ink-3)}
.close .cta{margin-top:1.75rem}
.close .stamp{margin-top:3rem;border-top:1px solid var(--rule);
  padding-top:1rem;text-align:start}

.stamp{color:var(--ink-4);font-size:var(--s0)}
.stamp a{color:inherit}
.note{background:var(--paper-2);border:1px solid var(--rule);
  border-radius:var(--radius);padding:1.25rem 1.5rem;color:var(--ink-2);
  font-size:var(--s0)}
.prose{max-width:62ch}
.prose p + p{margin-top:1rem}

/* Kept because the audit checks that a wide table scrolls on its own rather
   than depending on a wrapper the generator has to remember. */
.tw,table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;
  border-collapse:collapse;width:100%;font-size:var(--s0);white-space:nowrap}
th,td{text-align:start;padding:.75rem 1rem;border-bottom:1px solid var(--rule)}
th{color:var(--ink-3);font-weight:520}

.end{border-top:1px solid var(--rule);background:var(--paper-2);
  color:var(--ink-4);font-size:.8125rem}
.end .wrap{padding-block:2.5rem}
.end p + p{margin-top:.75rem}
.end .legal{display:flex;flex-wrap:wrap;gap:.5rem 1.25rem;margin-top:1.5rem}

/* Motion is a 6: things arrive, things respond, nothing loops. Every rule
   below is inside this query, so a reader who asked for less motion gets a
   page that is simply already in place rather than one that jerks. */
@media (prefers-reduced-motion:no-preference){
  .rise{animation:rise .55s cubic-bezier(.16,1,.3,1) both;
    animation-delay:calc(var(--i,0) * 70ms)}
  @keyframes rise{from{opacity:0;transform:translateY(14px)}
    to{opacity:1;transform:none}}

  /* Sections arrive as the reader reaches them. Staggered by position within
     the section so a shelf of forty cells reads as one movement rather than
     forty. */
  /* The headline figure lifts into place without its value ever changing. */
  .land{opacity:0;transform:translateY(.18em) scale(.985);filter:blur(6px);
    transition:opacity .5s cubic-bezier(.16,1,.3,1),
               transform .7s cubic-bezier(.16,1,.3,1),
               filter .5s cubic-bezier(.16,1,.3,1);
    transition-delay:calc(var(--i,0) * 90ms)}
  .land.landed{opacity:1;transform:none;filter:none}

  .reveal{opacity:0;transform:translateY(14px);will-change:opacity,transform;
    transition:opacity .55s cubic-bezier(.16,1,.3,1),
               transform .55s cubic-bezier(.16,1,.3,1)}
  .reveal.in{opacity:1;transform:none}

  /* The hero ground drifts a little slower than the page. Small on purpose:
     enough to give the headline something to sit in front of, not enough to
     make a reader notice they are being moved. */
  .hero{background-position:center calc(50% + var(--drift,0px))}
}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none}
}
/* Printing, and any renderer that does not scroll. `.in` is only ever added by
   the observer, so without this a printed page carried a hero and blank space
   where every price should have been. */
@media print{
  .reveal,.land{opacity:1 !important;transform:none !important;
    filter:none !important}
  .top,.cta,.calc{display:none}
  body{background:#fff;color:#000}
}
/* Drawn inside on tiles: their parent clips at its padding box, so an outline
   offset outwards was cut off entirely on every edge tile. */
:focus-visible{outline:2px solid var(--teal-lift);outline-offset:3px}
.bento .cell:focus-visible,.posts .post:focus-visible{outline-offset:-3px}
