/* ---------------------------------------------------------------------------
   Products page - Signal Doors opening.

   Promoted from `iterations/product-hero-signal-doors/` on 2026-07-31 at
   operator request. That route stays in place as the reference copy, and its
   README carries the reasoning, the texture recipe, the cable findings, and the
   shapes that were tried and thrown away.

   What this replaced: an orange field with a drawn grid, four decorative signal
   routes, a placeholder traffic figure, and a bottom strip of three tariff links
   that had no visible relation to the three headline words and no button
   identity at all.

   Colour and type tokens come from the :root block in style.css. Nothing global
   is defined here, only the local variables this surface needs.
   --------------------------------------------------------------------------- */

/* ---- The hero surface ---------------------------------------------------- */

.hero {
  --gutter: clamp(20px, 3.2vw, 46px);
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 100svh;
  color: var(--ink);
  background: var(--signal-orange);
}

/* The head bootstrap applies this state before the first paint. The main
   timeline replaces it with the same inline values when GSAP is ready. If the
   page script fails, the bootstrap removes the class after 2.5 seconds. Text
   and links remain in the document and can still receive focus. */
@media (prefers-reduced-motion: no-preference) {
  .product-motion-boot .hero__eyebrow {
    clip-path: inset(0 100% 0 0);
    transform: translateX(-12px);
  }

  .product-motion-boot .hero__word {
    clip-path: inset(-20% -8% 120% -8%);
  }

  .product-motion-boot .doors__slot {
    clip-path: inset(100% 0 0 0);
  }
}

/* ---- Field: texture only ------------------------------------------------
   Two material layers at different scales. One alone reads as a single tiled
   noise; two at different sizes give the surface depth without any drawn
   element. The cables are the only lines in this field, which is why there is
   no grid and no dot matrix behind them.

   Both assets were generated as neutral material, mapped onto the brand ramp
   with lutgen, and flattened with ImageMagick. The recipe is in README.md so
   the surface can be regenerated rather than guessed at.
   ------------------------------------------------------------------------- */

.hero__field {
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
}

.hero__ground,
.hero__grain {
  position: absolute;
  inset: 0;
  display: block;
}

/* The printed surface itself. The orange is baked into this asset rather than
   multiplied over the flat colour, because a grey texture on multiply drags
   the whole field towards brown and loses the brand orange. It carries the
   broad tonal drift of a rolled ink surface and nothing sharper: the first
   build put the full mottling here and the field read as stucco, competing
   with the type. The flat --signal-orange under it is the fallback if the
   asset fails to load. */
.hero__ground {
  background-image: url("../img/product/hero-ground.jpg");
  background-image: image-set(
    url("../img/product/hero-ground-v1.webp") type("image/webp"),
    url("../img/product/hero-ground.jpg") type("image/jpeg")
  );
  background-position: center;
  background-size: cover;
}

/* The surface tooth, which the flattened ground gives up. It tiles at a fixed
   size rather than stretching to cover, because cover scales the grain with
   the viewport and a hero at 2560px would show coarse blobs. The asset is a
   mirrored tile, so it repeats without a seam. */
.hero__grain {
  background-image: url("../img/product/hero-grain.jpg");
  background-image: image-set(
    url("../img/product/hero-grain-v1.webp") type("image/webp"),
    url("../img/product/hero-grain.jpg") type("image/jpeg")
  );
  background-position: center;
  background-repeat: repeat;
  background-size: 700px auto;
  mix-blend-mode: soft-light;
  opacity: 0.5;
}

.cables {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.cables path {
  fill: none;
  stroke-linecap: round;
}

/* ---- Type: the staircase ------------------------------------------------
   The offsets are not decoration. Each word is parked above its own door, so
   the diagonal is the three door positions read upward. That is the whole
   reason the title steps at all.
   ------------------------------------------------------------------------- */

/* The header is fixed and the hero starts underneath it, so the type block
   reserves its height. The route this came from used a stand-in element in the
   flex column for the same purpose. */
.hero__type {
  position: relative;
  z-index: 2;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
  padding: calc(var(--header-height) + 34px) var(--gutter) 0;
}

.hero__eyebrow {
  margin: 0 0 22px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.hero__eyebrow::after {
  display: block;
  width: 24px;
  height: 2px;
  margin-top: 10px;
  content: "";
  background: var(--ink);
}

.hero__title {
  display: flex;
  flex-direction: column;
  margin: 0;
  font-family: var(--font-display);
  /* The size is capped against viewport height as well as width. Width alone
     looks right on a 1440x1000 screen and overruns a 1280x600 one, because
     three lines at 0.84 leading are a fixed multiple of the font size while the
     frame the hero has to fit is not. */
  font-size: clamp(46px, min(9.8vw, 19svh), 158px);
  font-weight: 800;
  line-height: 0.84;
  letter-spacing: -0.045em;
}

.hero__word {
  display: block;
  width: fit-content;
  margin-left: var(--offset, 0);
}

/* Both offsets came back one character to the left at operator request. One
   character is about half the font size, which is 5.2% of the text box at the
   reference width, so 27% and 60% became 22% and 55%.

   They moved by the same amount on purpose. The dot of the capital I in İnternet
   and the full stop of Mesaj sit on adjacent lines at almost the same x, and
   below a 33-point gap between the two offsets they merge into one blob. Shifting
   both keeps that gap at 33 and keeps the clearance. */
.hero__word:nth-child(2) {
  --offset: 22%;
}

.hero__word:nth-child(3) {
  --offset: 55%;
}

/* The full stop is the terminal the cable leaves from, so it is a real element
   rather than a character inside a run of text. cables.js measures it. */
.hero__stop {
  display: inline-block;
}

/* Baseline probe. An empty inline-block with no in-flow content takes its
   baseline from its own bottom margin edge, so this element's bottom is exactly
   the text baseline of the line it sits on - which is the one measurement the
   DOM will not otherwise give you.

   It is needed because a span's box is as tall as the line box, and a full stop
   sits at the very bottom of that box. Measuring the span's centre started every
   cable well above the dot it was supposed to leave from. */
.hero__baseline {
  display: inline-block;
  width: 0;
  height: 0;
}

/* ---- The doors ----------------------------------------------------------
   Three graphite masses on a shared floor with staggered tops, so their
   skyline runs parallel to the title diagonal and closes the gap the live
   page leaves open. Each door carries real figures from the tariff sheets.
   ------------------------------------------------------------------------- */

.doors {
  position: relative;
  z-index: 2;
  display: grid;
  flex: 0 0 auto;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  align-items: end;
  margin: 0;
  padding: 0 var(--gutter) var(--gutter);
  list-style: none;
}

.doors__slot {
  display: flex;
  min-width: 0;
}

/* The steps are small - about 26px apart at 1440 - so the skyline still answers
   the title diagonal without any one door carrying much more air inside it than
   its neighbours. Heights are also capped against viewport height, because the
   whole hero has to fit one frame on a 768px-tall screen without scrolling. */
.doors__slot:nth-child(1) {
  --door-height: clamp(142px, min(14vw, 22svh), 216px);
}

.doors__slot:nth-child(2) {
  --door-height: clamp(128px, min(13vw, 20svh), 196px);
}

.doors__slot:nth-child(3) {
  --door-height: clamp(114px, min(12vw, 18svh), 176px);
}

/* space-between rather than a run of auto margins. The three doors are
   different heights, so the extra height has to go somewhere: distributed
   between the three rows it reads as air, pooled above the first row it reads
   as an empty card. */
.door {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
  height: var(--door-height);
  padding: 26px 28px 24px;
  color: var(--paper-bright);
  background: var(--graphite);
  text-decoration: none;
}

/* Cable gland. The cable from the word terminates on this fitting, so the join
   is a fitting rather than a line that stops in mid-air. cables.js measures the
   top centre of it. The first build made it 3px wide and it read as a pin, so
   the body is wide enough to look like it accepts the cable that lands on it
   and the collar sits on the door edge. */
.door__port {
  position: absolute;
  top: -17px;
  left: 32px;
  width: 7px;
  height: 17px;
  background: var(--graphite);
}

.door__port::before {
  position: absolute;
  bottom: 0;
  left: -7px;
  width: 21px;
  height: 8px;
  content: "";
  background: var(--graphite);
}

/* The hover drawing. It is parked against the right edge of the card, in the
   part the word and the price leave empty, and motifs.js sizes it from the card
   rather than from the viewport. currentColor means the ink follows the door: at
   rest the card is graphite, on hover it is paper and the drawing lands dark on
   light, which is when it is actually seen. */
.door__motif {
  position: absolute;
  top: 50%;
  right: 24px;
  overflow: visible;
  pointer-events: none;
  transform: translateY(-50%);
}

/* The word from the title, repeated verbatim, and the only name the door has.
   It is what removes the Ses-to-Telefon translation the live strip forces on the
   reader, and a separate title line under it would restate the same thing while
   pushing the rest of the card down. */
.door__word {
  font-family: var(--font-display);
  font-size: clamp(26px, 2.9vw, 46px);
  font-weight: 700;
  letter-spacing: -0.028em;
  line-height: 0.9;
}

.door__figure {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.door__price {
  font-family: var(--font-display);
  font-size: clamp(19px, 1.6vw, 25px);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.door__unit {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.66;
}

.door__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(250, 247, 240, 0.22);
}

.door__count {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.66;
}

.door__arrow {
  flex: 0 0 auto;
  width: 26px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-width: 1.4;
}

/* The open state. Hover and keyboard focus resolve to the same look, and
   cables.js energises the matching cable at the same moment, so touching a
   door shows the reader which word it belongs to. */
.door:hover,
.door:focus-visible {
  color: var(--ink);
  background: var(--paper-bright);
  outline: none;
}

.door:hover .door__unit,
.door:focus-visible .door__unit,
.door:hover .door__count,
.door:focus-visible .door__count {
  opacity: 0.62;
}

.door:hover .door__foot,
.door:focus-visible .door__foot {
  border-top-color: rgba(39, 20, 14, 0.26);
}

.door:hover .door__port,
.door:focus-visible .door__port,
.door:hover .door__port::before,
.door:focus-visible .door__port::before {
  background: var(--paper-bright);
}

.door:focus-visible {
  box-shadow: 0 0 0 3px var(--ink);
}

/* ---- Narrow ------------------------------------------------------------
   The staircase collapses and the doors stack. One cable runs down the left
   margin and lands on each door in turn, so the binding survives the width
   the diagonal cannot.
   ----------------------------------------------------------------------- */

@media (max-width: 860px) {
  /* The type block keeps the slack so the doors sit on the floor of the
     viewport. The first build gave the slack to nothing and left a third of the
     screen empty below the last door. */
  .hero__type {
    justify-content: flex-start;
    padding-top: calc(var(--header-height) + 30px);
    padding-bottom: 30px;
  }

  /* The staircase has to open up here. At 0.84 the lines overlap, and the
     narrow offsets put that overlap directly on top of the previous word, so
     Mesaj collided with Ses. */
  .hero__title {
    line-height: 0.95;
  }

  .hero__word:nth-child(2) {
    --offset: 7%;
  }

  .hero__word:nth-child(3) {
    --offset: 14%;
  }

  .doors {
    grid-template-columns: 1fr;
    gap: 12px;
    padding-left: calc(var(--gutter) + 26px);
  }

  .doors__slot:nth-child(1),
  .doors__slot:nth-child(2),
  .doors__slot:nth-child(3) {
    --door-height: auto;
  }

  .door {
    flex-direction: row;
    align-items: center;
    gap: 16px;
    padding: 18px 20px;
  }

  .door__port {
    top: 50%;
    left: -26px;
    width: 26px;
    height: 3px;
    transform: translateY(-50%);
  }

  .door__port::before {
    top: -4px;
    left: -2px;
    width: 6px;
    height: 11px;
  }

  /* The word stays and stays large. It is the one element that ties the door to
     its headline word, so shrinking it away here would reinstate on a phone the
     exact fault this route exists to repair. */
  .door__word {
    flex: 0 0 auto;
    font-size: 26px;
  }

  .door__figure {
    flex: 0 0 auto;
    flex-direction: column;
    gap: 1px;
    margin: 0 0 0 auto;
    text-align: right;
  }

  .door__unit {
    white-space: nowrap;
  }

  /* display: contents dissolves the foot so its two children join the row as
     siblings of the word and the price. The count then sits beside the word it
     qualifies, and the arrow stays last, without the markup having to differ
     between the two layouts. The count used to be hidden here, which meant a
     phone showed one fact fewer than a desktop for no reason. */
  .door__foot {
    display: contents;
  }

  .door__word {
    order: 1;
  }

  .door__count {
    order: 2;
    padding-left: 12px;
  }

  .door__figure {
    order: 3;
  }

  .door__arrow {
    order: 4;
    margin-left: 14px;
  }
}

/* ---- Short viewports ---------------------------------------------------
   The hero has to be one frame: everything visible, and the next scroll goes to
   the tariff sheets rather than to the rest of the opening. The svh caps on the
   title and the doors hold that on their own down to 1280x720 and 390x844, but a
   360x640 screen still cut 58px, so the chrome, the paddings and the door
   interiors all tighten together there. Nothing is hidden - a short screen still
   shows every word.
   ----------------------------------------------------------------------- */

/* ---- Very narrow ---------------------------------------------------------
   One row cannot hold a word, a count, a price with its unit, and an arrow at
   this width: the row overruns and the arrow is pushed outside the card. So the
   card takes two rows here rather than shaving type sizes until something
   breaks. Nothing is dropped - every fact a wide card shows, a 360px card shows
   as well.
   ------------------------------------------------------------------------- */

@media (max-width: 430px) {
  .door {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px 14px;
    padding: 14px 18px 12px;
  }

  /* The order values have to be restated. They were set for the single-row flex
     layout, they apply to grid auto-placement as well, and the foot has no order
     of its own - so without these three lines the count and the arrow sort ahead
     of the word and the card prints its footer first. */
  .door__word {
    order: 1;
    grid-column: 1;
    font-size: 23px;
  }

  .door__figure {
    order: 2;
    grid-column: 2;
  }

  /* A real element again, because it is now its own row. */
  .door__foot {
    display: flex;
    order: 3;
    grid-column: 1 / -1;
    margin: 0;
    padding-top: 10px;
    border-top: 1px solid rgba(250, 247, 240, 0.22);
  }

  .door__count {
    padding: 0;
  }

  .door__arrow {
    margin: 0;
  }

  .door:hover .door__foot,
  .door:focus-visible .door__foot {
    border-top-color: rgba(39, 20, 14, 0.26);
  }
}

@media (max-height: 740px) {
  .hero__type {
    padding-top: calc(var(--header-height) + 8px);
  }

  .hero__eyebrow {
    margin-bottom: 14px;
  }

  .doors {
    gap: 12px;
  }

  .door {
    padding: 16px 22px 14px;
  }
}

/* Narrow and short together. Here the doors are a stacked column rather than a
   row, so their three heights add up instead of sitting side by side, and the
   block above has to give up more than the wide case does. */
@media (max-height: 740px) and (max-width: 860px) {
  .hero__type {
    padding-top: calc(var(--header-height) + 16px);
    padding-bottom: 16px;
  }

  .doors {
    gap: 8px;
  }

  .door {
    padding: 14px 18px;
  }

  .door__word {
    font-size: 22px;
  }
}

/* Short and very narrow. The two-row card costs height that a 360x640 screen
   does not have, so the interiors tighten once more. This is the tightest case
   the route supports and it still shows every word, every price and every
   count in one frame. */
@media (max-height: 740px) and (max-width: 430px) {
  .hero__eyebrow {
    margin-bottom: 10px;
  }

  .doors {
    gap: 6px;
  }

  .door {
    gap: 6px 12px;
    padding: 10px 16px 8px;
  }

  .door__word {
    font-size: 20px;
  }

  .door__foot {
    padding-top: 6px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cables path {
    transition: none;
  }
}

/* ---- Condition detail dialog -------------------------------------------

   The rows stay native details elements without JavaScript. The enhanced page
   uses their same copy in one independent bottom dialog, so long conditions do
   not make a tariff frame scroll internally.
   ------------------------------------------------------------------------- */

.ledger.has-condition-modal .rail-toggle,
.ledger.has-condition-modal .cond__body {
  display: none;
}

.ledger.has-condition-modal .cond__row {
  margin-inline: -8px;
  padding-inline: 8px;
  transition:
    color 180ms ease,
    background-color 180ms ease;
}

.ledger.has-condition-modal .cond__row:hover,
.ledger.has-condition-modal .cond__row:focus,
.ledger.has-condition-modal .cond__row:focus-visible,
.ledger.has-condition-modal .cond.is-modal-active > .cond__row {
  color: var(--paper-bright);
  background: rgba(240, 89, 31, 0.14);
}

.ledger.has-condition-modal .cond__row:hover::after,
.ledger.has-condition-modal .cond__row:focus::after,
.ledger.has-condition-modal .cond__row:focus-visible::after,
.ledger.has-condition-modal .cond.is-modal-active > .cond__row::after {
  color: var(--signal-orange-invert);
}

.condition-modal {
  position: fixed;
  top: auto;
  right: 0;
  bottom: clamp(12px, 2.5vh, 28px);
  left: 0;
  width: min(720px, calc(100% - 32px));
  max-width: none;
  max-height: min(68svh, 620px);
  margin: 0 auto;
  padding: 0;
  overflow: auto;
  border: 1px solid rgba(255, 124, 66, 0.72);
  color: var(--paper-bright);
  background: var(--graphite);
  box-shadow: 0 26px 90px rgba(0, 0, 0, 0.48);
  font-family: var(--font-ui);
}

.condition-modal::backdrop {
  background: rgba(20, 14, 10, 0.68);
  backdrop-filter: blur(3px);
}

.condition-modal__bar {
  position: sticky;
  z-index: 1;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 12px 14px 12px 22px;
  border-bottom: 1px solid var(--ledger-line-strong);
  background: var(--graphite);
}

.condition-modal__context {
  margin: 0;
  color: var(--signal-orange-invert);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.condition-modal__close {
  min-width: 76px;
  min-height: 38px;
  padding: 8px 13px;
  border: 1px solid var(--ledger-line-strong);
  color: var(--paper-bright);
  background: transparent;
  font: 600 9px/1 var(--font-ui);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
}

.condition-modal__close:hover,
.condition-modal__close:focus-visible {
  color: var(--ink);
  background: var(--signal-orange);
  outline: none;
}

.condition-modal__content {
  padding: clamp(24px, 5vw, 46px);
}

.condition-modal__title {
  margin: 0;
  color: var(--paper-bright);
  font-family: var(--font-display);
  font-size: clamp(30px, 5vw, 54px);
  font-weight: 430;
  letter-spacing: -0.035em;
  line-height: 0.98;
}

.condition-modal__lead {
  max-width: 58ch;
  margin: 22px 0 0;
  color: var(--paper-bright);
  font-size: clamp(13px, 1.25vw, 16px);
  font-weight: 500;
  line-height: 1.55;
}

.condition-modal__lead strong {
  color: var(--signal-orange-invert);
  font-weight: 650;
}

.condition-modal__body {
  max-width: 68ch;
  margin: 18px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--ledger-line-strong);
  color: var(--muted-invert);
  font-size: clamp(12px, 1.1vw, 14px);
  font-weight: 500;
  line-height: 1.75;
}

/* Long connectivity product names keep a full two-line name field. The card
   width does not change, so all ten products remain in the same frame. */
@media (min-width: 1280px) {
  .ledger.is-framed #internet-tarifeleri .tariff-card__name {
    min-height: 2.55em;
    overflow-wrap: normal;
    font-size: clamp(11.5px, 0.9vw, 13px);
    line-height: 1.24;
    word-break: normal;
  }
}

@media (max-width: 600px) {
  .condition-modal {
    bottom: 8px;
    width: calc(100% - 16px);
    max-height: calc(100svh - 80px);
  }

  .condition-modal__bar {
    padding-left: 14px;
  }

  .condition-modal__context {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .condition-modal__content {
    padding: 24px 20px 30px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ledger.has-condition-modal .cond__row {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   Viewport tariff frames.

   JavaScript adds .is-framed only when GSAP motion is available and motion is
   permitted. The unenhanced and reduced-motion page keeps the complete natural
   document above. In the enhanced page the ledger is one pinned viewport. The
   three sheets occupy the same frame and move through it in both directions.
   ------------------------------------------------------------------------- */

/* The product header always has an opaque surface. The colour follows the
   section below it, but copy and figures can never pass behind the controls.
   The shared footer scene is still the only place that hides the header. */
.site-header::before {
  opacity: 1;
}

.site-header[data-theme="signal"]::before {
  background: var(--signal-orange);
}

.site-header[data-theme="light"]::before,
.site-header.is-menu-open::before {
  background: var(--paper-bright);
}

.site-header[data-theme="dark"]::before {
  background: var(--graphite);
}

.site-header.is-tariff-frame {
  --nav-color: var(--paper-bright);
  --nav-divider: rgba(255, 255, 255, 0.22);
  --nav-hover: rgba(255, 255, 255, 0.1);
  --cta-bg: var(--paper-bright);
  --cta-color: var(--graphite);
}

.site-header.is-tariff-frame::before {
  background: var(--graphite);
}

.site-header.is-tariff-frame .brand__logo--light {
  opacity: 1;
  transform: none;
}

.site-header.is-tariff-frame .brand__logo--color {
  opacity: 0;
}

.site-header.is-tariff-frame .brand__word-cloud {
  color: var(--paper-bright);
}

.site-header.is-tariff-frame .brand__word-cell {
  color: var(--signal-orange-invert);
}

.site-header.is-menu-open > .ledger__top.is-header-dock {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

.sheet__compact-controls,
.rail__close {
  display: none;
}

.ledger.is-handoff-ready .ledger__top,
.ledger.is-framed .ledger__top,
.ledger__top.is-header-dock {
  position: fixed;
  z-index: 52;
  top: 0;
  right: var(--tariff-nav-right, 228px);
  left: var(--tariff-nav-left, 240px);
  display: block;
  height: var(--header-height);
  padding: 0;
  border-bottom: 1px solid var(--ledger-line-strong);
  background: var(--graphite);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.ledger.is-handoff-ready .ledger__tabs,
.ledger.is-framed .ledger__tabs,
.ledger__top.is-header-dock .ledger__tabs {
  height: 100%;
  border-top: 0;
  border-bottom: 0;
}

.ledger.is-handoff-ready .ledger-tab,
.ledger.is-framed .ledger-tab,
.ledger__top.is-header-dock .ledger-tab {
  justify-content: center;
  padding: 0 18px;
}

.ledger.is-framed {
  --ledger-foot-height: 76px;
  position: relative;
  isolation: isolate;
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
  padding: 0;
}

.ledger.is-framed::after {
  position: absolute;
}

.ledger.is-framed .sheet {
  position: absolute;
  z-index: 1;
  top: var(--header-height);
  right: 0;
  bottom: var(--ledger-foot-height);
  left: 0;
  display: flex;
  min-height: 0;
  flex-direction: column;
  overflow: hidden;
  border: 0;
  background: var(--graphite);
  scroll-margin-top: 0;
}

.ledger.is-framed #sms-tarifeleri {
  z-index: 2;
  transform: translate3d(0, 100%, 0);
}

.ledger.is-framed #internet-tarifeleri {
  z-index: 3;
  transform: translate3d(0, 100%, 0);
}

.ledger.is-framed .sheet[aria-hidden="true"] {
  pointer-events: none;
}

.ledger.is-framed .sheet__head {
  display: flex;
  min-height: 54px;
  flex: 0 0 54px;
  align-items: center;
  gap: 18px;
  padding: 11px var(--ledger-gutter) 10px;
  border-bottom: 1px solid var(--ledger-line);
}

.ledger.is-framed .sheet__title {
  font-size: 13px;
}

.ledger.is-framed .sheet__hint {
  font-size: 9px;
}

.ledger.is-framed .sheet__body {
  display: grid;
  min-height: 0;
  flex: 1 1 auto;
  grid-template-columns: minmax(0, 1fr) clamp(310px, 22vw, 340px);
  grid-template-rows: minmax(0, 1fr) auto;
  overflow: hidden;
}

@media (min-width: 1280px) {
  .ledger.is-framed .sheet .sheet__grid {
    --stride-open: clamp(22px, 2.4vw, 34px);
    --stride-y: var(--stride-open);
    grid-column: 1;
    grid-row: 1;
    height: 100%;
    min-height: 0;
    align-content: start;
    padding: 16px 14px 10px var(--ledger-gutter);
    overflow: hidden;
  }

  .ledger.is-framed .sheet .tariff-card {
    align-self: flex-start;
    padding: 11px 10px 12px;
  }

  .ledger.is-framed .sheet .tariff-card__tag {
    font-size: 9.5px;
    letter-spacing: 0.04em;
  }

  .ledger.is-framed .sheet .tariff-card__name {
    margin-bottom: 9px;
    font-size: clamp(12.5px, 0.98vw, 14px);
    line-height: 1.22;
  }

  .ledger.is-framed .sheet .tariff-card__value[data-w] {
    font-size: clamp(20px, 1.9vw, 29px);
  }

  .ledger.is-framed .sheet .tariff-card__value[data-w="l"] {
    font-size: clamp(19px, 1.65vw, 24px);
  }

  .ledger.is-framed .sheet .tariff-card__value[data-w="xl"] {
    font-size: clamp(17.5px, 1.4vw, 21px);
  }

  .ledger.is-framed .sheet .tariff-card__unit {
    font-size: 9.5px;
  }

  .ledger.is-framed .sheet .tariff-card__spec {
    gap: 4px;
    margin-top: 10px;
    padding-top: 9px;
  }

  .ledger.is-framed .sheet .tariff-card__spec li {
    font-size: 10.25px;
    line-height: 1.42;
  }

  .ledger.is-framed .sheet .tariff-card__foot {
    gap: 8px;
    margin-top: 11px;
    padding-top: 9px;
  }

  .ledger.is-framed .sheet .tariff-card__price {
    display: block;
    font-size: 18.5px;
  }

  .ledger.is-framed .sheet .tariff-card__price span {
    display: block;
    margin: 2px 0 0;
    font-size: 8.5px;
  }

  .ledger.is-framed .sheet .tariff-card__cta {
    font-size: 9.5px;
  }

  .ledger.is-framed .rail {
    display: contents;
  }

  .ledger.is-framed .rail__main {
    display: grid;
    grid-column: 2;
    grid-row: 1 / 3;
    height: 100%;
    min-height: 0;
    align-content: start;
    align-self: stretch;
    gap: 14px;
    grid-template-columns: minmax(0, 1fr);
    padding: 18px 20px 16px;
    overflow: auto;
    border-top: 0;
    border-left: 1px solid var(--ledger-line);
    background: var(--graphite);
    scrollbar-color: var(--ledger-line-strong) transparent;
    scrollbar-width: thin;
  }

  .ledger.is-framed .sheet__lower {
    display: grid;
    grid-column: 1;
    grid-row: 2;
    min-height: 152px;
    gap: clamp(24px, 3vw, 48px);
    padding: 17px var(--ledger-gutter) 14px;
    overflow: hidden;
    border-top: 1px solid var(--ledger-line-strong);
    background: rgba(255, 255, 255, 0.018);
  }

  .ledger.is-framed .sheet__lower--voice {
    grid-template-columns: minmax(250px, 0.72fr) minmax(0, 1.28fr);
  }

  .ledger.is-framed .sheet__lower--messaging {
    grid-template-columns: minmax(0, 1.45fr) minmax(260px, 0.55fr);
  }

  .ledger.is-framed .sheet__lower--connectivity {
    display: block;
  }

  .ledger.is-framed .sheet__lower > .rail-block {
    min-width: 0;
    margin: 0;
  }

  .ledger.is-framed .rail__main .rail__title {
    margin: 0;
    font-size: 12px;
  }

  .ledger.is-framed .rail__main .rail-block,
  .ledger.is-framed .rail__main .limit {
    max-width: none;
    margin: 0;
  }

  .ledger.is-framed .rail-block__title {
    margin-bottom: 9px;
    font-size: 10px;
    letter-spacing: 0.15em;
  }

  .ledger.is-framed .meter {
    gap: 2px;
    padding: 8px 10px;
  }

  .ledger.is-framed .meter__value {
    font-size: 26px;
  }

  .ledger.is-framed .meter__unit,
  .ledger.is-framed .meter__label {
    font-size: 9.5px;
  }

  .ledger.is-framed .cond__row {
    gap: 3px 10px;
    padding: 8px 0;
  }

  .ledger.is-framed .cond__name {
    font-size: 10.5px;
    letter-spacing: 0.1em;
  }

  .ledger.is-framed .cond__lead,
  .ledger.is-framed .cond__body {
    font-size: 10.75px;
    line-height: 1.45;
  }

  .ledger.is-framed .cond__body {
    padding: 0 10px 8px 12px;
  }

  .ledger.is-framed .rail-toggle {
    margin-top: 7px;
    padding: 7px 9px;
    font-size: 8px;
  }

  .ledger.is-framed .ladder__step {
    gap: 7px;
    grid-template-columns: 34px minmax(0, 1fr) 30px;
    padding: 3px 0;
  }

  .ledger.is-framed .ladder__term,
  .ledger.is-framed .ladder__value,
  .ledger.is-framed .timeline__key {
    font-size: 10.5px;
  }

  .ledger.is-framed .timeline__month {
    gap: 7px;
    font-size: 9.5px;
  }

  .ledger.is-framed .timeline__legend {
    gap: 9px;
    margin-top: 7px;
  }

  .ledger.is-framed .validity__figure {
    gap: 5px;
    margin-bottom: 9px;
    font-size: 10.5px;
  }

  .ledger.is-framed .validity__figure span {
    font-size: 38px;
  }

  .ledger.is-framed .validity__track {
    gap: 2px;
  }

  .ledger.is-framed .validity__track li {
    height: 14px;
  }

  .ledger.is-framed .validity__note,
  .ledger.is-framed .flags__note {
    margin-top: 8px;
    font-size: 10.75px;
    line-height: 1.45;
  }

  .ledger.is-framed .scope__cell {
    padding: 8px;
  }

  .ledger.is-framed .scope__cell dt {
    font-size: 9.5px;
  }

  .ledger.is-framed .scope__cell dd {
    margin-top: 7px;
    font-size: 14px;
  }

  .ledger.is-framed .flags li {
    gap: 2px;
    padding: 6px 0;
  }

  .ledger.is-framed .flags__name {
    font-size: 10px;
  }

  .ledger.is-framed .curve__row {
    gap: 7px;
    grid-template-columns: 30px minmax(0, 1fr) 34px;
    padding: 3px 0;
  }

  .ledger.is-framed .curve__name,
  .ledger.is-framed .curve__value {
    font-size: 10px;
  }

  .ledger.is-framed .limit {
    grid-column: 1 / -1;
    gap: 9px;
    padding: 7px 10px;
  }

  .ledger.is-framed .limit__mark {
    font-size: 27px;
  }

  .ledger.is-framed .limit__label {
    font-size: 10px;
  }

  .ledger.is-framed .sheet__lower--connectivity .fees {
    display: block;
  }

  .ledger.is-framed .sheet__lower--connectivity .fees caption {
    display: block;
    width: 100%;
  }

  .ledger.is-framed .sheet__lower--connectivity .fees tbody {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    border-top: 1px solid var(--ledger-line);
    border-left: 1px solid var(--ledger-line);
  }

  .ledger.is-framed .sheet__lower--connectivity .fees tr {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 4px;
    padding: 8px 12px;
    border-top: 0;
    border-right: 1px solid var(--ledger-line);
    border-bottom: 1px solid var(--ledger-line);
  }

  .ledger.is-framed .sheet__lower--connectivity .fees th,
  .ledger.is-framed .sheet__lower--connectivity .fees td {
    display: block;
    padding: 0;
    font-size: 11px;
    text-align: left;
  }

  .ledger.is-framed .sheet__lower--connectivity .fees td {
    color: var(--paper-bright);
    font-size: 13px;
  }

  .ledger.is-framed .perks {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ledger.is-framed .perks li {
    gap: 8px;
    padding: 7px 9px;
  }

  .ledger.is-framed .perks__value {
    font-size: 13px;
  }

  .ledger.is-framed .perks__label {
    font-size: 10px;
  }
}

.ledger.is-framed .ledger__foot {
  position: absolute;
  z-index: 5;
  right: 0;
  bottom: 0;
  left: 0;
  display: grid;
  height: var(--ledger-foot-height);
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  gap: 18px;
  padding: 10px var(--ledger-gutter);
  border-top: 1px solid var(--ledger-line-strong);
  background: var(--graphite);
}

.ledger.is-framed .ledger__foot-note {
  max-width: 86ch;
  font-size: 9px;
  line-height: 1.45;
}

/* The compact frame uses a plan switcher. One complete plan is visible at a
   time. The conditions surface opens over the same frame, so vertical page
   movement continues to mean a tariff-type change. */
@media (max-width: 1279px) {
  .ledger.is-framed {
    --ledger-foot-height: 70px;
    min-height: 540px;
  }

  .ledger.is-framed .sheet__body {
    position: relative;
    display: flex;
    min-height: 0;
    flex-direction: column;
    padding: 10px var(--ledger-gutter) 8px;
    overflow: hidden;
  }

  .ledger.is-framed .rail__main {
    display: block;
  }

  .ledger.is-framed .sheet__lower {
    display: grid;
    gap: 24px;
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--ledger-line-strong);
  }

  .ledger.is-framed .sheet__lower--voice,
  .ledger.is-framed .sheet__lower--messaging {
    grid-template-columns: minmax(0, 1fr);
  }

  .ledger.is-framed .sheet__lower--connectivity {
    display: block;
  }

  .ledger.is-framed .sheet__lower > .rail-block {
    margin: 0;
  }

  .ledger.is-framed .sheet__compact-controls {
    display: grid;
    flex: 0 0 auto;
    gap: 7px;
    grid-template-columns: minmax(0, 1fr) auto;
    margin-bottom: 9px;
  }

  .ledger.is-framed .sheet__plan-picker {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: repeat(var(--picker-columns, 5), minmax(0, 1fr));
    border-top: 1px solid var(--ledger-line-strong);
    border-left: 1px solid var(--ledger-line-strong);
  }

  .ledger.is-framed .sheet__plan-button {
    min-width: 0;
    padding: 7px 3px;
    border: 0;
    border-right: 1px solid var(--ledger-line-strong);
    border-bottom: 1px solid var(--ledger-line-strong);
    color: var(--muted-invert);
    background: transparent;
    font-family: var(--font-ui);
    font-size: 8.5px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    cursor: pointer;
  }

  .ledger.is-framed .sheet__plan-button[aria-pressed="true"] {
    color: var(--ink);
    background: var(--signal-orange);
  }

  .ledger.is-framed .sheet__rail-trigger {
    grid-column: 2;
    padding: 8px 11px;
    border: 1px solid var(--ledger-line-strong);
    color: var(--paper-bright);
    background: transparent;
    font-family: var(--font-ui);
    font-size: 8px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: pointer;
  }

  .ledger.is-framed .sheet__grid {
    display: block;
    min-height: 0;
    flex: 1 1 auto;
    padding: 0;
    overflow: hidden;
  }

  .ledger.is-framed .sheet .tariff-card {
    display: grid;
    width: 100%;
    height: 100%;
    min-height: 0;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    align-content: start;
    gap: 0 18px;
    margin: 0;
    padding: clamp(14px, 3.5vh, 28px);
    border-left-width: 1px;
  }

  .ledger.is-framed .sheet .tariff-card[hidden] {
    display: none;
  }

  .ledger.is-framed .tariff-card__head,
  .ledger.is-framed .tariff-card__name {
    grid-column: 1;
  }

  .ledger.is-framed .tariff-card__head {
    margin-bottom: 5px;
  }

  .ledger.is-framed .tariff-card__name {
    margin-bottom: 10px;
    font-size: clamp(15px, 3.8vw, 22px);
  }

  .ledger.is-framed .tariff-card__figure {
    grid-column: 2;
    grid-row: 1 / 3;
    min-height: 0;
    align-self: start;
    justify-self: end;
    margin: 0;
  }

  .ledger.is-framed .tariff-card__value[data-w] {
    font-size: clamp(34px, 10vw, 60px);
  }

  .ledger.is-framed .tariff-card__spec {
    grid-column: 1 / -1;
    grid-row: 3;
    align-self: center;
    gap: 8px;
    margin: 12px 0;
    padding-top: 14px;
    font-size: 11px;
  }

  .ledger.is-framed .tariff-card__spec li {
    font-size: 11px;
  }

  .ledger.is-framed .tariff-card__foot {
    grid-column: 1 / -1;
    grid-row: 4;
    margin-top: 0;
    padding-top: 13px;
  }

  .ledger.is-framed .tariff-card__price {
    font-size: clamp(24px, 6.5vw, 36px);
  }

  .ledger.is-framed .rail {
    position: absolute;
    z-index: 8;
    inset: 0;
    display: block;
    height: auto;
    padding: 12px 18px 24px;
    overflow: auto;
    border: 0;
    background: var(--graphite);
    opacity: 0;
    transform: translateX(100%);
    visibility: hidden;
    pointer-events: none;
  }

  .ledger.is-framed .sheet.is-rail-open .rail {
    opacity: 1;
    transform: translateX(0);
    visibility: visible;
    pointer-events: auto;
  }

  .ledger.is-framed .rail__close {
    position: sticky;
    z-index: 2;
    top: -12px;
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: space-between;
    margin: 0 0 14px;
    padding: 11px 0;
    border: 0;
    border-bottom: 1px solid var(--ledger-line-strong);
    color: var(--paper-bright);
    background: var(--graphite);
    font-family: var(--font-ui);
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
  }

  .ledger.is-framed .rail-toggle {
    display: none;
  }

  .ledger.is-framed .ledger__foot {
    gap: 10px;
    padding: 8px var(--ledger-gutter);
  }

  .ledger.is-framed .ledger__foot-note {
    font-size: 7.5px;
    line-height: 1.35;
  }

}

@media (max-width: 820px) {
  .ledger.is-handoff-ready .ledger__top,
  .ledger.is-framed .ledger__top,
  .ledger__top.is-header-dock {
    top: var(--header-height);
    right: 0;
    left: 0;
    height: 44px;
  }

  .ledger.is-handoff-ready .ledger-tab,
  .ledger.is-framed .ledger-tab,
  .ledger__top.is-header-dock .ledger-tab {
    padding: 0 8px;
  }

  .ledger.is-framed .sheet {
    top: calc(var(--header-height) + 44px);
  }

  .ledger.is-framed .sheet__head {
    min-height: 44px;
    flex-basis: 44px;
    flex-wrap: nowrap;
    gap: 10px;
    padding: 7px var(--ledger-gutter);
  }

  .ledger.is-framed .sheet__hint {
    flex-basis: auto;
    overflow: hidden;
    padding-left: 10px;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

@media (max-width: 430px), (max-height: 700px) and (max-width: 1279px) {
  .ledger.is-framed {
    --ledger-foot-height: 0px;
  }

  .ledger.is-framed .sheet__body {
    padding-top: 7px;
  }

  .ledger.is-framed .sheet__compact-controls {
    gap: 5px;
    margin-bottom: 6px;
  }

  .ledger.is-framed .sheet__plan-button {
    padding: 5px 2px;
    font-size: 7.5px;
  }

  .ledger.is-framed .sheet .tariff-card {
    padding: 12px 14px;
  }

  .ledger.is-framed .tariff-card__spec {
    gap: 4px;
    margin: 6px 0;
    padding-top: 8px;
  }

  .ledger.is-framed .ledger__foot {
    display: none;
  }
}

@media (min-width: 1280px) and (max-height: 820px) {
  .ledger.is-framed {
    --ledger-foot-height: 58px;
  }

  .ledger.is-framed .sheet__head {
    min-height: 42px;
    flex-basis: 42px;
    padding-top: 6px;
    padding-bottom: 6px;
  }

  .ledger.is-framed .sheet .sheet__grid {
    --stride-open: clamp(15px, 2.2vh, 18px);
    padding-top: 8px;
    padding-bottom: 6px;
  }

  .ledger.is-framed .sheet .tariff-card {
    padding-top: 7px;
    padding-bottom: 8px;
  }

  .ledger.is-framed .sheet .tariff-card__name {
    margin-bottom: 6px;
  }

  .ledger.is-framed .sheet .tariff-card__spec {
    margin-top: 7px;
    padding-top: 7px;
  }

  .ledger.is-framed .sheet .tariff-card__foot {
    gap: 6px;
    margin-top: 7px;
    padding-top: 7px;
  }

  .ledger.is-framed .rail__main {
    gap: 6px;
    padding-right: 16px;
    padding-left: 16px;
    padding-top: 9px;
    padding-bottom: 8px;
  }

  .ledger.is-framed .sheet__lower {
    min-height: 124px;
    gap: clamp(18px, 2.4vw, 34px);
    padding-top: 10px;
    padding-bottom: 8px;
  }

  .ledger.is-framed .rail-block__title {
    margin-bottom: 6px;
  }

  .ledger.is-framed .meter {
    padding-top: 6px;
    padding-bottom: 6px;
  }

  .ledger.is-framed .cond__row {
    padding-top: 5px;
    padding-bottom: 5px;
  }

  .ledger.is-framed .rail-toggle {
    margin-top: 4px;
    padding-top: 5px;
    padding-bottom: 5px;
  }

  .ledger.is-framed .flags li,
  .ledger.is-framed .perks li {
    padding-top: 5px;
    padding-bottom: 5px;
  }

  .ledger.is-framed .sheet__lower--connectivity .fees tr {
    padding-top: 6px;
    padding-bottom: 6px;
  }
}

/* ---------------------------------------------------------------------------
   Tariff operations ledger.

   Direction: docs/research/pricing-directions/01-tariff-operations-ledger.png

   Ground rules for this block. The ledger is one graphite plate carrying three
   sheets. A sheet is a card grid plus a rail, and the two never share a scale:
   the grid is the loud side (one measured figure per card, set large), the
   rail is the quiet side (11px stencil labels, hairline rules, no display
   type). That split is what keeps 28 cards and three pages of legal text on
   the same plate without either one shouting the other down.

   Rails are deliberately not interchangeable. Each one is built for the notes
   it carries, so the three do not read as one component filled three times.
   --------------------------------------------------------------------------- */

.ledger {
  --ledger-line: rgba(255, 255, 255, 0.12);
  --ledger-line-strong: rgba(255, 255, 255, 0.2);
  --ledger-figure: #8d7d70;
  --ledger-gutter: clamp(20px, 3vw, 40px);
  --rail-width: 372px;
  position: relative;
  padding-bottom: 0;
  color: var(--paper-bright);
  background: var(--graphite);
  font-family: var(--font-ui);
}

/* The plate reads as printed stock, same treatment as the orange hero. */
.ledger::after {
  position: absolute;
  z-index: 0;
  inset: 0;
  content: "";
  background-image: var(--grain);
  background-size: 220px 220px;
  opacity: 0.035;
  pointer-events: none;
}

.ledger > * {
  position: relative;
  z-index: 1;
}

/* ---- Top bar: title, sticky sheet navigator, clock ---------------------- */

.ledger__top {
  position: sticky;
  z-index: 6;
  /* The site header is fixed and transparent: it takes its ink from whatever
     is behind it. Parking the navigator at the header's lower edge would let
     the card grid scroll through that strip and print spec lines across the
     brand mark. The navigator sticks to the very top instead and reserves the
     header's height as its own padding, so the strip is always this bar's own
     ground while the ledger is on screen. */
  top: 0;
  display: grid;
  align-items: center;
  /* One column. It was three - a mark, the navigator and the clock - and when the
     mark and the clock were removed the navigator inherited the mark's 220px
     column and ellipsised all three labels to "Tel... SM... INT...". */
  grid-template-columns: minmax(0, 1fr);
  padding: calc(var(--header-height) + 22px) var(--ledger-gutter) 22px;
  border-bottom: 1px solid var(--ledger-line);
  background: var(--graphite);
}

.ledger__tabs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--ledger-line-strong);
}

.ledger-tab {
  display: flex;
  align-items: center;
  padding: 15px 18px;
  border-left: 1px solid var(--ledger-line-strong);
  color: var(--muted-invert);
  text-decoration: none;
  transition:
    color 0.2s ease,
    background-color 0.2s ease;
}

.ledger-tab:first-child {
  border-left: 0;
}

.ledger-tab__label {
  overflow: hidden;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.ledger-tab:hover,
.ledger-tab:focus-visible {
  color: var(--paper-bright);
  background: rgba(255, 255, 255, 0.06);
}

/* Set by product.js from the sheet currently under the top bar. */
/* Dark ink on the orange, not paper. Light ink on --signal-orange measures
   3.19:1 and this tab is 15px, so the one control that reports which sheet is
   open was the least readable text on the page. --ink carries 5.16:1 on the
   same surface, and DEC-014 already records that this palette cannot take
   light nav ink on orange. */
.ledger-tab.is-active {
  color: var(--ink);
  background: var(--signal-orange);
}

/* ---- Sheet -------------------------------------------------------------- */

.sheet {
  border-bottom: 1px solid var(--ledger-line);
  /* The fixed header plus the sticky navigator must not cover a sheet heading
     when a tab is clicked. product.js measures both and writes the offset. */
  scroll-margin-top: var(--ledger-offset, 180px);
}

.sheet__head {
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 34px var(--ledger-gutter) 20px;
}

.sheet__title {
  margin: 0;
  color: var(--signal-orange-invert);
  font-family: var(--font-ui);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.sheet__signal {
  display: none;
  width: clamp(148px, 14vw, 196px);
  height: 34px;
  color: var(--signal-orange-invert);
}

.ledger.has-sheet-signals .sheet__title {
  position: relative;
  min-width: clamp(148px, 14vw, 196px);
}

.ledger.has-sheet-signals .sheet__title-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  white-space: nowrap;
}

.ledger.has-sheet-signals .sheet__signal {
  display: block;
}

.sheet__signal svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.sheet__signal path,
.sheet__signal line,
.sheet__signal polyline {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2.25;
  vector-effect: non-scaling-stroke;
}

.sheet__signal circle,
.sheet__signal rect {
  fill: currentColor;
}

.sheet__hint {
  flex: 1 1 auto;
  margin: 0;
  padding-left: 20px;
  border-left: 1px solid var(--ledger-line);
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.sheet__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--rail-width);
}

/* ---- The two arrangements of a sheet ------------------------------------

   Direction: runtime/tariff-directions/T4-tier-steps.png, operator choice,
   2026-07-31, with the focus mechanic the operator asked for on top of it.

   A sheet has two arrangements and the same content in both. Closed, it is the
   grid it always was. Focused, its packages fan out into a flight of steps that
   descends as the quantity grows, and the empty triangle the flight leaves at the
   lower left is the negative space this section had none of.

   Nothing is ever hidden. The direction frame collapsed two of the three sheets
   behind an ellipsis, and the ledger's own contract - stated in product.js - is
   that the sheets are a flow and not a tab panel set. So focus changes the
   arrangement of a sheet and never the amount of it: all 28 packages are on the
   page, readable, at every moment.

   A sheet that opens stays open. Closing one on the way past would shrink a block
   that is above the viewport and pull the whole page up under the reader; growing
   one only ever pushes content down, below where they are looking.

   Both arrangements are pure layout, so a reader with no JavaScript gets the grid
   and loses nothing but the flight. product.js sets --count and --step; the rest
   is here.
   ----------------------------------------------------------------------- */

.sheet__grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-content: start;
  padding: 0 30px 40px var(--ledger-gutter);
}

/* The flight is a wide-screen arrangement. Below 1280px a staircase has no width
   to descend across, so the sheet keeps the grid it always had - which is why the
   grid was never removed. Nothing is lost at that width but the shape.

   This wrapper was lost once in a rewrite and the flight then applied at every
   width, which put 53px of horizontal overflow on a 390px screen. */
@media (min-width: 1280px) {
  /* The flight. Ten narrow packages standing side by side across the sheet, each
     one a step lower than the one before, so the sheet reads as a flight you could
     walk down and the whole of it is visible at once.

     The axis is the thing. An earlier build stacked wide landscape rows and
     indented each one - which is a diagonal, but it ran to 1895px for one sheet, so
     the shape of the flight could never be seen, and the rail ran out after three
     steps leaving most of the width empty. Turning the cards portrait and stepping
     them across brings the same ten packages into about 500px.

     --stride-y is the drop per step. --step comes from product.js.

     The steps touch and never overlap: a staircase is worth nothing if it hides the
     figures it is made of. */
  .sheet .sheet__grid {
    /* The stride is the whole mechanic. At zero the ten packages stand side by
       side in a row; at full height they are a flight of steps. product.js scrubs
       between the two against scroll, so a sheet unfolds as it arrives and packs
       itself away as it leaves, and scrolling back up runs the same construction
       in reverse. --stride-open is the target; --stride-y is what is drawn. */
    --stride-open: clamp(22px, 2.4vw, 34px);
    /* The default is open, so a reader with no JavaScript, or one who asked for
       reduced motion, gets the flight as a finished thing. product.js sets it to
       zero and scrubs it up, which is what turns the row into the staircase. */
    --stride-y: var(--stride-open);
    display: flex;
    align-items: flex-start;
    gap: 0;
    /* The flight has the whole width now that the rail is a band below it, so it
       needs the gutter back on the right - without it the last package sat hard
       against the edge of the viewport. */
    padding-right: var(--ledger-gutter);
    padding-bottom: 40px;
  }

  .sheet .tariff-card {
    /* Equal shares of the column, and none of them may refuse to shrink: ten
       packages have to fit the width whatever the width is. */
    flex: 1 1 0;
    min-width: 0;
    margin-top: calc(var(--step, 0) * var(--stride-y));
    padding: 10px 9px 11px;
    border-left-width: 0;
  }

  .sheet .tariff-card:first-child {
    border-left-width: 1px;
  }

  /* Everything in the card comes down in scale. At a tenth of the column a package
     has about 100px to say ten things in, so the type is set to that width rather
     than to the width the grid card had. */
  .sheet .tariff-card__head {
    margin-bottom: 3px;
  }

  .sheet .tariff-card__tag {
    font-size: 8px;
    letter-spacing: 0.1em;
  }

  .sheet .tariff-card__name {
    margin: 0 0 8px;
    font-size: 11px;
    letter-spacing: 0.01em;
  }

  /* The grid card reserves 96px for the numeral so that a two-digit speed and a
     six-digit minute package sit on the same optical line. In the flight that
     reservation is dead space at the top of every step - it was adding 86px to each
     of the ten cards - and the flight has no cross-sheet line to hold. */
  .sheet .tariff-card__figure {
    min-height: 0;
    gap: 2px;
    margin: 6px 0 0;
  }

  /* [data-w] on the selector, not for the sake of it: the grid card sizes the
     numeral through .tariff-card__value[data-w="s"] and friends, which carry the
     same specificity as .sheet .tariff-card__value and sit later in this file. A
     plain class pair therefore lost, and the 74px grid numerals overflowed the
     flight cards and printed across their neighbours. */
  .sheet .tariff-card__value[data-w] {
    font-size: clamp(15px, 1.55vw, 23px);
  }

  .sheet .tariff-card__unit {
    font-size: 8px;
    letter-spacing: 0.1em;
  }

  .sheet .tariff-card__spec {
    gap: 3px;
    margin: 9px 0 0;
    padding-top: 8px;
    border-top: 1px solid var(--ledger-line);
    /* 8px with the tracking pulled in, because at a tenth of the column
       "Birim 1,29 TL/dk" has about 74px to sit in and at 8.5px it broke onto a
       second line for all three conditions of all ten packages. */
    font-size: 8px;
    letter-spacing: -0.005em;
    line-height: 1.4;
  }

  /* The size has to be set on the item, not on the list. .tariff-card__spec li
     declares its own 11.5px, and a font-size on the list cannot beat a font-size on
     the element itself however specific the list's selector is - which is why all
     three conditions were still wrapping onto two lines. The dot's indent goes with
     the dot. */
  .sheet .tariff-card__spec li {
    padding-left: 0;
    font-size: 8.5px;
    line-height: 1.5;
  }

  /* The dots go. Ten packages times three conditions is thirty marks in one flight,
     and the direction frame carries none. */
  .sheet .tariff-card__spec li::before {
    display: none;
  }

  /* The price and the control stack, because side by side they do not fit and the
     price is the thing that has to stay legible. */
  .sheet .tariff-card__foot {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    margin-top: 10px;
    padding-top: 8px;
  }

  .sheet .tariff-card__price {
    font-size: 15px;
  }

  .sheet .tariff-card__price span {
    font-size: 8px;
  }

  .sheet .tariff-card__cta {
    font-size: 8.5px;
    letter-spacing: 0.1em;
  }

  .sheet .tariff-card__cta svg {
    width: 14px;
  }

  /* The featured package is the one solid step, so the flight has a landing rather
     than an even slope. Filled rather than outlined, which is how the direction
     frame carries it - and on orange every part of the card takes ink. */
  .sheet .tariff-card--featured,
  .sheet .tariff-card--featured:hover {
    color: var(--ink);
    background: var(--signal-orange);
    border-color: var(--signal-orange);
  }

  .sheet .tariff-card--featured .tariff-card__tag,
  .sheet .tariff-card--featured .tariff-card__value,
  .sheet .tariff-card--featured .tariff-card__unit,
  .sheet .tariff-card--featured .tariff-card__spec,
  .sheet .tariff-card--featured .tariff-card__price,
  .sheet .tariff-card--featured .tariff-card__price span,
  .sheet .tariff-card--featured .tariff-card__cta,
  .sheet .tariff-card--featured .tariff-card__spec li {
    color: var(--ink);
  }

  .sheet .tariff-card--featured .tariff-card__spec,
  .sheet .tariff-card--featured .tariff-card__foot {
    border-top-color: rgba(39, 20, 14, 0.3);
  }

}

/* ---- The conditions band ------------------------------------------------
   Operator request: bring the conditions and fees down to the bottom of the
   tariff's own frame, and make the packages bigger.

   Those are one change. The rail was a 372px column beside the flight, which is
   what held the packages down to a tenth of nine hundred-odd pixels. Moving it
   under the flight gives the flight the whole width - the packages grow by about
   forty per cent with no other edit - and it puts the conditions in the space the
   descending staircase leaves empty at the bottom of the frame.

   It also fixes the height. Stacked in one narrow column the three rails ran 876,
   817 and 1172px, and the internet one was taller than a 1080px screen on its
   own. In three columns the same blocks come to roughly a third of that.

   I moved all of the rail rather than part of it, because leaving a block beside
   the flight would have kept the column that made the packages small.
   ----------------------------------------------------------------------- */

@media (min-width: 1280px) {
  .sheet__body {
    display: block;
  }

  .rail {
    padding: 0 var(--ledger-gutter) 40px;
    border-top: 1px solid var(--ledger-line);
    border-left: 0;
    /* Three, not four. Four narrower columns wrap the condition text more, so the
       tallest column got taller: the Ses rail went from 512px to 530px. */
    column-gap: clamp(28px, 3.2vw, 52px);
    columns: 3;
  }

  .rail-block {
    margin-bottom: 20px;
  }

  /* A fee table or a condition book split down the middle by a column break is
     unreadable, so a block is atomic and the columns balance around them. */
  .rail-block,
  .limit,
  .rail__title {
    break-inside: avoid;
  }

  .rail__title {
    column-span: all;
    margin-bottom: 22px;
    padding-top: 26px;
  }
}

/* Below 1280px the flight is closed. A staircase needs width to descend across,
   and the sheet keeps the grid it always had - which is why the grid was never
   removed. Nothing is lost at that width but the shape. */

/* ---- Tariff card --------------------------------------------------------

   One card states one measured quantity. The name and the tier chip sit above
   it, the derived unit price and the package direction below it, and the
   price closes the card on its own rule. Nothing here animates on scroll: the
   grid is a price list and has to be readable the moment it is on screen.
   ------------------------------------------------------------------------- */

.tariff-card {
  display: flex;
  flex-direction: column;
  padding: 16px 18px 14px;
  border: 1px solid var(--ledger-line-strong);
  color: var(--paper-bright);
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease;
}

.tariff-card:hover {
  border-color: rgba(255, 255, 255, 0.42);
  background: rgba(255, 255, 255, 0.035);
}

/* The tag is what is left in the head row now that the sequence number is gone
   (DESIGN.md, heading restraint), so the row no longer needs to space two items
   apart. */
.tariff-card__head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
}

.tariff-card__tag {
  color: var(--muted-invert);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.tariff-card__name {
  margin: 12px 0 0;
  font-family: var(--font-ui);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

/* One height for every figure block. The value is bucketed by digit count, so
   a two digit speed and a seven digit SMS count set different type sizes; left
   free, the rule under the block would land on a different line in every card
   of a row. The block is fixed and the value sits on its floor instead. */
.tariff-card__figure {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  min-height: clamp(72px, 6.4vw, 96px);
  margin: 10px 0 16px;
}

/* The measured quantity. Bucketed by digit count so a six figure minute
   package and a two figure speed sit on the same optical weight instead of
   one of them wrapping out of the card. */
.tariff-card__value {
  color: var(--ledger-figure);
  font-family: var(--font-display);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.04em;
  line-height: 0.86;
}

.tariff-card__value[data-w="s"] {
  font-size: clamp(48px, 4.9vw, 74px);
}

.tariff-card__value[data-w="m"] {
  font-size: clamp(40px, 4vw, 60px);
}

.tariff-card__value[data-w="l"] {
  font-size: clamp(30px, 3vw, 45px);
}

.tariff-card__value[data-w="xl"] {
  font-size: clamp(24px, 2.3vw, 35px);
}

.tariff-card__unit {
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.tariff-card__spec {
  margin: 0 0 16px;
  padding: 14px 0 0;
  border-top: 1px solid var(--ledger-line);
  list-style: none;
}

.tariff-card__spec li {
  position: relative;
  padding-left: 13px;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.9;
  font-variant-numeric: tabular-nums;
}

.tariff-card__spec li::before {
  position: absolute;
  top: 9px;
  left: 0;
  width: 4px;
  height: 4px;
  content: "";
  background: var(--signal-orange-invert);
  border-radius: 50%;
}

.tariff-card__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: auto 0 0;
  padding-top: 13px;
  border-top: 1px solid var(--ledger-line);
}

.tariff-card__price {
  font-size: 21px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.tariff-card__price span {
  margin-left: 6px;
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
}

.tariff-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-decoration: none;
  text-transform: uppercase;
  transition: color 0.2s ease;
}

.tariff-card__cta svg {
  width: 18px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-width: 1.4;
  transition: transform 0.2s ease;
}

.tariff-card:hover .tariff-card__cta,
.tariff-card__cta:focus-visible {
  color: var(--signal-orange-invert);
}

.tariff-card:hover .tariff-card__cta svg {
  transform: translateX(4px);
}

/* The one card lifted out of the grid.

   The first build inverted it to paper. On a graphite plate that reads as a
   different component dropped into the row rather than as one of its cards,
   and at 1440 it pulled the eye before the sheet heading did. The card stays
   on the plate's own ground now; it is marked by a half step of surface, an
   orange edge, and the price - the field a buyer is comparing anyway. */
.tariff-card--featured {
  position: relative;
  border-color: rgba(255, 124, 66, 0.45);
  background: rgba(255, 255, 255, 0.045);
  box-shadow: -3px 0 0 0 var(--signal-orange-invert);
}

.tariff-card--featured:hover {
  border-color: rgba(255, 124, 66, 0.7);
  background: rgba(255, 255, 255, 0.075);
}

.tariff-card--featured .tariff-card__tag,
.tariff-card--featured .tariff-card__price {
  color: var(--signal-orange-invert);
}

/* The figure is warmed a step so the card reads as the brighter one in the
   row without leaving the tone the other cards are set in. */
.tariff-card--featured .tariff-card__value {
  color: #a8968a;
}

/* ---- Rail (shared chassis) ----------------------------------------------

   Only the chassis is shared: the column, its left rule, the block rhythm and
   the stencil label. What sits inside differs per sheet, because the notes
   differ per sheet.
   ------------------------------------------------------------------------- */

.rail {
  align-self: start;
  padding: 0 var(--ledger-gutter) 40px 26px;
  border-left: 1px solid var(--ledger-line);
}

/* The wrappers only assign the lower field inside the animated one-frame
   layout. In the no-motion document they dissolve, so the original full-flow
   rail keeps its multi-column reading order. */
.ledger:not(.is-framed) .rail__main,
.ledger:not(.is-framed) .sheet__lower {
  display: contents;
}

.rail__title {
  margin: 0 0 20px;
  color: var(--signal-orange-invert);
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.rail-block {
  margin: 0 0 26px;
  padding: 0;
  border: 0;
}

.rail-block:last-child {
  margin-bottom: 0;
}

.rail-block__title {
  margin: 0 0 12px;
  color: var(--muted-invert);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-align: left;
  text-transform: uppercase;
}

.rail-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin-top: 14px;
  padding: 13px 15px;
  border: 1px solid var(--ledger-line-strong);
  color: var(--paper-bright);
  background: none;
  font-family: inherit;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.rail-toggle:hover {
  background: rgba(255, 255, 255, 0.06);
}

.rail-toggle svg {
  width: 13px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-width: 1.4;
  transition: transform 0.2s ease;
}

.rail-toggle[aria-expanded="true"] svg {
  transform: rotate(180deg);
}

/* ---- Rail instrument: paired meters (voice) ----------------------------- */

.rail-meters {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: 1px solid var(--ledger-line-strong);
}

.meter {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 0;
  padding: 15px 16px;
  border-left: 1px solid var(--ledger-line-strong);
}

.meter:first-child {
  border-left: 0;
}

.meter__value {
  color: var(--signal-orange-invert);
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1;
}

.meter__unit {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.meter__label {
  color: var(--muted-invert);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---- Rail instrument: expandable condition ledger (voice, connectivity) --

   Built on details/summary, so every condition is reachable with the script
   disabled. product.js only adds the bulk open button on top of it.
   ------------------------------------------------------------------------- */

.cond-list {
  border-top: 1px solid var(--ledger-line);
}

.cond {
  border-bottom: 1px solid var(--ledger-line);
}

/* Two columns now that the leading sequence number is gone: the name and lead
   on the left, the open/close marker on the right. */
.cond__row {
  display: grid;
  align-items: baseline;
  gap: 4px 12px;
  grid-template-columns: minmax(0, 1fr) auto;
  padding: 13px 0;
  cursor: pointer;
  list-style: none;
}

.cond__row::-webkit-details-marker {
  display: none;
}

.cond__row::after {
  grid-column: 2;
  grid-row: 1;
  color: var(--muted-invert);
  content: "+";
  font-size: 15px;
  line-height: 1;
}

.cond[open] > .cond__row::after {
  content: "\2212";
}

.cond__name {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.cond__lead {
  grid-column: 1 / -1;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.55;
}

/* The operative words of a condition are marked inside the sentence that
   states them. An earlier build put a coloured status pill beside the row
   title instead; it restated in a chip what the line already said, and read
   as a consumer feature list rather than a contract sheet. */
.cond__lead strong,
.flags__note strong {
  color: var(--paper-bright);
  font-weight: 600;
  text-decoration: underline;
  /* The mark stays; its colour does not. Fifteen orange underlines inside the
     condition text made the accent the page's most repeated element, and an
     accent that appears in every sentence stops reporting anything. The
     operative word is already carried by weight and by the brighter ink, so
     the rule underneath it can be neutral. */
  text-decoration-color: rgba(250, 247, 240, 0.4);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.cond__body {
  margin: 0;
  padding: 0 24px 15px 32px;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.7;
  /* Twelve orange edges down the conditions rail competed with the one orange
     edge that means something on this page - the featured tariff card. The
     rule still indents and groups the answer under its condition; it no longer
     claims to be a mark. */
  border-left: 1px solid rgba(250, 247, 240, 0.22);
}

.cond__row:focus-visible {
  outline: 2px solid var(--signal-orange-invert);
  outline-offset: 2px;
}

/* ---- Rail instrument: prepayment ladder (voice) ------------------------- */

.ladder {
  margin: 0;
  padding: 0;
  list-style: none;
}

.ladder__step {
  display: grid;
  align-items: center;
  gap: 12px;
  grid-template-columns: 46px minmax(0, 1fr) 40px;
  padding: 7px 0;
}

.ladder__term,
.ladder__value {
  color: var(--muted-invert);
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.ladder__value {
  text-align: right;
}

.ladder__bar {
  position: relative;
  height: 6px;
  background: rgba(255, 255, 255, 0.09);
}

.ladder__bar::after {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--w, 0%);
  content: "";
  background: rgba(255, 255, 255, 0.34);
}

.ladder__step--peak .ladder__value {
  color: var(--signal-orange-invert);
}

.ladder__step--peak .ladder__bar::after {
  background: var(--signal-orange);
}

/* ---- Rail instrument: 12 month usage track (voice) ---------------------- */

.timeline {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.timeline__month {
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 9px;
  color: var(--muted-invert);
  font-size: 8.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

.timeline__dot {
  position: relative;
  width: 100%;
  height: 7px;
}

.timeline__dot::before {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1px;
  content: "";
  background: var(--ledger-line-strong);
}

.timeline__dot::after {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  content: "";
  background: var(--signal-orange);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.timeline__month:first-child .timeline__dot::before {
  left: 50%;
  width: 50%;
}

.timeline__month:last-child .timeline__dot::before {
  width: 50%;
}

.timeline__legend {
  display: flex;
  gap: 20px;
  margin: 14px 0 0;
}

.timeline__key {
  color: var(--muted-invert);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.timeline__key::before {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  content: "";
  border-radius: 50%;
  vertical-align: middle;
}

.timeline__key--on::before {
  background: var(--signal-orange);
}

.timeline__key--off::before {
  background: none;
  box-shadow: inset 0 0 0 1px var(--muted-invert);
}

/* ---- Rail instrument: validity window (messaging) ----------------------- */

.validity__figure {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 0 0 12px;
  color: var(--muted-invert);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.validity__figure span {
  color: var(--signal-orange-invert);
  font-family: var(--font-display);
  font-size: 46px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 0.9;
}

.validity__track {
  display: grid;
  gap: 3px;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.validity__track li {
  height: 22px;
  background: rgba(255, 255, 255, 0.14);
}

/* The last segment is the edge of the window, not another month of it. */
.validity__track li:last-child {
  background: repeating-linear-gradient(
    -45deg,
    var(--signal-orange) 0 2px,
    transparent 2px 5px
  );
  box-shadow: inset 0 0 0 1px var(--signal-orange);
}

.validity__note {
  max-width: 34ch;
  margin: 13px 0 0;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.7;
}

/* ---- Rail instrument: scope split (messaging) --------------------------- */

.scope {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: 1px solid var(--ledger-line-strong);
}

.scope__cell {
  padding: 15px 16px;
  border-left: 1px solid var(--ledger-line-strong);
}

.scope__cell:first-child {
  border-left: 0;
}

.scope__cell dt {
  color: var(--muted-invert);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.scope__cell dd {
  margin: 9px 0 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.scope__cell--alt dd {
  color: var(--signal-orange-invert);
}

/* ---- Rail instrument: flat condition flags (messaging) ------------------

   The messaging notes are four short sentences. They are printed in full
   rather than folded behind an expander: an accordion over one line of text
   hides nothing and only adds a click.
   ------------------------------------------------------------------------- */

.flags {
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--ledger-line);
  list-style: none;
}

.flags li {
  display: grid;
  gap: 5px;
  padding: 12px 0;
  border-bottom: 1px solid var(--ledger-line);
}

.flags__name {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.flags__note {
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.6;
}

/* ---- Rail instrument: unit price curve (messaging) ---------------------- */

.curve {
  margin: 0;
  padding: 0;
  list-style: none;
}

.curve__row {
  display: grid;
  align-items: center;
  gap: 12px;
  grid-template-columns: 40px minmax(0, 1fr) 44px;
  padding: 5px 0;
}

.curve__name,
.curve__value {
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
}

.curve__value {
  text-align: right;
}

/* A unit-price curve exists to show one thing: the price falls as the volume
   rises. Every bar drawn in the accent said "look here" seven times over, so
   the shape had to be read rather than seen. The bars now carry the ink and
   the accent marks only the row the curve is travelling towards - the lowest
   unit price - which is the row the reader is being shown. */
.curve__bar {
  height: 5px;
  background: linear-gradient(
    to right,
    rgba(250, 247, 240, 0.42) 0 var(--w, 0%),
    rgba(255, 255, 255, 0.09) var(--w, 0%) 100%
  );
}

.curve__row:last-child .curve__bar {
  background: linear-gradient(
    to right,
    var(--signal-orange-invert) 0 var(--w, 0%),
    rgba(255, 255, 255, 0.09) var(--w, 0%) 100%
  );
}

.curve__row:last-child .curve__value {
  color: var(--signal-orange-invert);
}

/* ---- Rail instrument: limit mark and fee table (connectivity) ----------- */

.limit {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 26px;
  padding: 12px 16px;
  border: 1px solid var(--ledger-line-strong);
}

.limit__mark {
  color: var(--signal-orange-invert);
  font-family: var(--font-display);
  font-size: 42px;
  font-weight: 400;
  line-height: 0.7;
}

.limit__label {
  color: var(--muted-invert);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.fees {
  width: 100%;
  border-collapse: collapse;
}

.fees caption {
  caption-side: top;
}

.fees tr {
  border-bottom: 1px solid var(--ledger-line);
}

.fees tr:first-child {
  border-top: 1px solid var(--ledger-line);
}

.fees th {
  padding: 10px 0;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  text-align: left;
}

.fees td {
  padding: 10px 0;
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* ---- Rail instrument: discount cells (connectivity) --------------------- */

.perks {
  display: grid;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.perks li {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 13px 15px;
  background: rgba(255, 255, 255, 0.05);
}

.perks__value {
  color: var(--signal-orange-invert);
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.perks__label {
  color: var(--muted-invert);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
}

/* ---- Ledger foot -------------------------------------------------------- */

.ledger__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 30px;
  padding: 30px var(--ledger-gutter);
}

.ledger__foot-note {
  max-width: 62ch;
  margin: 0;
  color: var(--muted-invert);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.7;
}

/* ---- Ledger: intermediate widths ---------------------------------------- */

@media (max-width: 1240px) {
  .ledger {
    --rail-width: 320px;
  }

  .sheet__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 1040px) {
  .ledger__top {
    grid-template-columns: minmax(0, 1fr) minmax(120px, 150px);
    row-gap: 18px;
  }

  .ledger__tabs {
    grid-column: 1 / -1;
    grid-row: 2;
  }

  .sheet__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .sheet__grid {
    padding-right: var(--ledger-gutter);
  }

  /* Below the grid the rail is no longer a column, so it loses the rule that
     made it one and takes a top rule instead. */
  .rail {
    padding: 30px var(--ledger-gutter) 40px;
    border-top: 1px solid var(--ledger-line);
    border-left: 0;
  }

  .rail > .rail-block,
  .rail > .limit {
    max-width: 640px;
  }
}

/* ---- Ledger: compact ---------------------------------------------------- */

@media (max-width: 820px) {
  /* The bar wraps to three rows here and would hold a third of the viewport
     for the whole ledger. It stops being sticky and becomes the plate's own
     masthead instead; the sheets are still a flow, so nothing is lost but the
     running navigator. */
  .ledger__top {
    position: static;
    grid-template-columns: minmax(0, 1fr);
    padding-top: calc(var(--header-height) + 16px);
  }

  .ledger-tab {
    padding: 12px;
  }

  .ledger-tab__label {
    font-size: 9.5px;
    letter-spacing: 0.1em;
    white-space: normal;
  }

  .sheet__head {
    flex-wrap: wrap;
    row-gap: 14px;
  }

  .sheet__hint {
    flex-basis: 100%;
    padding-left: 0;
    border-left: 0;
  }

  .sheet__signal,
  .ledger.has-sheet-signals .sheet__title {
    width: 116px;
    min-width: 116px;
    height: 25px;
  }

  .sheet__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .ledger__foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 22px;
  }
}

/* ---- Ledger: reduced motion --------------------------------------------

   Nothing in the ledger is scroll driven, so only the hover travel and the
   sticky bar need stepping back. Every figure, condition and fee stays on the
   page unchanged.
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .ledger *,
  .ledger *::before,
  .ledger *::after {
    transition-duration: 0.01ms !important;
  }

  .tariff-card:hover .tariff-card__cta svg {
    transform: none;
  }
}
