/* 広告を「ブラウン管テレビの画面」として見せる枠。TV.png を参考にしている。
 *
 * 構成は アンテナ ／ 本体（画面＋操作パネル） ／ 脚 の3段。
 * 画像を使わず図形だけで描いているため、広告の大きさに合わせて伸縮する。
 *
 * 元の絵は黄色の背景に黒いテレビだが、当サイトの背景は濃い灰色（#263238）のため
 * 輪郭を白にしている。記事カードの白枠とも揃う。
 *
 * 広告そのもの（a と img）には手を触れていない。
 * ASPのタグに差し替えても、この枠はそのまま使える。
 */

/* テレビ全体の幅。

   中身から自動で決めさせると、入れ子の伸縮計算で6px足りない幅に確定し、
   画面が広告より狭くなってしまう（実測: 広告が294pxになった）。
   「広告300px ＋ 枠の取り分」を上限として明示し、
   入る場所が狭いときだけ width:100% で縮む形にしている。

   --tv-chrome は枠が使う横幅の合計。
   内訳: 操作パネル56 ＋ 画面との間隔10 ＋ 本体の内側余白24 ＋ 枠線8 = 98px */
.tv {
  --tv-chrome: 98px;
  display: block;
  width: 100%;
  max-width: calc(300px + var(--tv-chrome));
  margin: 0 auto;
}

/* ---- アンテナ ---- */
/* 2本の棒を根元を軸に左右へ傾けて V 字にする。
   高さ30pxの帯の中に、34pxの棒を傾けて収めている */
.tv__antenna {
  position: relative;
  height: 30px;
}

.tv__antenna::before,
.tv__antenna::after {
  content: "";
  position: absolute;
  bottom: -2px;
  left: 50%;
  width: 6px;
  height: 34px;
  margin-left: -3px;
  background: #fff;
  border-radius: 3px;
  transform-origin: bottom center;
}

.tv__antenna::before {
  transform: rotate(-28deg);
}

.tv__antenna::after {
  transform: rotate(28deg);
}

/* ---- 本体 ---- */
.tv__body {
  display: flex;
  align-items: stretch;
  gap: 10px;
  padding: 12px;
  background: #111;
  border: 4px solid #fff;
  border-radius: 14px;
  box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.45);
}

/* ---- 画面（広告が入る場所） ---- */
/* line-height を0にしているのは、img の下に生じる余白を消すため。
   overflow: hidden で、角の丸みから広告がはみ出さないようにする */
.tv__screen {
  /* 広告の標準サイズ（300px）を基準の幅にする。
     幅を書かずに中身任せにすると、伸縮の計算が入れ子で堂々巡りになり、
     広告が数px縮んだ状態で確定してしまう（実測で294pxになっていた）。
     入る場所が狭いときは max-width で縮み、広告もそれに追従する */
  flex: 0 1 auto;
  width: 300px;
  max-width: 100%;
  min-width: 0;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  line-height: 0;
  /* 切り替え時の砂嵐（.tv__noise）を画面いっぱいに重ねるための基準 */
  position: relative;
}

/* 画面の中身（広告のリンクと画像）は、画面の幅にそのまま従わせる。

   もともと a と img には max-width:100% が付いており、
   「画面の幅は中身で決まる／中身の幅は画面で決まる」という堂々巡りになる。
   その結果、幅に余裕があっても広告が294pxで確定していた。

   画面側だけが幅を決め（width:300px、狭ければ max-width で縮む）、
   中身はそれに合わせる形にすると、余裕があるときは必ず300pxになる。

   詳細度は css/ad-slot.css の元の指定に合わせてある */
.sidebar_nav > ul > li.ad-slot .tv__screen .ad-slot__link,
.ad-inline .tv__screen .ad-inline__link,
.ad-side .tv__screen .ad-side__link {
  display: block;
  max-width: none;
}

.sidebar_nav > ul > li.ad-slot .tv__screen img,
.ad-inline .tv__screen img,
.ad-side .tv__screen img {
  width: 100%;
  max-width: none;
  height: auto;
}

/* ---- 切り替え時の砂嵐 ---- */
/* 広告が入れ替わる瞬間だけ、画面に砂嵐を重ねて消えていく。
   要素は js/ad-rotator.js が画面(.tv__screen)の中に作る。
   切り替えが起きないページ・環境では作られないため、常時の負荷はない。

   砂嵐は SVG の feTurbulence（乱数で作る模様）を背景画像にしている。
   画像ファイルを増やさずに済み、画面の大きさが変わっても粗さが変わらない。

   重ね方は3層。
     1. 走査線     … 横縞。ブラウン管の線を表す
     2. 砂嵐       … 位置をずらして animation でちらつかせる
     3. 走るバー   … ::after。上から下へ流れる明るい帯（同期が外れた画）*/
.tv__noise {
  /* 砂嵐をかぶせてから広告を入れ替えるまでの時間。
     実際の値は js/ad-rotator.js の 砂嵐ミリ秒 が各要素へ書き込む。
     ここの値は書き込まれなかったときの控えである */
  --noise-hold: 900ms;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0;
  pointer-events: none;
  background-color: #000;
  background-image:
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.3) 0 1px,
      transparent 1px 3px
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.62' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: auto, 160px 160px;
  /* 消えるときはゆっくり。出るときは下の .is-on で決める */
  transition: opacity 0.5s ease-out;
}

/* 目に優しくするための調整（2026-08-11）。
   当初は「一瞬で真っ白な砂嵐が出る」形にしていたが、明滅が強すぎたため
   次の4点を弱めている。数値を戻せば元の強さに戻せる。

     粒の明るさ  SVGの rect に opacity 0.42（真っ白 → 暗い灰色の粒）
     粒の細かさ  baseFrequency 0.9 → 0.62（細かいほどちらついて見えるため粗く）
     明滅の速さ  0.12s → 0.36s（下の keyframes は4区切りのため、
                 1秒あたり約33回 → 約11回になる）
     出る速さ    0.05s → 0.18s（一気に出さず、短く溶け込ませる） */
.tv__noise.is-on {
  opacity: 1;
  transition: opacity 0.18s ease-in;
  animation: tv-noise-shift 0.36s steps(1) infinite;
}

/* 砂嵐の粒を動かす。位置を飛ばすだけで、模様の再計算は起きない */
@keyframes tv-noise-shift {
  0%   { background-position: 0 0, 0 0; }
  25%  { background-position: 0 0, -37px 61px; }
  50%  { background-position: 0 0, 84px -23px; }
  75%  { background-position: 0 0, -52px -78px; }
  100% { background-position: 0 0, 19px 44px; }
}

/* 上から下へ流れる明るい帯。
   明るさ0.28・0.45秒では素早く光が横切って目立ちすぎたため、
   薄く・ゆっくり・幅広にして、ぼんやり通り過ぎる程度にしている */
.tv__noise::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 28%;
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(255, 255, 255, 0.11),
    transparent
  );
}

/* バーは上から下へ1回だけ通す。繰り返さないのは、
   広告が入れ替わる瞬間にバーが必ず同じ位置へ来るようにするため。

   入れ替わるのは、バーが画面の真ん中を少し過ぎたあたり（中心が高さの60%）。
   そこへ合わせるための倍率 1.71 は次のように出している。

     バーの上端は -30% から 100% まで動き、バー自身の高さは 28%。
     よってバーの中心は -16% から 114% まで、合わせて 130% ぶん動く。
     中心が 60% に来るのは、動き始めてから (60 - (-16)) / 130 = 0.585 の時点。
     入れ替えの時刻（--noise-hold）がその 0.585 にあたればよいので、
     バーの動きにかかる時間は --noise-hold ÷ 0.585 ＝ --noise-hold × 1.71 になる。

   倍率で書いているため、砂嵐の長さを変えても
   「真ん中を少し過ぎたところで入れ替わる」関係は保たれる */
.tv__noise.is-on::after {
  animation: tv-noise-roll calc(var(--noise-hold) * 1.71) linear 1 forwards;
}

@keyframes tv-noise-roll {
  from { top: -30%; }
  to   { top: 100%; }
}

/* 動きを抑える設定にしている利用者には、ちらつきを出さず
   ひとこまだけ挟んで静かに消す */
@media (prefers-reduced-motion: reduce) {
  .tv__noise.is-on {
    animation: none;
  }

  .tv__noise.is-on::after {
    animation: none;
  }
}

/* ---- 右側の操作パネル ---- */
.tv__panel {
  flex: 0 0 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 4px 0;
}

/* スピーカーの網。白い線を等間隔で繰り返して描く */
.tv__grille {
  width: 36px;
  height: 46px;
  background: repeating-linear-gradient(
    to bottom,
    #fff 0 3px,
    transparent 3px 8px
  );
}

/* 小さな丸2つ（表示ランプ） */
.tv__dots {
  width: 34px;
  height: 10px;
  background:
    radial-gradient(circle 5px at 25% 50%, #fff 98%, transparent 100%),
    radial-gradient(circle 5px at 75% 50%, #fff 98%, transparent 100%);
}

/* チャンネルのつまみ */
.tv__dial {
  width: 30px;
  height: 30px;
  border: 4px solid #fff;
  border-radius: 50%;
}

/* つまみを押すと広告がすぐ切り替わる。
   is-switch は js/ad-rotator.js が付ける目印で、
   切り替える広告が2つ以上あるときだけ押せる見た目になる
   （広告が1つしかないときは押しても何も起きないため、飾りのままにする）。

   色は他の押せる箇所と同じ黄色にそろえている。
   var の既定値を書いているのは、--link-yellow を定義している
   css/link-menu.css を読み込まない記事ページでも同じ色にするため */
.tv__dial.is-switch {
  cursor: pointer;
  background-color: transparent;
  transition: background-color 0.15s ease;
}

.tv__dial.is-switch:hover,
.tv__dial.is-switch:focus-visible {
  background-color: var(--link-yellow, #f7d51d);
}

.tv__dial.is-switch:focus-visible {
  outline: 2px solid var(--link-yellow, #f7d51d);
  outline-offset: 2px;
}

/* ---- 脚 ---- */
/* 下へ広がる台形。幅0の要素に左右を透明にした太い下枠を付けると
   台形になる（上辺8px・下辺18px） */
.tv__legs {
  position: relative;
  height: 14px;
}

.tv__legs::before,
.tv__legs::after {
  content: "";
  position: absolute;
  top: 0;
  width: 8px;
  height: 0;
  border-bottom: 14px solid #fff;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}

.tv__legs::before {
  left: 16%;
}

.tv__legs::after {
  right: 16%;
}

/* ---- 幅に余裕がない場所で使う形 ---- */
/* 記事ページの左カラムは最も狭いもので325pxしかなく、
   300pxの広告に操作パネル（56px）を足すと収まらない。
   広告を縮めるとASPの固定サイズのタグが入らなくなるため、
   パネルを省いて画面だけのテレビにする */
.tv--narrow {
  /* 内訳: 間隔0 ＋ 内側余白12 ＋ 枠線8 = 20px */
  --tv-chrome: 20px;
}

.tv--narrow .tv__panel {
  display: none;
}

.tv--narrow .tv__body {
  gap: 0;
  padding: 6px;
}

/* 狭い画面ではテレビ全体を控えめにする。
   .tv--narrow でもパネルを出し、どの画面でも同じ形にそろえる。
   幅が足りない環境でのみ広告が縮む（下の実測を参照） */
@media screen and (max-width: 768px) {
  /* 内訳: 操作パネル28 ＋ 間隔4 ＋ 内側余白12 ＋ 枠線8 = 52px */
  .tv,
  .tv--narrow {
    --tv-chrome: 52px;
  }

  /* 記事間の広告枠の左マージン8pxを外す。
     PCでは記事カードの margin-left に合わせるための値だが、
     スマホではカードが画面幅いっぱいに広がるため、逆に8pxずれる。
     外すとカードと左端が揃い、テレビに使える幅も8px増える */
  .ad-inline {
    margin-left: 0;
  }

  .tv__antenna {
    height: 22px;
  }

  .tv__antenna::before,
  .tv__antenna::after {
    height: 26px;
    width: 5px;
    margin-left: -2.5px;
  }

  .tv__body,
  .tv--narrow .tv__body {
    gap: 4px;
    padding: 6px;
  }

  .tv--narrow .tv__panel {
    display: flex;
  }

  .tv__panel {
    flex-basis: 28px;
    padding: 2px 0;
  }

  .tv__grille {
    width: 22px;
    height: 26px;
    background: repeating-linear-gradient(
      to bottom,
      #fff 0 2px,
      transparent 2px 6px
    );
  }

  .tv__dots {
    width: 22px;
    height: 7px;
    background:
      radial-gradient(circle 3.5px at 25% 50%, #fff 98%, transparent 100%),
      radial-gradient(circle 3.5px at 75% 50%, #fff 98%, transparent 100%);
  }

  .tv__dial {
    width: 20px;
    height: 20px;
    border-width: 3px;
  }

  .tv__legs {
    height: 12px;
  }

  .tv__legs::before,
  .tv__legs::after {
    border-bottom-width: 12px;
  }
}

/* ごく狭い画面では操作パネルを省き、広告の幅を優先する。

   テレビの枠は横幅を使うため、画面が狭いと広告が300pxに届かない。
   実測では画面幅410px未満で不足する（390pxのとき285px、360pxのとき255px）。
   ASPが配布する300×250の固定サイズのタグは、縮むと右端が切れてしまう。

   パネルを省くと枠の取り分が52px→20pxになり、
   360pxの画面でも広告が287pxまで確保できる。

   `.tv--narrow .tv__panel` を打ち消すため、クラス2つ分の詳細度にしている */
@media screen and (max-width: 409px) {
  .tv .tv__panel,
  .tv--narrow .tv__panel {
    display: none;
  }

  .tv .tv__body,
  .tv--narrow .tv__body {
    gap: 0;
    padding: 6px;
  }

  /* 内訳: 間隔0 ＋ 内側余白12 ＋ 枠線8 = 20px */
  .tv,
  .tv--narrow {
    --tv-chrome: 20px;
  }
}

/* ---- 既存の広告枠との調整 ---- */
/* .ad-inline と .ad-side はもともと白枠・黒背景・影の箱だった。
   テレビ側が同じ役割を持つため、外側の箱は透明にして二重にならないようにする。
   「広告」のラベルはこの箱の中に残るため、要素そのものは消さない */
.ad-inline,
.ad-side {
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
}

/* テレビとラベルの間隔。ラベルの下余白（10px）だけでは詰まって見える */
.ad-inline .tv,
.ad-side .tv,
.sidebar_nav > ul > li.ad-slot .tv {
  margin-top: 4px;
}
